mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-20 12:17:19 -04:00
Merge branch 'ariane_next' into serpent
This commit is contained in:
commit
6539da7193
32 changed files with 1947 additions and 1047 deletions
|
@ -110,6 +110,15 @@ torture:
|
|||
dependencies:
|
||||
- build
|
||||
|
||||
serdiv-quest:
|
||||
stage: standard
|
||||
script:
|
||||
- cd tb/tb_serdiv/
|
||||
- make simc
|
||||
- "grep 'CI: PASSED' summary.rep"
|
||||
dependencies:
|
||||
- build
|
||||
|
||||
###################################
|
||||
# tests with serpent cache system
|
||||
|
||||
|
@ -155,10 +164,6 @@ s-icache-quest:
|
|||
stage: serpent
|
||||
script:
|
||||
- cd tb/tb_serpent_icache/
|
||||
- make simc
|
||||
- "grep 'CI: PASSED' summary.rep"
|
||||
dependencies:
|
||||
- build
|
||||
|
||||
s-dcache-quest:
|
||||
stage: serpent
|
||||
|
|
|
@ -77,6 +77,7 @@ sources:
|
|||
- src/lsu.sv
|
||||
- src/mmu.sv
|
||||
- src/mult.sv
|
||||
- src/serdiv.sv
|
||||
- src/perf_counters.sv
|
||||
- src/ptw.sv
|
||||
- src/ariane_regfile_ff.sv
|
||||
|
|
5
Makefile
5
Makefile
|
@ -95,6 +95,7 @@ src := $(filter-out src/ariane_regfile.sv, $(wildcard src/*.sv)) \
|
|||
src/common_cells/src/fifo_v1.sv \
|
||||
src/common_cells/src/lzc.sv \
|
||||
src/common_cells/src/rrarbiter.sv \
|
||||
src/common_cells/src/pipe_reg_simple.sv \
|
||||
src/common_cells/src/lfsr_8bit.sv \
|
||||
src/tech_cells_generic/src/cluster_clock_inverter.sv \
|
||||
src/tech_cells_generic/src/pulp_clock_mux2.sv \
|
||||
|
@ -122,7 +123,7 @@ incdir :=
|
|||
# Compile and sim flags
|
||||
compile_flag += +cover=bcfst+/dut -incr -64 -nologo -quiet -suppress 13262 -permissive +define+$(defines)
|
||||
uvm-flags += +UVM_NO_RELNOTES +UVM_VERBOSITY=LOW
|
||||
questa-flags += -t 1ns -64 -coverage -classdebug $(gui-sim)
|
||||
questa-flags += -t 1ns -64 -coverage -classdebug $(gui-sim) $(QUESTASIM_FLAGS)
|
||||
# if defined, calls the questa targets in batch mode
|
||||
ifdef batch-mode
|
||||
questa-flags += -c
|
||||
|
@ -203,7 +204,7 @@ run-asm-tests: $(riscv-asm-tests)
|
|||
$(MAKE) check-asm-tests
|
||||
|
||||
run-amo-tests: $(riscv-amo-tests)
|
||||
make check-amo-tests
|
||||
$(MAKE) check-amo-tests
|
||||
|
||||
check-asm-tests:
|
||||
ci/check-tests.sh tmp/riscv-asm-tests- $(shell wc -l $(riscv-asm-tests-list) | awk -F " " '{ print $1 }')
|
||||
|
|
|
@ -24,16 +24,33 @@ package ariane_pkg;
|
|||
localparam NR_SB_ENTRIES = 8; // number of scoreboard entries
|
||||
localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits
|
||||
// to uniquely identify the entry in the scoreboard
|
||||
localparam NR_WB_PORTS = 4;
|
||||
localparam ASID_WIDTH = 1;
|
||||
localparam BTB_ENTRIES = 8;
|
||||
localparam BHT_ENTRIES = 32;
|
||||
localparam BTB_ENTRIES = 64;
|
||||
localparam BHT_ENTRIES = 128;
|
||||
localparam RAS_DEPTH = 2;
|
||||
localparam BITS_SATURATION_COUNTER = 2;
|
||||
localparam NR_COMMIT_PORTS = 2;
|
||||
|
||||
localparam ENABLE_RENAME = 1'b1;
|
||||
|
||||
// amount of pipeline registers inserted for load/store return path
|
||||
// this can be tuned to trade-off IPC vs. cycle time
|
||||
localparam NR_LOAD_PIPE_REGS = 1;
|
||||
localparam NR_STORE_PIPE_REGS = 0;
|
||||
|
||||
// depth of store-buffers, this needs to be a power of two
|
||||
localparam int unsigned DEPTH_SPEC = 4;
|
||||
|
||||
`ifdef SERPENT_PULP
|
||||
// in this case we can use a small commit queue since we have a write buffer in the dcache
|
||||
// we could in principle do without the commit queue in this case, but the timing degrades if we do that due
|
||||
// to longer paths into the commit stage
|
||||
localparam int unsigned DEPTH_COMMIT = 2;
|
||||
`else
|
||||
// allocate more space for the commit buffer to be on the save side, this needs to be a power of two
|
||||
localparam int unsigned DEPTH_COMMIT = 8;
|
||||
`endif
|
||||
|
||||
// Floating-point extensions configuration
|
||||
localparam bit RVF = 1'b0; // Is F extension enabled
|
||||
localparam bit RVD = 1'b0; // Is D extension enabled
|
||||
|
@ -112,6 +129,8 @@ package ariane_pkg;
|
|||
// when more than one core is in a system
|
||||
localparam logic INVALIDATE_ON_FLUSH = 1'b1;
|
||||
|
||||
localparam NR_WB_PORTS = 4;
|
||||
|
||||
// ---------------
|
||||
// Fetch Stage
|
||||
// ---------------
|
||||
|
@ -262,10 +281,12 @@ package ariane_pkg;
|
|||
} fu_op;
|
||||
|
||||
typedef struct packed {
|
||||
fu_op operator;
|
||||
logic [63:0] operand_a;
|
||||
logic [63:0] operand_b;
|
||||
logic [63:0] imm;
|
||||
fu_t fu;
|
||||
fu_op operator;
|
||||
logic [63:0] operand_a;
|
||||
logic [63:0] operand_b;
|
||||
logic [63:0] imm;
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
} fu_data_t;
|
||||
|
||||
// -------------------------------
|
||||
|
|
|
@ -273,6 +273,8 @@ package riscv;
|
|||
localparam logic [11:0] PERF_CALL = 12'h9; // Procedure call
|
||||
localparam logic [11:0] PERF_RET = 12'hA; // Procedure Return
|
||||
localparam logic [11:0] PERF_MIS_PREDICT = 12'hB; // Branch mis-predicted
|
||||
localparam logic [11:0] PERF_SB_FULL = 12'hC; // Scoreboard full
|
||||
localparam logic [11:0] PERF_IF_EMPTY = 12'hD; // instruction fetch queue empty
|
||||
|
||||
// ----------------------
|
||||
// Virtual Memory
|
||||
|
|
131
src/alu.sv
131
src/alu.sv
|
@ -12,65 +12,35 @@
|
|||
// Author: Igor Loi <igor.loi@unibo.it>
|
||||
// Author: Andreas Traber <atraber@student.ethz.ch>
|
||||
// Author: Lukas Mueller <lukasmue@student.ethz.ch>
|
||||
// Author: Florian Zaruba <zaruabf@ethz.ch>
|
||||
// Author: Florian Zaruba <zaruabf@iis.ee.ethz.ch>
|
||||
//
|
||||
// Date: 19.03.2017
|
||||
// Description: Ariane ALU
|
||||
// Description: Ariane ALU based on RI5CY's ALU
|
||||
|
||||
import ariane_pkg::*;
|
||||
|
||||
module alu (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic flush_i,
|
||||
input logic [63:0] pc_i,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input logic alu_valid_i,
|
||||
input logic branch_valid_i,
|
||||
input logic csr_valid_i,
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] imm_i,
|
||||
input fu_data_t fu_data_i,
|
||||
output logic [63:0] result_o,
|
||||
output logic alu_valid_o,
|
||||
output logic alu_ready_o,
|
||||
output logic [TRANS_ID_BITS-1:0] alu_trans_id_o,
|
||||
output exception_t alu_exception_o,
|
||||
|
||||
input logic fu_valid_i,
|
||||
input logic is_compressed_instr_i,
|
||||
input branchpredict_sbe_t branch_predict_i,
|
||||
output branchpredict_t resolved_branch_o,
|
||||
output logic resolve_branch_o,
|
||||
|
||||
input logic commit_i,
|
||||
// to CSR file
|
||||
output logic [11:0] csr_addr_o // CSR address to commit stage
|
||||
output logic alu_branch_res_o
|
||||
);
|
||||
|
||||
logic csr_ready;
|
||||
|
||||
assign alu_ready_o = csr_ready;
|
||||
assign alu_valid_o = alu_valid_i | branch_valid_i | csr_valid_i;
|
||||
assign alu_trans_id_o = trans_id_i;
|
||||
|
||||
logic [63:0] operand_a_rev;
|
||||
logic [31:0] operand_a_rev32;
|
||||
logic [64:0] operand_b_neg;
|
||||
logic [65:0] adder_result_ext_o;
|
||||
logic less; // handles both signed and unsigned forms
|
||||
logic alu_branch_res;
|
||||
logic [63:0] branch_result, csr_result;
|
||||
|
||||
// bit reverse operand_a for left shifts and bit counting
|
||||
generate
|
||||
genvar k;
|
||||
for(k = 0; k < 64; k++)
|
||||
assign operand_a_rev[k] = operand_a_i[63-k];
|
||||
assign operand_a_rev[k] = fu_data_i.operand_a[63-k];
|
||||
|
||||
for (k = 0; k < 32; k++)
|
||||
assign operand_a_rev32[k] = operand_a_i[31-k];
|
||||
assign operand_a_rev32[k] = fu_data_i.operand_a[31-k];
|
||||
endgenerate
|
||||
|
||||
// ------
|
||||
|
@ -84,7 +54,7 @@ module alu (
|
|||
always_comb begin
|
||||
adder_op_b_negate = 1'b0;
|
||||
|
||||
unique case (operator_i)
|
||||
unique case (fu_data_i.operator)
|
||||
// ADDER OPS
|
||||
EQ, NE,
|
||||
SUB, SUBW: adder_op_b_negate = 1'b1;
|
||||
|
@ -94,10 +64,10 @@ module alu (
|
|||
end
|
||||
|
||||
// prepare operand a
|
||||
assign adder_in_a = {operand_a_i, 1'b1};
|
||||
assign adder_in_a = {fu_data_i.operand_a, 1'b1};
|
||||
|
||||
// prepare operand b
|
||||
assign operand_b_neg = {operand_b_i, 1'b0} ^ {65{adder_op_b_negate}};
|
||||
assign operand_b_neg = {fu_data_i.operand_b, 1'b0} ^ {65{adder_op_b_negate}};
|
||||
assign adder_in_b = operand_b_neg ;
|
||||
|
||||
// actual adder
|
||||
|
@ -108,13 +78,13 @@ module alu (
|
|||
// get the right branch comparison result
|
||||
always_comb begin : branch_resolve
|
||||
// set comparison by default
|
||||
alu_branch_res = 1'b1;
|
||||
case (operator_i)
|
||||
EQ: alu_branch_res = adder_z_flag;
|
||||
NE: alu_branch_res = ~adder_z_flag;
|
||||
LTS, LTU: alu_branch_res = less;
|
||||
GES, GEU: alu_branch_res = ~less;
|
||||
default: alu_branch_res = 1'b1;
|
||||
alu_branch_res_o = 1'b1;
|
||||
case (fu_data_i.operator)
|
||||
EQ: alu_branch_res_o = adder_z_flag;
|
||||
NE: alu_branch_res_o = ~adder_z_flag;
|
||||
LTS, LTU: alu_branch_res_o = less;
|
||||
GES, GEU: alu_branch_res_o = ~less;
|
||||
default: alu_branch_res_o = 1'b1;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -139,19 +109,19 @@ module alu (
|
|||
logic [63:0] shift_left_result;
|
||||
logic [31:0] shift_left_result32;
|
||||
|
||||
assign shift_amt = operand_b_i;
|
||||
assign shift_amt = fu_data_i.operand_b;
|
||||
|
||||
assign shift_left = (operator_i == SLL) | (operator_i == SLLW);
|
||||
assign shift_left = (fu_data_i.operator == SLL) | (fu_data_i.operator == SLLW);
|
||||
|
||||
assign shift_arithmetic = (operator_i == SRA) | (operator_i == SRAW);
|
||||
assign shift_arithmetic = (fu_data_i.operator == SRA) | (fu_data_i.operator == SRAW);
|
||||
|
||||
// right shifts, we let the synthesizer optimize this
|
||||
logic [64:0] shift_op_a_64;
|
||||
logic [32:0] shift_op_a_32;
|
||||
|
||||
// choose the bit reversed or the normal input for shift operand a
|
||||
assign shift_op_a = shift_left ? operand_a_rev : operand_a_i;
|
||||
assign shift_op_a32 = shift_left ? operand_a_rev32 : operand_a_i[31:0];
|
||||
assign shift_op_a = shift_left ? operand_a_rev : fu_data_i.operand_a;
|
||||
assign shift_op_a32 = shift_left ? operand_a_rev32 : fu_data_i.operand_a[31:0];
|
||||
|
||||
assign shift_op_a_64 = { shift_arithmetic & shift_op_a[63], shift_op_a};
|
||||
assign shift_op_a_32 = { shift_arithmetic & shift_op_a[31], shift_op_a32};
|
||||
|
@ -181,12 +151,12 @@ module alu (
|
|||
logic sgn;
|
||||
sgn = 1'b0;
|
||||
|
||||
if ((operator_i == SLTS) ||
|
||||
(operator_i == LTS) ||
|
||||
(operator_i == GES))
|
||||
if ((fu_data_i.operator == SLTS) ||
|
||||
(fu_data_i.operator == LTS) ||
|
||||
(fu_data_i.operator == GES))
|
||||
sgn = 1'b1;
|
||||
|
||||
less = ($signed({sgn & operand_a_i[63], operand_a_i}) < $signed({sgn & operand_b_i[63], operand_b_i}));
|
||||
less = ($signed({sgn & fu_data_i.operand_a[63], fu_data_i.operand_a}) < $signed({sgn & fu_data_i.operand_b[63], fu_data_i.operand_b}));
|
||||
end
|
||||
|
||||
// -----------
|
||||
|
@ -195,11 +165,11 @@ module alu (
|
|||
always_comb begin
|
||||
result_o = '0;
|
||||
|
||||
unique case (operator_i)
|
||||
unique case (fu_data_i.operator)
|
||||
// Standard Operations
|
||||
ANDL: result_o = operand_a_i & operand_b_i;
|
||||
ORL: result_o = operand_a_i | operand_b_i;
|
||||
XORL: result_o = operand_a_i ^ operand_b_i;
|
||||
ANDL: result_o = fu_data_i.operand_a & fu_data_i.operand_b;
|
||||
ORL: result_o = fu_data_i.operand_a | fu_data_i.operand_b;
|
||||
XORL: result_o = fu_data_i.operand_a ^ fu_data_i.operand_b;
|
||||
|
||||
// Adder Operations
|
||||
ADD, SUB: result_o = adder_result;
|
||||
|
@ -217,48 +187,5 @@ module alu (
|
|||
|
||||
default: ; // default case to suppress unique warning
|
||||
endcase
|
||||
|
||||
if (branch_valid_i) begin
|
||||
result_o = branch_result;
|
||||
end else if (csr_valid_i) begin
|
||||
result_o = csr_result;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// ----------------------
|
||||
// Branch Unit
|
||||
// ----------------------
|
||||
branch_unit branch_unit_i (
|
||||
.operator_i,
|
||||
.operand_a_i,
|
||||
.operand_b_i,
|
||||
.imm_i,
|
||||
.pc_i,
|
||||
.is_compressed_instr_i,
|
||||
// any functional unit is valid, check that there is no accidental mis-predict
|
||||
.fu_valid_i,
|
||||
.branch_valid_i,
|
||||
.branch_comp_res_i ( alu_branch_res ),
|
||||
.branch_result_o ( branch_result ),
|
||||
.branch_predict_i,
|
||||
.resolved_branch_o,
|
||||
.resolve_branch_o,
|
||||
.branch_exception_o ( alu_exception_o )
|
||||
);
|
||||
|
||||
csr_buffer csr_buffer_i (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i,
|
||||
.csr_valid_i,
|
||||
.operator_i,
|
||||
.operand_a_i,
|
||||
.operand_b_i,
|
||||
.csr_ready_o ( csr_ready ),
|
||||
.csr_result_o ( csr_result ),
|
||||
.commit_i,
|
||||
.csr_addr_o
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
205
src/ariane.sv
205
src/ariane.sv
|
@ -85,39 +85,37 @@ module ariane #(
|
|||
// --------------
|
||||
// ISSUE <-> EX
|
||||
// --------------
|
||||
logic [63:0] imm_id_ex;
|
||||
logic [TRANS_ID_BITS-1:0] trans_id_id_ex;
|
||||
fu_t fu_id_ex;
|
||||
fu_op operator_id_ex;
|
||||
logic [63:0] operand_a_id_ex;
|
||||
logic [63:0] operand_b_id_ex;
|
||||
fu_data_t fu_data_id_ex;
|
||||
logic [63:0] pc_id_ex;
|
||||
logic is_compressed_instr_id_ex;
|
||||
// fixed latency units
|
||||
logic flu_ready_ex_id;
|
||||
logic [TRANS_ID_BITS-1:0] flu_trans_id_ex_id;
|
||||
logic flu_valid_ex_id;
|
||||
logic [63:0] flu_result_ex_id;
|
||||
exception_t flu_exception_ex_id;
|
||||
// ALU
|
||||
logic alu_ready_ex_id;
|
||||
logic alu_valid_id_ex;
|
||||
logic [TRANS_ID_BITS-1:0] alu_trans_id_ex_id;
|
||||
logic alu_valid_ex_id;
|
||||
logic [63:0] alu_result_ex_id;
|
||||
exception_t alu_exception_ex_id;
|
||||
// Branches and Jumps
|
||||
logic branch_valid_id_ex;
|
||||
|
||||
branchpredict_sbe_t branch_predict_id_ex;
|
||||
logic resolve_branch_ex_id;
|
||||
// LSU
|
||||
logic [TRANS_ID_BITS-1:0] lsu_trans_id_ex_id;
|
||||
logic lsu_valid_id_ex;
|
||||
logic [63:0] lsu_result_ex_id;
|
||||
logic lsu_ready_ex_id;
|
||||
logic lsu_valid_ex_id;
|
||||
exception_t lsu_exception_ex_id;
|
||||
|
||||
logic [TRANS_ID_BITS-1:0] load_trans_id_ex_id;
|
||||
logic [63:0] load_result_ex_id;
|
||||
logic load_valid_ex_id;
|
||||
exception_t load_exception_ex_id;
|
||||
|
||||
logic [63:0] store_result_ex_id;
|
||||
logic [TRANS_ID_BITS-1:0] store_trans_id_ex_id;
|
||||
logic store_valid_ex_id;
|
||||
exception_t store_exception_ex_id;
|
||||
// MULT
|
||||
logic mult_ready_ex_id;
|
||||
logic mult_valid_id_ex;
|
||||
logic [TRANS_ID_BITS-1:0] mult_trans_id_ex_id;
|
||||
logic [63:0] mult_result_ex_id;
|
||||
logic mult_valid_ex_id;
|
||||
// FPU
|
||||
logic fpu_ready_ex_id;
|
||||
logic fpu_valid_id_ex;
|
||||
|
@ -218,6 +216,7 @@ module ariane #(
|
|||
|
||||
amo_req_t amo_req;
|
||||
amo_resp_t amo_resp;
|
||||
logic sb_full;
|
||||
|
||||
logic debug_req;
|
||||
// Disable debug during AMO commit
|
||||
|
@ -287,25 +286,23 @@ module ariane #(
|
|||
.NR_ENTRIES ( NR_SB_ENTRIES ),
|
||||
.NR_WB_PORTS ( NR_WB_PORTS )
|
||||
) issue_stage_i (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.sb_full_o ( sb_full ),
|
||||
.flush_unissued_instr_i ( flush_unissued_instr_ctrl_id ),
|
||||
.flush_i ( flush_ctrl_id ),
|
||||
|
||||
// ID Stage
|
||||
.decoded_instr_i ( issue_entry_id_issue ),
|
||||
.decoded_instr_valid_i ( issue_entry_valid_id_issue ),
|
||||
.is_ctrl_flow_i ( is_ctrl_fow_id_issue ),
|
||||
.decoded_instr_ack_o ( issue_instr_issue_id ),
|
||||
|
||||
// Functional Units
|
||||
.fu_o ( fu_id_ex ),
|
||||
.operator_o ( operator_id_ex ),
|
||||
.operand_a_o ( operand_a_id_ex ),
|
||||
.operand_b_o ( operand_b_id_ex ),
|
||||
.imm_o ( imm_id_ex ),
|
||||
.trans_id_o ( trans_id_id_ex ),
|
||||
.fu_data_o ( fu_data_id_ex ),
|
||||
.pc_o ( pc_id_ex ),
|
||||
.is_compressed_instr_o ( is_compressed_instr_id_ex ),
|
||||
// fixed latency unit ready
|
||||
.flu_ready_i ( flu_ready_ex_id ),
|
||||
// ALU
|
||||
.alu_ready_i ( alu_ready_ex_id ),
|
||||
.alu_valid_o ( alu_valid_id_ex ),
|
||||
// Branches and Jumps
|
||||
.branch_valid_o ( branch_valid_id_ex ), // branch is valid
|
||||
|
@ -315,7 +312,6 @@ module ariane #(
|
|||
.lsu_ready_i ( lsu_ready_ex_id ),
|
||||
.lsu_valid_o ( lsu_valid_id_ex ),
|
||||
// Multiplier
|
||||
.mult_ready_i ( mult_ready_ex_id ),
|
||||
.mult_valid_o ( mult_valid_id_ex ),
|
||||
// FPU
|
||||
.fpu_ready_i ( fpu_ready_ex_id ),
|
||||
|
@ -324,13 +320,12 @@ module ariane #(
|
|||
.fpu_rm_o ( fpu_rm_id_ex ),
|
||||
// CSR
|
||||
.csr_valid_o ( csr_valid_id_ex ),
|
||||
|
||||
// Commit
|
||||
.resolved_branch_i ( resolved_branch ),
|
||||
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id, mult_trans_id_ex_id, fpu_trans_id_ex_id }),
|
||||
.wbdata_i ( {alu_result_ex_id, lsu_result_ex_id, mult_result_ex_id, fpu_result_ex_id }),
|
||||
.ex_ex_i ( {alu_exception_ex_id, lsu_exception_ex_id, {$bits(exception_t){1'b0}}, fpu_exception_ex_id }),
|
||||
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, mult_valid_ex_id, fpu_valid_ex_id }),
|
||||
.trans_id_i ( {flu_trans_id_ex_id, load_trans_id_ex_id, store_trans_id_ex_id, fpu_trans_id_ex_id }),
|
||||
.wbdata_i ( {flu_result_ex_id, load_result_ex_id, store_result_ex_id, fpu_result_ex_id }),
|
||||
.ex_ex_i ( {flu_exception_ex_id, load_exception_ex_id, store_exception_ex_id, fpu_exception_ex_id }),
|
||||
.wb_valid_i ( {flu_valid_ex_id, load_valid_ex_id, store_valid_ex_id, fpu_valid_ex_id }),
|
||||
|
||||
.waddr_i ( waddr_commit_id ),
|
||||
.wdata_i ( wdata_commit_id ),
|
||||
|
@ -345,81 +340,80 @@ module ariane #(
|
|||
// EX
|
||||
// ---------
|
||||
ex_stage ex_stage_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_ctrl_ex ),
|
||||
.fu_i ( fu_id_ex ),
|
||||
.operator_i ( operator_id_ex ),
|
||||
.operand_a_i ( operand_a_id_ex ),
|
||||
.operand_b_i ( operand_b_id_ex ),
|
||||
.imm_i ( imm_id_ex ),
|
||||
.trans_id_i ( trans_id_id_ex ),
|
||||
.pc_i ( pc_id_ex ),
|
||||
.is_compressed_instr_i ( is_compressed_instr_id_ex ),
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_ctrl_ex ),
|
||||
.fu_data_i ( fu_data_id_ex ),
|
||||
.pc_i ( pc_id_ex ),
|
||||
.is_compressed_instr_i ( is_compressed_instr_id_ex ),
|
||||
// fixed latency units
|
||||
.flu_result_o ( flu_result_ex_id ),
|
||||
.flu_trans_id_o ( flu_trans_id_ex_id ),
|
||||
.flu_valid_o ( flu_valid_ex_id ),
|
||||
.flu_exception_o ( flu_exception_ex_id ),
|
||||
.flu_ready_o ( flu_ready_ex_id ),
|
||||
// ALU
|
||||
.alu_ready_o ( alu_ready_ex_id ),
|
||||
.alu_valid_i ( alu_valid_id_ex ),
|
||||
.alu_result_o ( alu_result_ex_id ),
|
||||
.alu_trans_id_o ( alu_trans_id_ex_id ),
|
||||
.alu_valid_o ( alu_valid_ex_id ),
|
||||
.alu_exception_o ( alu_exception_ex_id ),
|
||||
.alu_valid_i ( alu_valid_id_ex ),
|
||||
// Branches and Jumps
|
||||
.branch_valid_i ( branch_valid_id_ex ),
|
||||
.branch_predict_i ( branch_predict_id_ex ), // branch predict to ex
|
||||
.resolved_branch_o ( resolved_branch ),
|
||||
.resolve_branch_o ( resolve_branch_ex_id ),
|
||||
.branch_valid_i ( branch_valid_id_ex ),
|
||||
.branch_predict_i ( branch_predict_id_ex ), // branch predict to ex
|
||||
.resolved_branch_o ( resolved_branch ),
|
||||
.resolve_branch_o ( resolve_branch_ex_id ),
|
||||
// CSR
|
||||
.csr_valid_i ( csr_valid_id_ex ),
|
||||
.csr_addr_o ( csr_addr_ex_csr ),
|
||||
.csr_commit_i ( csr_commit_commit_ex ), // from commit
|
||||
// LSU
|
||||
.lsu_ready_o ( lsu_ready_ex_id ),
|
||||
.lsu_valid_i ( lsu_valid_id_ex ),
|
||||
.lsu_result_o ( lsu_result_ex_id ),
|
||||
.lsu_trans_id_o ( lsu_trans_id_ex_id ),
|
||||
.lsu_valid_o ( lsu_valid_ex_id ),
|
||||
.lsu_commit_i ( lsu_commit_commit_ex ), // from commit
|
||||
.lsu_commit_ready_o ( lsu_commit_ready_ex_commit ), // to commit
|
||||
.lsu_exception_o ( lsu_exception_ex_id ),
|
||||
.no_st_pending_o ( no_st_pending_ex ),
|
||||
.csr_valid_i ( csr_valid_id_ex ),
|
||||
.csr_addr_o ( csr_addr_ex_csr ),
|
||||
.csr_commit_i ( csr_commit_commit_ex ), // from commit
|
||||
// MULT
|
||||
.mult_ready_o ( mult_ready_ex_id ),
|
||||
.mult_valid_i ( mult_valid_id_ex ),
|
||||
.mult_trans_id_o ( mult_trans_id_ex_id ),
|
||||
.mult_result_o ( mult_result_ex_id ),
|
||||
.mult_valid_o ( mult_valid_ex_id ),
|
||||
.mult_valid_i ( mult_valid_id_ex ),
|
||||
// LSU
|
||||
.lsu_ready_o ( lsu_ready_ex_id ),
|
||||
.lsu_valid_i ( lsu_valid_id_ex ),
|
||||
|
||||
.load_result_o ( load_result_ex_id ),
|
||||
.load_trans_id_o ( load_trans_id_ex_id ),
|
||||
.load_valid_o ( load_valid_ex_id ),
|
||||
.load_exception_o ( load_exception_ex_id ),
|
||||
|
||||
.store_result_o ( store_result_ex_id ),
|
||||
.store_trans_id_o ( store_trans_id_ex_id ),
|
||||
.store_valid_o ( store_valid_ex_id ),
|
||||
.store_exception_o ( store_exception_ex_id ),
|
||||
|
||||
.lsu_commit_i ( lsu_commit_commit_ex ), // from commit
|
||||
.lsu_commit_ready_o ( lsu_commit_ready_ex_commit ), // to commit
|
||||
.no_st_pending_o ( no_st_pending_ex ),
|
||||
// FPU
|
||||
.fpu_ready_o ( fpu_ready_ex_id ),
|
||||
.fpu_valid_i ( fpu_valid_id_ex ),
|
||||
.fpu_fmt_i ( fpu_fmt_id_ex ),
|
||||
.fpu_rm_i ( fpu_rm_id_ex ),
|
||||
.fpu_frm_i ( frm_csr_id_issue_ex ),
|
||||
.fpu_prec_i ( fprec_csr_ex ),
|
||||
.fpu_trans_id_o ( fpu_trans_id_ex_id ),
|
||||
.fpu_result_o ( fpu_result_ex_id ),
|
||||
.fpu_valid_o ( fpu_valid_ex_id ),
|
||||
.fpu_exception_o ( fpu_exception_ex_id ),
|
||||
.amo_valid_commit_i ( amo_valid_commit ),
|
||||
.amo_req_o ( amo_req ),
|
||||
.amo_resp_i ( amo_resp ),
|
||||
.fpu_ready_o ( fpu_ready_ex_id ),
|
||||
.fpu_valid_i ( fpu_valid_id_ex ),
|
||||
.fpu_fmt_i ( fpu_fmt_id_ex ),
|
||||
.fpu_rm_i ( fpu_rm_id_ex ),
|
||||
.fpu_frm_i ( frm_csr_id_issue_ex ),
|
||||
.fpu_prec_i ( fprec_csr_ex ),
|
||||
.fpu_trans_id_o ( fpu_trans_id_ex_id ),
|
||||
.fpu_result_o ( fpu_result_ex_id ),
|
||||
.fpu_valid_o ( fpu_valid_ex_id ),
|
||||
.fpu_exception_o ( fpu_exception_ex_id ),
|
||||
.amo_valid_commit_i ( amo_valid_commit ),
|
||||
.amo_req_o ( amo_req ),
|
||||
.amo_resp_i ( amo_resp ),
|
||||
// Performance counters
|
||||
.itlb_miss_o ( itlb_miss_ex_perf ),
|
||||
.dtlb_miss_o ( dtlb_miss_ex_perf ),
|
||||
.itlb_miss_o ( itlb_miss_ex_perf ),
|
||||
.dtlb_miss_o ( dtlb_miss_ex_perf ),
|
||||
// Memory Management
|
||||
.enable_translation_i ( enable_translation_csr_ex ), // from CSR
|
||||
.en_ld_st_translation_i ( en_ld_st_translation_csr_ex ),
|
||||
.flush_tlb_i ( flush_tlb_ctrl_ex ),
|
||||
.priv_lvl_i ( priv_lvl ), // from CSR
|
||||
.ld_st_priv_lvl_i ( ld_st_priv_lvl_csr_ex ), // from CSR
|
||||
.sum_i ( sum_csr_ex ), // from CSR
|
||||
.mxr_i ( mxr_csr_ex ), // from CSR
|
||||
.satp_ppn_i ( satp_ppn_csr_ex ), // from CSR
|
||||
.asid_i ( asid_csr_ex ), // from CSR
|
||||
.icache_areq_i ( icache_areq_cache_ex ),
|
||||
.icache_areq_o ( icache_areq_ex_cache ),
|
||||
.enable_translation_i ( enable_translation_csr_ex ), // from CSR
|
||||
.en_ld_st_translation_i ( en_ld_st_translation_csr_ex ),
|
||||
.flush_tlb_i ( flush_tlb_ctrl_ex ),
|
||||
.priv_lvl_i ( priv_lvl ), // from CSR
|
||||
.ld_st_priv_lvl_i ( ld_st_priv_lvl_csr_ex ), // from CSR
|
||||
.sum_i ( sum_csr_ex ), // from CSR
|
||||
.mxr_i ( mxr_csr_ex ), // from CSR
|
||||
.satp_ppn_i ( satp_ppn_csr_ex ), // from CSR
|
||||
.asid_i ( asid_csr_ex ), // from CSR
|
||||
.icache_areq_i ( icache_areq_cache_ex ),
|
||||
.icache_areq_o ( icache_areq_ex_cache ),
|
||||
// DCACHE interfaces
|
||||
.dcache_req_ports_i ( dcache_req_ports_cache_ex ),
|
||||
.dcache_req_ports_o ( dcache_req_ports_ex_cache )
|
||||
.dcache_req_ports_i ( dcache_req_ports_cache_ex ),
|
||||
.dcache_req_ports_o ( dcache_req_ports_ex_cache )
|
||||
);
|
||||
|
||||
// ---------
|
||||
|
@ -522,6 +516,9 @@ module ariane #(
|
|||
// Performance Counters
|
||||
// ------------------------
|
||||
perf_counters i_perf_counters (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.debug_mode_i ( debug_mode ),
|
||||
.addr_i ( addr_csr_perf ),
|
||||
.we_i ( we_csr_perf ),
|
||||
.data_i ( data_csr_perf ),
|
||||
|
@ -533,11 +530,11 @@ module ariane #(
|
|||
.l1_dcache_miss_i ( dcache_miss_cache_perf ),
|
||||
.itlb_miss_i ( itlb_miss_ex_perf ),
|
||||
.dtlb_miss_i ( dtlb_miss_ex_perf ),
|
||||
|
||||
.sb_full_i ( sb_full ),
|
||||
.if_empty_i ( ~fetch_valid_if_id ),
|
||||
.ex_i ( ex_commit ),
|
||||
.eret_i ( eret ),
|
||||
.resolved_branch_i ( resolved_branch ),
|
||||
.*
|
||||
.resolved_branch_i ( resolved_branch )
|
||||
);
|
||||
|
||||
// ------------
|
||||
|
|
|
@ -15,10 +15,7 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module branch_unit (
|
||||
input fu_op operator_i, // comparison operation to perform
|
||||
input logic [63:0] operand_a_i, // contains content of RS 1
|
||||
input logic [63:0] operand_b_i, // contains content of RS 2
|
||||
input logic [63:0] imm_i, // immediate to add to PC
|
||||
input fu_data_t fu_data_i,
|
||||
input logic [63:0] pc_i, // PC of instruction
|
||||
input logic is_compressed_instr_i,
|
||||
input logic fu_valid_i, // any functional unit is valid, check that there is no accidental mis-predict
|
||||
|
@ -39,7 +36,7 @@ module branch_unit (
|
|||
always_comb begin : mispredict_handler
|
||||
// set the jump base, for JALR we need to look at the register, for all other control flow instructions we can take the current PC
|
||||
automatic logic [63:0] jump_base;
|
||||
jump_base = (operator_i == JALR) ? operand_a_i : pc_i;
|
||||
jump_base = (fu_data_i.operator == JALR) ? fu_data_i.operand_a : pc_i;
|
||||
|
||||
target_address = 64'b0;
|
||||
resolve_branch_o = 1'b0;
|
||||
|
@ -53,9 +50,9 @@ module branch_unit (
|
|||
// calculate next PC, depending on whether the instruction is compressed or not this may be different
|
||||
next_pc = pc_i + ((is_compressed_instr_i) ? 64'h2 : 64'h4);
|
||||
// calculate target address simple 64 bit addition
|
||||
target_address = $unsigned($signed(jump_base) + $signed(imm_i));
|
||||
target_address = $unsigned($signed(jump_base) + $signed(fu_data_i.imm));
|
||||
// on a JALR we are supposed to reset the LSB to 0 (according to the specification)
|
||||
if (operator_i == JALR)
|
||||
if (fu_data_i.operator == JALR)
|
||||
target_address[0] = 1'b0;
|
||||
// if we need to put the branch target address in a destination register, output it here to WB
|
||||
branch_result_o = next_pc;
|
||||
|
|
|
@ -192,6 +192,7 @@ module serpent_cache_subsystem #(
|
|||
.rdata_o ( adapter_icache.data ),
|
||||
.id_o ( ),
|
||||
.critical_word_o ( ),
|
||||
.critical_word_valid_o( ),
|
||||
.axi_req_o ( axi_data_o ),
|
||||
.axi_resp_i ( axi_data_i )
|
||||
);
|
||||
|
@ -243,7 +244,8 @@ module serpent_cache_subsystem #(
|
|||
.id_o ( axi_dcache_id ),
|
||||
.critical_word_o ( ),
|
||||
.critical_word_valid_o( ),
|
||||
.axi ( dcache_data_if )
|
||||
.axi_req_o ( ),
|
||||
.axi_resp_i ( '0 )
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3b18d9ce9889fb140cd39c8d7c86b3a6cc68872e
|
||||
Subproject commit 1bea86b04d0c341c555e2ff83a8e247c7d1a3260
|
|
@ -20,15 +20,12 @@ module csr_buffer (
|
|||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic flush_i,
|
||||
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input fu_data_t fu_data_i,
|
||||
|
||||
output logic csr_ready_o, // FU is ready e.g. not busy
|
||||
input logic csr_valid_i, // Input is valid
|
||||
output logic [63:0] csr_result_o,
|
||||
input logic commit_i, // commit the pending CSR OP
|
||||
|
||||
input logic csr_commit_i, // commit the pending CSR OP
|
||||
// to CSR file
|
||||
output logic [11:0] csr_addr_o // CSR address to commit stage
|
||||
);
|
||||
|
@ -40,7 +37,7 @@ module csr_buffer (
|
|||
} csr_reg_n, csr_reg_q;
|
||||
|
||||
// control logic, scoreboard signals
|
||||
assign csr_result_o = operand_a_i;
|
||||
assign csr_result_o = fu_data_i.operand_a;
|
||||
assign csr_addr_o = csr_reg_q.csr_address;
|
||||
|
||||
// write logic
|
||||
|
@ -49,16 +46,16 @@ module csr_buffer (
|
|||
// by default we are ready
|
||||
csr_ready_o = 1'b1;
|
||||
// if we have a valid uncomiited csr req or are just getting one WITHOUT a commit in, we are not ready
|
||||
if ((csr_reg_q.valid || csr_valid_i) && ~commit_i)
|
||||
if ((csr_reg_q.valid || csr_valid_i) && ~csr_commit_i)
|
||||
csr_ready_o = 1'b0;
|
||||
// if we got a valid from the scoreboard
|
||||
// store the CSR address
|
||||
if (csr_valid_i) begin
|
||||
csr_reg_n.csr_address = operand_b_i[11:0];
|
||||
csr_reg_n.csr_address = fu_data_i.operand_b[11:0];
|
||||
csr_reg_n.valid = 1'b1;
|
||||
end
|
||||
// if we get a commit and no new valid instruction -> clear the valid bit
|
||||
if (commit_i && ~csr_valid_i) begin
|
||||
if (csr_commit_i && ~csr_valid_i) begin
|
||||
csr_reg_n.valid = 1'b0;
|
||||
end
|
||||
// clear the buffer if we flushed
|
||||
|
|
276
src/ex_stage.sv
276
src/ex_stage.sv
|
@ -15,30 +15,25 @@
|
|||
|
||||
import ariane_pkg::*;
|
||||
|
||||
module ex_stage #(
|
||||
parameter int ASID_WIDTH = 1
|
||||
)(
|
||||
module ex_stage (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic flush_i,
|
||||
|
||||
input fu_t fu_i,
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] imm_i,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input fu_data_t fu_data_i,
|
||||
input logic [63:0] pc_i, // PC of current instruction
|
||||
input logic is_compressed_instr_i, // we need to know if this was a compressed instruction
|
||||
// in order to calculate the next PC on a mis-predict
|
||||
// ALU 1
|
||||
output logic alu_ready_o, // FU is ready
|
||||
input logic alu_valid_i, // Output is valid
|
||||
output logic alu_valid_o, // ALU result is valid
|
||||
output logic [63:0] alu_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] alu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output exception_t alu_exception_o,
|
||||
// Fixed latency unit(s)
|
||||
output logic [63:0] flu_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] flu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output exception_t flu_exception_o,
|
||||
output logic flu_ready_o, // FLU is ready
|
||||
output logic flu_valid_o, // FLU result is valid
|
||||
// Branches and Jumps
|
||||
// ALU 1
|
||||
input logic alu_valid_i, // Output is valid
|
||||
// Branch Unit
|
||||
input logic branch_valid_i, // we are using the branch unit
|
||||
input branchpredict_sbe_t branch_predict_i,
|
||||
output branchpredict_t resolved_branch_o, // the branch engine uses the write back from the ALU
|
||||
|
@ -47,23 +42,25 @@ module ex_stage #(
|
|||
input logic csr_valid_i,
|
||||
output logic [11:0] csr_addr_o,
|
||||
input logic csr_commit_i,
|
||||
// MULT
|
||||
input logic mult_valid_i, // Output is valid
|
||||
// LSU
|
||||
output logic lsu_ready_o, // FU is ready
|
||||
input logic lsu_valid_i, // Input is valid
|
||||
output logic lsu_valid_o, // Output is valid
|
||||
output logic [63:0] lsu_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] lsu_trans_id_o,
|
||||
output logic lsu_ready_o, // FU is ready
|
||||
input logic lsu_valid_i, // Input is valid
|
||||
|
||||
output logic load_valid_o,
|
||||
output logic [63:0] load_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] load_trans_id_o,
|
||||
output exception_t load_exception_o,
|
||||
output logic store_valid_o,
|
||||
output logic [63:0] store_result_o,
|
||||
output logic [TRANS_ID_BITS-1:0] store_trans_id_o,
|
||||
output exception_t store_exception_o,
|
||||
|
||||
input logic lsu_commit_i,
|
||||
output logic lsu_commit_ready_o, // commit queue is ready to accept another commit request
|
||||
output exception_t lsu_exception_o,
|
||||
output logic lsu_commit_ready_o, // commit queue is ready to accept another commit request
|
||||
output logic no_st_pending_o,
|
||||
input logic amo_valid_commit_i,
|
||||
// MULT
|
||||
output logic mult_ready_o, // FU is ready
|
||||
input logic mult_valid_i, // Output is valid
|
||||
output logic [TRANS_ID_BITS-1:0] mult_trans_id_o,
|
||||
output logic [63:0] mult_result_o,
|
||||
output logic mult_valid_o,
|
||||
// FPU
|
||||
output logic fpu_ready_o, // FU is ready
|
||||
input logic fpu_valid_i, // Output is valid
|
||||
|
@ -75,7 +72,6 @@ module ex_stage #(
|
|||
output logic [63:0] fpu_result_o,
|
||||
output logic fpu_valid_o,
|
||||
output exception_t fpu_exception_o,
|
||||
|
||||
// Memory Management
|
||||
input logic enable_translation_i,
|
||||
input logic en_ld_st_translation_i,
|
||||
|
@ -101,69 +97,116 @@ module ex_stage #(
|
|||
output logic dtlb_miss_o
|
||||
);
|
||||
|
||||
// -------------------------
|
||||
// Fixed Latency Units
|
||||
// -------------------------
|
||||
// all fixed latency units share a single issue port and a sing write
|
||||
// port into the scoreboard. At the moment those are:
|
||||
// 1. ALU - all operations are single cycle
|
||||
// 2. Branch unit: operation is single cycle, the ALU is needed
|
||||
// for comparison
|
||||
// 3. CSR: This is a small buffer which saves the address of the CSR.
|
||||
// The value is then re-fetched once the instruction retires. The buffer
|
||||
// is only a single entry deep, hence this operation will block all
|
||||
// other operations once this buffer is full. This should not be a major
|
||||
// concern though as CSRs are infrequent.
|
||||
// 4. Multiplier/Divider: The multiplier has a fixed latency of 1 cycle.
|
||||
// The issue logic will take care of not issuing
|
||||
// another instruction if it will collide on the
|
||||
// output port. Divisions are arbitrary in length
|
||||
// they will simply block the issue of all other
|
||||
// instructions.
|
||||
|
||||
// from ALU to branch unit
|
||||
logic alu_branch_res; // branch comparison result
|
||||
logic [63:0] alu_result, branch_result, csr_result, mult_result;
|
||||
logic csr_ready, mult_ready;
|
||||
logic [TRANS_ID_BITS-1:0] mult_trans_id;
|
||||
logic mult_valid;
|
||||
|
||||
// -----
|
||||
// ALU
|
||||
// -----
|
||||
// 1. ALU (combinatorial)
|
||||
// data silence operation
|
||||
fu_data_t alu_data;
|
||||
assign alu_data.operator = (alu_valid_i | branch_valid_i | csr_valid_i) ? operator_i : ADD;
|
||||
assign alu_data.operand_a = (alu_valid_i | branch_valid_i | csr_valid_i) ? operand_a_i : '0;
|
||||
assign alu_data.operand_b = (alu_valid_i | branch_valid_i | csr_valid_i) ? operand_b_i : '0;
|
||||
assign alu_data.imm = (alu_valid_i | branch_valid_i | csr_valid_i) ? imm_i : '0;
|
||||
assign alu_data = (alu_valid_i | branch_valid_i) ? fu_data_i : '0;
|
||||
|
||||
// fixed latency FUs
|
||||
// TOOD(zarubaf) Re-name this module and re-factor ALU
|
||||
alu alu_i (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i,
|
||||
.pc_i,
|
||||
.trans_id_i,
|
||||
.alu_valid_i,
|
||||
.branch_valid_i,
|
||||
.csr_valid_i ( csr_valid_i ),
|
||||
.operator_i ( alu_data.operator ),
|
||||
.operand_a_i ( alu_data.operand_a ),
|
||||
.operand_b_i ( alu_data.operand_b ),
|
||||
.imm_i ( alu_data.imm ),
|
||||
.result_o ( alu_result_o ),
|
||||
.alu_valid_o,
|
||||
.alu_ready_o,
|
||||
.alu_trans_id_o,
|
||||
.alu_exception_o,
|
||||
.fu_data_i ( alu_data ),
|
||||
.result_o ( alu_result ),
|
||||
.alu_branch_res_o ( alu_branch_res )
|
||||
);
|
||||
|
||||
.fu_valid_i ( alu_valid_i || lsu_valid_i || csr_valid_i || mult_valid_i || fpu_valid_i ),
|
||||
// 2. Branch Unit (combinatorial)
|
||||
// we don't silence the branch unit as this is already critical and we do
|
||||
// not want to add another layer of logic
|
||||
branch_unit branch_unit_i (
|
||||
.fu_data_i,
|
||||
.pc_i,
|
||||
.is_compressed_instr_i,
|
||||
// any functional unit is valid, check that there is no accidental mis-predict
|
||||
.fu_valid_i ( alu_valid_i || lsu_valid_i || csr_valid_i || mult_valid_i || fpu_valid_i ) ,
|
||||
.branch_valid_i,
|
||||
.branch_comp_res_i ( alu_branch_res ),
|
||||
.branch_result_o ( branch_result ),
|
||||
.branch_predict_i,
|
||||
.resolved_branch_o,
|
||||
.resolve_branch_o,
|
||||
|
||||
.commit_i ( csr_commit_i ),
|
||||
.csr_addr_o ( csr_addr_o )
|
||||
.branch_exception_o ( flu_exception_o )
|
||||
);
|
||||
|
||||
// ----------------
|
||||
// Multiplication
|
||||
// ----------------
|
||||
// 3. CSR (sequential)
|
||||
csr_buffer csr_buffer_i (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i,
|
||||
.fu_data_i,
|
||||
.csr_valid_i,
|
||||
.csr_ready_o ( csr_ready ),
|
||||
.csr_result_o ( csr_result ),
|
||||
.csr_commit_i,
|
||||
.csr_addr_o
|
||||
);
|
||||
|
||||
assign flu_valid_o = alu_valid_i | branch_valid_i | csr_valid_i | mult_valid;
|
||||
|
||||
// result MUX
|
||||
always_comb begin
|
||||
// Branch result as default case
|
||||
flu_result_o = branch_result;
|
||||
flu_trans_id_o = fu_data_i.trans_id;
|
||||
// ALU result
|
||||
if (alu_valid_i) begin
|
||||
flu_result_o = alu_result;
|
||||
// CSR result
|
||||
end else if (csr_valid_i) begin
|
||||
flu_result_o = csr_result;
|
||||
end else if (mult_valid) begin
|
||||
flu_result_o = mult_result;
|
||||
flu_trans_id_o = mult_trans_id;
|
||||
end
|
||||
end
|
||||
|
||||
// ready flags for FLU
|
||||
always_comb begin
|
||||
flu_ready_o = csr_ready & mult_ready;
|
||||
end
|
||||
|
||||
// 4. Multiplication (Sequential)
|
||||
fu_data_t mult_data;
|
||||
assign mult_data.operator = mult_valid_i ? operator_i : MUL;
|
||||
assign mult_data.operand_a = mult_valid_i ? operand_a_i : '0;
|
||||
assign mult_data.operand_b = mult_valid_i ? operand_b_i : '0;
|
||||
// input silencing of multiplier
|
||||
assign mult_data = mult_valid_i ? fu_data_i : '0;
|
||||
|
||||
mult i_mult (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i,
|
||||
.trans_id_i,
|
||||
.mult_valid_i,
|
||||
.operator_i ( mult_data.operator ),
|
||||
.operand_a_i ( mult_data.operand_a ),
|
||||
.operand_b_i ( mult_data.operand_b ),
|
||||
.result_o ( mult_result_o ),
|
||||
.mult_valid_o,
|
||||
.mult_ready_o,
|
||||
.mult_trans_id_o
|
||||
.fu_data_i ( mult_data ),
|
||||
.result_o ( mult_result ),
|
||||
.mult_valid_o ( mult_valid ),
|
||||
.mult_ready_o ( mult_ready ),
|
||||
.mult_trans_id_o ( mult_trans_id )
|
||||
);
|
||||
|
||||
// ----------------
|
||||
|
@ -172,29 +215,21 @@ module ex_stage #(
|
|||
generate
|
||||
if (FP_PRESENT) begin : fpu_gen
|
||||
fu_data_t fpu_data;
|
||||
assign fpu_data.operator = fpu_valid_i ? operator_i : FSGNJ;
|
||||
assign fpu_data.operand_a = fpu_valid_i ? operand_a_i : '0;
|
||||
assign fpu_data.operand_b = fpu_valid_i ? operand_b_i : '0;
|
||||
assign fpu_data.imm = fpu_valid_i ? imm_i : '0;
|
||||
assign fpu_data.operator = fpu_valid_i ? fu_data_i : '0;
|
||||
|
||||
fpu_wrap fpu_i (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i,
|
||||
.trans_id_i,
|
||||
.fu_i,
|
||||
.fpu_valid_i,
|
||||
.fpu_ready_o,
|
||||
.operator_i ( fpu_data.operator ),
|
||||
.operand_a_i ( fpu_data.operand_a[FLEN-1:0] ),
|
||||
.operand_b_i ( fpu_data.operand_b[FLEN-1:0] ),
|
||||
.operand_c_i ( fpu_data.imm[FLEN-1:0] ),
|
||||
.fu_data_i ( fpu_data ),
|
||||
.fpu_fmt_i,
|
||||
.fpu_rm_i,
|
||||
.fpu_frm_i,
|
||||
.fpu_prec_i,
|
||||
.fpu_trans_id_o,
|
||||
.result_o ( fpu_result_o ),
|
||||
.result_o ( fpu_result_o ),
|
||||
.fpu_valid_o,
|
||||
.fpu_exception_o
|
||||
);
|
||||
|
@ -211,47 +246,44 @@ module ex_stage #(
|
|||
// Load-Store Unit
|
||||
// ----------------
|
||||
fu_data_t lsu_data;
|
||||
assign lsu_data.operator = lsu_valid_i ? operator_i : LD;
|
||||
assign lsu_data.operand_a = lsu_valid_i ? operand_a_i : '0;
|
||||
assign lsu_data.operand_b = lsu_valid_i ? operand_b_i : '0;
|
||||
assign lsu_data.imm = lsu_valid_i ? imm_i : '0;
|
||||
|
||||
assign lsu_data = lsu_valid_i ? fu_data_i : '0;
|
||||
|
||||
lsu lsu_i (
|
||||
.clk_i ,
|
||||
.rst_ni ,
|
||||
.flush_i ,
|
||||
.no_st_pending_o ,
|
||||
.fu_i ,
|
||||
.operator_i (lsu_data.operator ),
|
||||
.operand_a_i (lsu_data.operand_a ),
|
||||
.operand_b_i (lsu_data.operand_b ),
|
||||
.imm_i (lsu_data.imm ),
|
||||
.lsu_ready_o ,
|
||||
.lsu_valid_i ,
|
||||
.trans_id_i ,
|
||||
.lsu_trans_id_o ,
|
||||
.lsu_result_o ,
|
||||
.lsu_valid_o ,
|
||||
.commit_i (lsu_commit_i ),
|
||||
.commit_ready_o (lsu_commit_ready_o ),
|
||||
.enable_translation_i ,
|
||||
.en_ld_st_translation_i ,
|
||||
.icache_areq_i ,
|
||||
.icache_areq_o ,
|
||||
.priv_lvl_i ,
|
||||
.ld_st_priv_lvl_i ,
|
||||
.sum_i ,
|
||||
.mxr_i ,
|
||||
.satp_ppn_i ,
|
||||
.asid_i ,
|
||||
.flush_tlb_i ,
|
||||
.itlb_miss_o ,
|
||||
.dtlb_miss_o ,
|
||||
.dcache_req_ports_i ,
|
||||
.dcache_req_ports_o ,
|
||||
.lsu_exception_o ,
|
||||
.amo_valid_commit_i ,
|
||||
.amo_req_o ,
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i,
|
||||
.no_st_pending_o,
|
||||
.fu_data_i ( lsu_data ),
|
||||
.lsu_ready_o,
|
||||
.lsu_valid_i,
|
||||
.load_trans_id_o,
|
||||
.load_result_o,
|
||||
.load_valid_o,
|
||||
.load_exception_o,
|
||||
.store_trans_id_o,
|
||||
.store_result_o,
|
||||
.store_valid_o,
|
||||
.store_exception_o,
|
||||
.commit_i ( lsu_commit_i ),
|
||||
.commit_ready_o ( lsu_commit_ready_o ),
|
||||
.enable_translation_i,
|
||||
.en_ld_st_translation_i,
|
||||
.icache_areq_i,
|
||||
.icache_areq_o,
|
||||
.priv_lvl_i,
|
||||
.ld_st_priv_lvl_i,
|
||||
.sum_i,
|
||||
.mxr_i,
|
||||
.satp_ppn_i,
|
||||
.asid_i,
|
||||
.flush_tlb_i,
|
||||
.itlb_miss_o,
|
||||
.dtlb_miss_o,
|
||||
.dcache_req_ports_i,
|
||||
.dcache_req_ports_o,
|
||||
.amo_valid_commit_i,
|
||||
.amo_req_o,
|
||||
.amo_resp_i
|
||||
);
|
||||
|
||||
|
|
|
@ -12,21 +12,16 @@
|
|||
// Date: 12.04.2018
|
||||
// Description: Wrapper for the floating-point unit
|
||||
|
||||
|
||||
import ariane_pkg::*;
|
||||
|
||||
module fpu_wrap (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic flush_i,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input fu_t fu_i,
|
||||
input logic fpu_valid_i,
|
||||
output logic fpu_ready_o,
|
||||
input fu_op operator_i,
|
||||
input logic [FLEN-1:0] operand_a_i,
|
||||
input logic [FLEN-1:0] operand_b_i, // imm will be here unless used as operand
|
||||
input logic [FLEN-1:0] operand_c_i, // imm will be here unless used as operand
|
||||
input fu_data_t fu_data_i,
|
||||
|
||||
input logic [1:0] fpu_fmt_i,
|
||||
input logic [2:0] fpu_rm_i,
|
||||
input logic [2:0] fpu_frm_i,
|
||||
|
@ -41,6 +36,14 @@ module fpu_wrap (
|
|||
// otherwise compilation might issue an error if FLEN=0
|
||||
generate
|
||||
if (FP_PRESENT) begin : fpu_gen
|
||||
|
||||
logic [FLEN-1:0] operand_a_i;
|
||||
logic [FLEN-1:0] operand_b_i;
|
||||
logic [FLEN-1:0] operand_c_i;
|
||||
assign operand_a_i = fu_data_i.operand_a[FLEN-1:0];
|
||||
assign operand_b_i = fu_data_i.operand_b[FLEN-1:0];
|
||||
assign operand_c_i = fu_data_i.imm[FLEN-1:0];
|
||||
|
||||
//-----------------------------------
|
||||
// FPnew encoding from FPnew package
|
||||
//-----------------------------------
|
||||
|
@ -166,8 +169,8 @@ generate
|
|||
fpu_fmt2_d = FMT_FP32;
|
||||
fpu_ifmt_d = IFMT_INT32;
|
||||
fpu_rm_d = fpu_rm_i;
|
||||
fpu_vec_op_d = fu_i == FPU_VEC;
|
||||
fpu_tag_d = trans_id_i;
|
||||
fpu_vec_op_d = fu_data_i.fu == FPU_VEC;
|
||||
fpu_tag_d = fu_data_i.trans_id;
|
||||
vec_replication = fpu_rm_i[0]; // replication bit is sent via rm field
|
||||
replicate_c = 1'b0;
|
||||
check_ah = 1'b0; // whether set scalar AH encoding from MSB of rm_i
|
||||
|
@ -199,7 +202,7 @@ generate
|
|||
|
||||
|
||||
// Operations (this can modify the rounding mode field and format!)
|
||||
unique case (operator_i)
|
||||
unique case (fu_data_i.operator)
|
||||
// Addition
|
||||
FADD : begin
|
||||
fpu_op_d = OP_ADD;
|
||||
|
|
|
@ -40,16 +40,11 @@ module issue_read_operands #(
|
|||
input fu_t [2**REG_ADDR_SIZE:0] rd_clobber_gpr_i,
|
||||
input fu_t [2**REG_ADDR_SIZE:0] rd_clobber_fpr_i,
|
||||
// To FU, just single issue for now
|
||||
output fu_t fu_o,
|
||||
output fu_op operator_o,
|
||||
output logic [63:0] operand_a_o,
|
||||
output logic [63:0] operand_b_o,
|
||||
output logic [63:0] imm_o, // output immediate for the LSU
|
||||
output logic [TRANS_ID_BITS-1:0] trans_id_o,
|
||||
output fu_data_t fu_data_o,
|
||||
output logic [63:0] pc_o,
|
||||
output logic is_compressed_instr_o,
|
||||
// ALU 1
|
||||
input logic alu_ready_i, // FU is ready
|
||||
input logic flu_ready_i, // Fixed latency unit ready to accept a new request
|
||||
output logic alu_valid_o, // Output is valid
|
||||
// Branches and Jumps
|
||||
output logic branch_valid_o, // this is a valid branch instruction
|
||||
|
@ -58,7 +53,6 @@ module issue_read_operands #(
|
|||
input logic lsu_ready_i, // FU is ready
|
||||
output logic lsu_valid_o, // Output is valid
|
||||
// MULT
|
||||
input logic mult_ready_i, // FU is ready
|
||||
output logic mult_valid_o, // Output is valid
|
||||
// FPU
|
||||
input logic fpu_ready_i, // FU is ready
|
||||
|
@ -81,7 +75,6 @@ module issue_read_operands #(
|
|||
logic fu_busy; // functional unit is busy
|
||||
logic [63:0] operand_a_regfile, operand_b_regfile; // operands coming from regfile
|
||||
logic [FLEN-1:0] operand_c_regfile; // third operand only from fp regfile
|
||||
|
||||
// output flipflop (ID <-> EX)
|
||||
logic [63:0] operand_a_n, operand_a_q,
|
||||
operand_b_n, operand_b_q,
|
||||
|
@ -108,20 +101,20 @@ module issue_read_operands #(
|
|||
assign orig_instr = riscv::instruction_t'(issue_instr_i.ex.tval[31:0]);
|
||||
|
||||
// ID <-> EX registers
|
||||
assign operand_a_o = operand_a_q;
|
||||
assign operand_b_o = operand_b_q;
|
||||
assign fu_o = fu_q;
|
||||
assign operator_o = operator_q;
|
||||
assign alu_valid_o = alu_valid_q;
|
||||
assign branch_valid_o = branch_valid_q;
|
||||
assign lsu_valid_o = lsu_valid_q;
|
||||
assign csr_valid_o = csr_valid_q;
|
||||
assign mult_valid_o = mult_valid_q;
|
||||
assign fpu_valid_o = fpu_valid_q;
|
||||
assign fpu_fmt_o = fpu_fmt_q;
|
||||
assign fpu_rm_o = fpu_rm_q;
|
||||
assign trans_id_o = trans_id_q;
|
||||
assign imm_o = imm_q;
|
||||
assign fu_data_o.operand_a = operand_a_q;
|
||||
assign fu_data_o.operand_b = operand_b_q;
|
||||
assign fu_data_o.fu = fu_q;
|
||||
assign fu_data_o.operator = operator_q;
|
||||
assign fu_data_o.trans_id = trans_id_q;
|
||||
assign fu_data_o.imm = imm_q;
|
||||
assign alu_valid_o = alu_valid_q;
|
||||
assign branch_valid_o = branch_valid_q;
|
||||
assign lsu_valid_o = lsu_valid_q;
|
||||
assign csr_valid_o = csr_valid_q;
|
||||
assign mult_valid_o = mult_valid_q;
|
||||
assign fpu_valid_o = fpu_valid_q;
|
||||
assign fpu_fmt_o = fpu_fmt_q;
|
||||
assign fpu_rm_o = fpu_rm_q;
|
||||
// ---------------
|
||||
// Issue Stage
|
||||
// ---------------
|
||||
|
@ -132,10 +125,8 @@ module issue_read_operands #(
|
|||
unique case (issue_instr_i.fu)
|
||||
NONE:
|
||||
fu_busy = 1'b0;
|
||||
ALU, CTRL_FLOW, CSR:
|
||||
fu_busy = ~alu_ready_i;
|
||||
MULT:
|
||||
fu_busy = ~mult_ready_i;
|
||||
ALU, CTRL_FLOW, CSR, MULT:
|
||||
fu_busy = ~flu_ready_i;
|
||||
FPU, FPU_VEC:
|
||||
fu_busy = ~fpu_ready_i;
|
||||
LOAD, STORE:
|
||||
|
@ -170,27 +161,30 @@ module issue_read_operands #(
|
|||
// check if the clobbering instruction is not a CSR instruction, CSR instructions can only
|
||||
// be fetched through the register file since they can't be forwarded
|
||||
// if the operand is available, forward it. CSRs don't write to/from FPR
|
||||
if (rs1_valid_i && (is_rs1_fpr(issue_instr_i.op) ? 1'b1 : rd_clobber_gpr_i[issue_instr_i.rs1] != CSR))
|
||||
if (rs1_valid_i && (is_rs1_fpr(issue_instr_i.op) ? 1'b1 : rd_clobber_gpr_i[issue_instr_i.rs1] != CSR)) begin
|
||||
forward_rs1 = 1'b1;
|
||||
else // the operand is not available -> stall
|
||||
end else begin // the operand is not available -> stall
|
||||
stall = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (is_rs2_fpr(issue_instr_i.op) ? rd_clobber_fpr_i[issue_instr_i.rs2] != NONE
|
||||
: rd_clobber_gpr_i[issue_instr_i.rs2] != NONE) begin
|
||||
// if the operand is available, forward it. CSRs don't write to/from FPR
|
||||
if (rs2_valid_i && (is_rs2_fpr(issue_instr_i.op) ? 1'b1 : rd_clobber_gpr_i[issue_instr_i.rs2] != CSR))
|
||||
if (rs2_valid_i && (is_rs2_fpr(issue_instr_i.op) ? 1'b1 : rd_clobber_gpr_i[issue_instr_i.rs2] != CSR)) begin
|
||||
forward_rs2 = 1'b1;
|
||||
else // the operand is not available -> stall
|
||||
end else begin // the operand is not available -> stall
|
||||
stall = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (is_imm_fpr(issue_instr_i.op) && rd_clobber_fpr_i[issue_instr_i.result[REG_ADDR_SIZE-1:0]] != NONE) begin
|
||||
// if the operand is available, forward it. CSRs don't write to/from FPR so no need to check
|
||||
if (rs3_valid_i)
|
||||
if (rs3_valid_i) begin
|
||||
forward_rs3 = 1'b1;
|
||||
else // the operand is not available -> stall
|
||||
end else begin // the operand is not available -> stall
|
||||
stall = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -325,6 +319,11 @@ module issue_read_operands #(
|
|||
issue_ack_o = 1'b1;
|
||||
end
|
||||
end
|
||||
// after a multiplication was issued we can only issue another multiplication
|
||||
// otherwise we will get contentions on the fixed latency bus
|
||||
if (mult_valid_q && issue_instr_i.fu != MULT) begin
|
||||
issue_ack_o = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------
|
||||
|
|
|
@ -23,6 +23,7 @@ module issue_stage #(
|
|||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
||||
output logic sb_full_o,
|
||||
input logic flush_unissued_instr_i,
|
||||
input logic flush_i,
|
||||
// from ISSUE
|
||||
|
@ -31,16 +32,10 @@ module issue_stage #(
|
|||
input logic is_ctrl_flow_i,
|
||||
output logic decoded_instr_ack_o,
|
||||
// to EX
|
||||
output fu_t fu_o,
|
||||
output fu_op operator_o,
|
||||
output logic [63:0] operand_a_o,
|
||||
output logic [63:0] operand_b_o,
|
||||
output logic [63:0] imm_o,
|
||||
output logic [TRANS_ID_BITS-1:0] trans_id_o,
|
||||
output fu_data_t fu_data_o,
|
||||
output logic [63:0] pc_o,
|
||||
output logic is_compressed_instr_o,
|
||||
|
||||
input logic alu_ready_i,
|
||||
input logic flu_ready_i,
|
||||
output logic alu_valid_o,
|
||||
// ex just resolved our predicted branch, we are ready to accept new requests
|
||||
input logic resolve_branch_i,
|
||||
|
@ -49,10 +44,9 @@ module issue_stage #(
|
|||
output logic lsu_valid_o,
|
||||
// branch prediction
|
||||
output logic branch_valid_o, // use branch prediction unit
|
||||
output branchpredict_sbe_t branch_predict_o,
|
||||
output branchpredict_sbe_t branch_predict_o, // Branch predict Out
|
||||
|
||||
input logic mult_ready_i,
|
||||
output logic mult_valid_o, // Branch predict Out
|
||||
output logic mult_valid_o,
|
||||
|
||||
input logic fpu_ready_i,
|
||||
output logic fpu_valid_o,
|
||||
|
@ -126,6 +120,7 @@ module issue_stage #(
|
|||
.NR_ENTRIES (NR_ENTRIES ),
|
||||
.NR_WB_PORTS(NR_WB_PORTS)
|
||||
) i_scoreboard (
|
||||
.sb_full_o ( sb_full_o ),
|
||||
.unresolved_branch_i ( 1'b0 ),
|
||||
.rd_clobber_gpr_o ( rd_clobber_gpr_sb_iro ),
|
||||
.rd_clobber_fpr_o ( rd_clobber_fpr_sb_iro ),
|
||||
|
@ -161,6 +156,8 @@ module issue_stage #(
|
|||
.issue_instr_i ( issue_instr_sb_iro ),
|
||||
.issue_instr_valid_i ( issue_instr_valid_sb_iro ),
|
||||
.issue_ack_o ( issue_ack_iro_sb ),
|
||||
.fu_data_o ( fu_data_o ),
|
||||
.flu_ready_i ( flu_ready_i ),
|
||||
.rs1_o ( rs1_iro_sb ),
|
||||
.rs1_i ( rs1_sb_iro ),
|
||||
.rs1_valid_i ( rs1_valid_sb_iro ),
|
||||
|
@ -172,6 +169,10 @@ module issue_stage #(
|
|||
.rs3_valid_i ( rs3_valid_iro_sb ),
|
||||
.rd_clobber_gpr_i ( rd_clobber_gpr_sb_iro ),
|
||||
.rd_clobber_fpr_i ( rd_clobber_fpr_sb_iro ),
|
||||
.alu_valid_o ( alu_valid_o ),
|
||||
.branch_valid_o ( branch_valid_o ),
|
||||
.csr_valid_o ( csr_valid_o ),
|
||||
.mult_valid_o ( mult_valid_o ),
|
||||
.*
|
||||
);
|
||||
|
||||
|
|
71
src/lsu.sv
71
src/lsu.sv
|
@ -23,17 +23,20 @@ module lsu #(
|
|||
output logic no_st_pending_o,
|
||||
input logic amo_valid_commit_i,
|
||||
|
||||
input fu_t fu_i,
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
input logic [63:0] imm_i,
|
||||
input fu_data_t fu_data_i,
|
||||
output logic lsu_ready_o, // FU is ready e.g. not busy
|
||||
input logic lsu_valid_i, // Input is valid
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i, // transaction id, needed for WB
|
||||
output logic [TRANS_ID_BITS-1:0] lsu_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output logic [63:0] lsu_result_o,
|
||||
output logic lsu_valid_o, // transaction id for which the output is the requested one
|
||||
|
||||
output logic [TRANS_ID_BITS-1:0] load_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output logic [63:0] load_result_o,
|
||||
output logic load_valid_o,
|
||||
output exception_t load_exception_o, // to WB, signal exception status LD exception
|
||||
|
||||
output logic [TRANS_ID_BITS-1:0] store_trans_id_o, // ID of scoreboard entry at which to write back
|
||||
output logic [63:0] store_result_o,
|
||||
output logic store_valid_o,
|
||||
output exception_t store_exception_o, // to WB, signal exception status ST exception
|
||||
|
||||
input logic commit_i, // commit the pending store
|
||||
output logic commit_ready_o, // commit queue is ready to accept another commit request
|
||||
|
||||
|
@ -60,9 +63,7 @@ module lsu #(
|
|||
output dcache_req_i_t [2:0] dcache_req_ports_o,
|
||||
// AMO interface
|
||||
output amo_req_t amo_req_o,
|
||||
input amo_resp_t amo_resp_i,
|
||||
output exception_t lsu_exception_o // to WB, signal exception status LD/ST exception
|
||||
|
||||
input amo_resp_t amo_resp_i
|
||||
);
|
||||
// data is misaligned
|
||||
logic data_misaligned;
|
||||
|
@ -83,7 +84,7 @@ module lsu #(
|
|||
logic [63:0] vaddr_i;
|
||||
logic [7:0] be_i;
|
||||
|
||||
assign vaddr_i = $unsigned($signed(imm_i) + $signed(operand_a_i));
|
||||
assign vaddr_i = $unsigned($signed(fu_data_i.imm) + $signed(fu_data_i.operand_a));
|
||||
|
||||
logic st_valid_i;
|
||||
logic ld_valid_i;
|
||||
|
@ -201,27 +202,27 @@ module lsu #(
|
|||
.*
|
||||
);
|
||||
|
||||
// ---------------------
|
||||
// Result Sequentialize
|
||||
// ---------------------
|
||||
lsu_arbiter i_lsu_arbiter (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_i ),
|
||||
.ld_valid_i ( ld_valid ),
|
||||
.ld_trans_id_i ( ld_trans_id ),
|
||||
.ld_result_i ( ld_result ),
|
||||
.ld_ex_i ( ld_ex ),
|
||||
// ----------------------------
|
||||
// Output Pipeline Register
|
||||
// ----------------------------
|
||||
pipe_reg_simple #(
|
||||
.dtype ( logic[$bits(ld_valid) + $bits(ld_trans_id) + $bits(ld_result) + $bits(ld_ex) - 1: 0]),
|
||||
.Depth ( NR_LOAD_PIPE_REGS )
|
||||
) i_pipe_reg_load (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i ( {ld_valid, ld_trans_id, ld_result, ld_ex} ),
|
||||
.d_o ( {load_valid_o, load_trans_id_o, load_result_o, load_exception_o} )
|
||||
);
|
||||
|
||||
.st_valid_i ( st_valid ),
|
||||
.st_trans_id_i ( st_trans_id ),
|
||||
.st_result_i ( st_result ),
|
||||
.st_ex_i ( st_ex ),
|
||||
|
||||
.valid_o ( lsu_valid_o ),
|
||||
.trans_id_o ( lsu_trans_id_o ),
|
||||
.result_o ( lsu_result_o ),
|
||||
.ex_o ( lsu_exception_o )
|
||||
pipe_reg_simple #(
|
||||
.dtype ( logic[$bits(st_valid) + $bits(st_trans_id) + $bits(st_result) + $bits(st_ex) - 1: 0]),
|
||||
.Depth ( NR_STORE_PIPE_REGS )
|
||||
) i_pipe_reg_store (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.d_i ( {st_valid, st_trans_id, st_result, st_ex} ),
|
||||
.d_o ( {store_valid_o, store_trans_id_o, store_result_o, store_exception_o} )
|
||||
);
|
||||
|
||||
// determine whether this is a load or store
|
||||
|
@ -259,7 +260,7 @@ module lsu #(
|
|||
// we can generate the byte enable from the virtual address since the last
|
||||
// 12 bit are the same anyway
|
||||
// and we can always generate the byte enable from the address at hand
|
||||
assign be_i = be_gen(vaddr_i[2:0], extract_transfer_size(operator_i));
|
||||
assign be_i = be_gen(vaddr_i[2:0], extract_transfer_size(fu_data_i.operator));
|
||||
|
||||
// ------------------------
|
||||
// Misaligned Exception
|
||||
|
@ -354,7 +355,7 @@ module lsu #(
|
|||
// new data arrives here
|
||||
lsu_ctrl_t lsu_req_i;
|
||||
|
||||
assign lsu_req_i = {lsu_valid_i, vaddr_i, operand_b_i, be_i, fu_i, operator_i, trans_id_i};
|
||||
assign lsu_req_i = {lsu_valid_i, vaddr_i, fu_data_i.operand_b, be_i, fu_data_i.fu, fu_data_i.operator, fu_data_i.trans_id};
|
||||
|
||||
lsu_bypass lsu_bypass_i (
|
||||
.lsu_req_i ( lsu_req_i ),
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>, ETH Zurich
|
||||
// Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
|
||||
// Date: 15.08.2018
|
||||
// Description: Arbitrates the LSU result port
|
||||
|
||||
import ariane_pkg::*;
|
||||
|
||||
module lsu_arbiter (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic flush_i,
|
||||
// Load Port
|
||||
input logic ld_valid_i,
|
||||
input logic [TRANS_ID_BITS-1:0] ld_trans_id_i,
|
||||
input logic [63:0] ld_result_i,
|
||||
input exception_t ld_ex_i,
|
||||
// Store Port
|
||||
input logic st_valid_i,
|
||||
input logic [TRANS_ID_BITS-1:0] st_trans_id_i,
|
||||
input logic [63:0] st_result_i,
|
||||
input exception_t st_ex_i,
|
||||
// Output Port
|
||||
output logic valid_o,
|
||||
output logic [TRANS_ID_BITS-1:0] trans_id_o,
|
||||
output logic [63:0] result_o,
|
||||
output exception_t ex_o
|
||||
);
|
||||
|
||||
// the two fifos are used to buffer results from ld and st paths, and arbits between these results in
|
||||
// RR fashion. FIFOs need to be 2 deep in order to unconditionally accept loads and stores since we can
|
||||
// have a maximum of 2 outstanding loads.
|
||||
// if there are valid elements in the fifos, the unit posts the result on its output ports and expects it
|
||||
// to be consumed unconditionally
|
||||
|
||||
// Important: this needs to be greater than 2 to unconditionally acept incoming requests
|
||||
localparam int DEPTH = 4;
|
||||
|
||||
typedef struct packed {
|
||||
logic [TRANS_ID_BITS-1:0] trans_id;
|
||||
logic [63:0] result;
|
||||
exception_t ex;
|
||||
} fifo_t;
|
||||
|
||||
fifo_t st_in, st_out, ld_in, ld_out;
|
||||
|
||||
logic ld_full, ld_empty, ld_ren;
|
||||
logic st_full, st_empty, st_ren;
|
||||
logic idx;
|
||||
|
||||
assign st_in.trans_id = st_trans_id_i;
|
||||
assign st_in.result = st_result_i;
|
||||
assign st_in.ex = st_ex_i;
|
||||
|
||||
assign ld_in.trans_id = ld_trans_id_i;
|
||||
assign ld_in.result = ld_result_i;
|
||||
assign ld_in.ex = ld_ex_i;
|
||||
|
||||
assign trans_id_o = (idx) ? st_out.trans_id : ld_out.trans_id;
|
||||
assign result_o = (idx) ? st_out.result : ld_out.result;
|
||||
assign ex_o = (idx) ? st_out.ex : ld_out.ex;
|
||||
|
||||
// round robin with "lookahead" for 2 requesters
|
||||
rrarbiter #(
|
||||
.NUM_REQ ( 2 )
|
||||
) i_rrarbiter (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_i ),
|
||||
.en_i ( 1'b1 ),
|
||||
.req_i ( {~st_empty, ~ld_empty} ),
|
||||
.ack_o ( { st_ren, ld_ren } ),
|
||||
.vld_o ( valid_o ),
|
||||
.idx_o ( idx )
|
||||
);
|
||||
|
||||
fifo_v2 #(
|
||||
.dtype ( fifo_t ),
|
||||
.DEPTH ( DEPTH )
|
||||
) i_ld_fifo (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_i ),
|
||||
.testmode_i ( 1'b0 ),
|
||||
.full_o ( ld_full ),
|
||||
.empty_o ( ld_empty ),
|
||||
.alm_full_o ( ),
|
||||
.alm_empty_o ( ),
|
||||
.data_i ( ld_in ),
|
||||
.push_i ( ld_valid_i ),
|
||||
.data_o ( ld_out ),
|
||||
.pop_i ( ld_ren )
|
||||
);
|
||||
|
||||
fifo_v2 #(
|
||||
.dtype ( fifo_t ),
|
||||
.DEPTH ( DEPTH )
|
||||
) i_st_fifo (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_i ),
|
||||
.testmode_i ( 1'b0 ),
|
||||
.full_o ( st_full ),
|
||||
.empty_o ( st_empty ),
|
||||
.alm_full_o ( ),
|
||||
.alm_empty_o ( ),
|
||||
.data_i ( st_in ),
|
||||
.push_i ( st_valid_i ),
|
||||
.data_o ( st_out ),
|
||||
.pop_i ( st_ren )
|
||||
);
|
||||
|
||||
|
||||
//pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
// check fifo control signals
|
||||
assert property (@(posedge clk_i) disable iff (~rst_ni) ld_full |-> !ld_valid_i) else $fatal (1,"cannot write full ld_fifo");
|
||||
assert property (@(posedge clk_i) disable iff (~rst_ni) st_full |-> !st_valid_i) else $fatal (1,"cannot write full st_fifo");
|
||||
assert property (@(posedge clk_i) disable iff (~rst_ni) ld_empty |-> !ld_ren) else $fatal (1,"cannot read empty ld_fifo");
|
||||
assert property (@(posedge clk_i) disable iff (~rst_ni) st_empty |-> !st_ren) else $fatal (1,"cannot read empty st_fifo");
|
||||
`endif
|
||||
//pragma translate_on
|
||||
|
||||
endmodule
|
455
src/mult.sv
455
src/mult.sv
|
@ -1,17 +1,3 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
|
||||
//
|
||||
// Date: 05.06.2017
|
||||
// Description: Ariane Multiplier
|
||||
|
||||
import ariane_pkg::*;
|
||||
|
||||
|
@ -19,11 +5,8 @@ module mult (
|
|||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic flush_i,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input fu_data_t fu_data_i,
|
||||
input logic mult_valid_i,
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
output logic [63:0] result_o,
|
||||
output logic mult_valid_o,
|
||||
output logic mult_ready_o,
|
||||
|
@ -40,8 +23,8 @@ module mult (
|
|||
logic div_valid_op;
|
||||
logic mul_valid_op;
|
||||
// Input Arbitration
|
||||
assign mul_valid_op = ~flush_i && mult_valid_i && (operator_i inside { MUL, MULH, MULHU, MULHSU, MULW });
|
||||
assign div_valid_op = ~flush_i && mult_valid_i && (operator_i inside { DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW });
|
||||
assign mul_valid_op = ~flush_i && mult_valid_i && (fu_data_i.operator inside { MUL, MULH, MULHU, MULHSU, MULW });
|
||||
assign div_valid_op = ~flush_i && mult_valid_i && (fu_data_i.operator inside { DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW });
|
||||
|
||||
// ---------------------
|
||||
// Output Arbitration
|
||||
|
@ -58,44 +41,33 @@ module mult (
|
|||
// Multiplication
|
||||
// ---------------------
|
||||
mul i_mul (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.trans_id_i ( fu_data_i.trans_id ),
|
||||
.operator_i ( fu_data_i.operator ),
|
||||
.operand_a_i ( fu_data_i.operand_a ),
|
||||
.operand_b_i ( fu_data_i.operand_b ),
|
||||
.result_o ( mul_result ),
|
||||
.mult_valid_i ( mul_valid_op ),
|
||||
.mult_valid_o ( mul_valid ),
|
||||
.mult_trans_id_o ( mul_trans_id ),
|
||||
.mult_ready_o ( ), // this unit is unconditionally ready
|
||||
.*
|
||||
.mult_ready_o ( ) // this unit is unconditionally ready
|
||||
);
|
||||
|
||||
// ---------------------
|
||||
// Division
|
||||
// ---------------------
|
||||
logic [5:0] lzc_result; // holds the index of the last '1' (as the input operand is reversed)
|
||||
logic lzc_no_one; // no one was found by find first one
|
||||
logic [63:0] lzc_input; // input to find first one
|
||||
logic [63:0] operand_b_rev, operand_b_rev_neg, operand_b_shift; // couple of different representations for the dividend
|
||||
logic [6:0] div_shift; // amount of which to shift to left
|
||||
logic div_signed; // should this operation be performed as a signed or unsigned division
|
||||
logic div_op_signed; // actual sign signal depends on div_signed and the MSB of the word
|
||||
logic [63:0] operand_b, operand_a; // input operands after input MUX (input silencing, word operations or full inputs)
|
||||
logic [63:0] result; // result before result mux
|
||||
|
||||
logic word_op; // is it a word operation
|
||||
logic div_signed; // signed or unsigned division
|
||||
logic rem; // is it a reminder (or not a reminder e.g.: a division)
|
||||
logic word_op_d, word_op_q; // save whether the operation was signed or not
|
||||
|
||||
// is this a signed operation?
|
||||
assign div_signed = (operator_i inside {DIV, DIVW, REM, REMW}) ? 1'b1 : 1'b0;
|
||||
// if this operation is signed look at the actual sign bit to determine whether we should perform signed or unsigned division
|
||||
assign div_op_signed = div_signed & operand_b[63];
|
||||
|
||||
// reverse input operands
|
||||
generate
|
||||
for (genvar k = 0; k < 64; k++)
|
||||
assign operand_b_rev[k] = operand_b[63-k];
|
||||
endgenerate
|
||||
// negated reverse input operand, used for signed divisions
|
||||
assign operand_b_rev_neg = ~operand_b_rev;
|
||||
assign lzc_input = (div_op_signed) ? operand_b_rev_neg : operand_b_rev;
|
||||
// is this a signed op?
|
||||
assign div_signed = fu_data_i.operator inside {DIV, DIVW, REM, REMW};
|
||||
// is this a modulo?
|
||||
assign rem = fu_data_i.operator inside {REM, REMU, REMW, REMUW};
|
||||
|
||||
// prepare the input operands and control divider
|
||||
always_comb begin
|
||||
|
@ -103,82 +75,53 @@ module mult (
|
|||
operand_a = '0;
|
||||
operand_b = '0;
|
||||
// control signals
|
||||
word_op_d = word_op_q;
|
||||
word_op = 1'b0;
|
||||
rem = 1'b0;
|
||||
word_op_d = word_op_q;
|
||||
|
||||
// we've go a new division operation
|
||||
if (mult_valid_i && operator_i inside {DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW}) begin
|
||||
if (mult_valid_i && fu_data_i.operator inside {DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW}) begin
|
||||
// is this a word operation?
|
||||
if (operator_i inside {DIVW, DIVUW, REMW, REMUW}) begin
|
||||
word_op = 1'b1;
|
||||
if (fu_data_i.operator inside {DIVW, DIVUW, REMW, REMUW}) begin
|
||||
// yes so check if we should sign extend this is only done for a signed operation
|
||||
if (div_signed) begin
|
||||
operand_a = sext32(operand_a_i[31:0]);
|
||||
operand_b = sext32(operand_b_i[31:0]);
|
||||
operand_a = sext32(fu_data_i.operand_a[31:0]);
|
||||
operand_b = sext32(fu_data_i.operand_b[31:0]);
|
||||
end else begin
|
||||
operand_a = {32'b0, operand_a_i[31:0]};
|
||||
operand_b = {32'b0, operand_b_i[31:0]};
|
||||
operand_a = fu_data_i.operand_a[31:0];
|
||||
operand_b = fu_data_i.operand_b[31:0];
|
||||
end
|
||||
|
||||
// save whether we want sign extend the result or not, this is done for all word operations
|
||||
word_op_d = 1'b1;
|
||||
// regular operation
|
||||
end else begin
|
||||
// regular op
|
||||
operand_a = fu_data_i.operand_a;
|
||||
operand_b = fu_data_i.operand_b;
|
||||
word_op_d = 1'b0;
|
||||
// no sign extending is necessary as we are already using the full 64 bit
|
||||
operand_a = operand_a_i;
|
||||
operand_b = operand_b_i;
|
||||
end
|
||||
|
||||
// is this a modulo?
|
||||
if (operator_i inside {REM, REMU, REMW, REMUW}) begin
|
||||
rem = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ---------------------
|
||||
// Leading Zero Counter
|
||||
// ---------------------
|
||||
// this unit is used to speed up the sequential division by shifting the dividend first
|
||||
lzc #(
|
||||
.WIDTH ( 64 )
|
||||
) i_lzc (
|
||||
.in_i ( lzc_input ), // signed = operand_b_rev_neg, unsigned operand_b_rev
|
||||
.cnt_o ( lzc_result ),
|
||||
.empty_o ( lzc_no_one )
|
||||
);
|
||||
|
||||
// if the dividend is all zero go for the full length
|
||||
assign div_shift = lzc_no_one ? 7'd64 : lzc_result;
|
||||
// prepare dividend by shifting
|
||||
assign operand_b_shift = operand_b <<< div_shift;
|
||||
|
||||
// ---------------------
|
||||
// Serial Divider
|
||||
// ---------------------
|
||||
serial_divider #(
|
||||
.C_WIDTH ( 64 ),
|
||||
.C_LOG_WIDTH ( $clog2(64) + 1 )
|
||||
serdiv #(
|
||||
.WIDTH ( 64 )
|
||||
) i_div (
|
||||
.Clk_CI ( clk_i ),
|
||||
.Rst_RBI ( rst_ni ),
|
||||
.TransId_DI ( trans_id_i ),
|
||||
.OpA_DI ( operand_a ),
|
||||
.OpB_DI ( operand_b_shift ),
|
||||
.OpBShift_DI ( div_shift ),
|
||||
.OpBIsZero_SI ( ~(|operand_b) ),
|
||||
.OpBSign_SI ( div_op_signed ), // gate this to 0 in case of unsigned ops
|
||||
.OpCode_SI ( {rem, div_signed} ), // 00: udiv, 10: urem, 01: div, 11: rem
|
||||
.InVld_SI ( div_valid_op ),
|
||||
.Flush_SI ( flush_i ),
|
||||
.OutRdy_SO ( mult_ready_o ),
|
||||
.OutRdy_SI ( div_ready_i ),
|
||||
.OutVld_SO ( div_valid ),
|
||||
.TransId_DO ( div_trans_id ),
|
||||
.Res_DO ( result )
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.id_i ( fu_data_i.trans_id ),
|
||||
.op_a_i ( operand_a ),
|
||||
.op_b_i ( operand_b ),
|
||||
.opcode_i ( {rem, div_signed} ), // 00: udiv, 10: urem, 01: div, 11: rem
|
||||
.in_vld_i ( div_valid_op ),
|
||||
.in_rdy_o ( mult_ready_o ),
|
||||
.flush_i ( flush_i ),
|
||||
.out_vld_o ( div_valid ),
|
||||
.out_rdy_i ( div_ready_i ),
|
||||
.id_o ( div_trans_id ),
|
||||
.res_o ( result )
|
||||
);
|
||||
|
||||
// Result multiplexer
|
||||
// if it was a signed word operation the bit will be set and the result will be sign extended accordingly
|
||||
assign div_result = (word_op_q) ? sext32(result) : result;
|
||||
|
@ -188,323 +131,9 @@ module mult (
|
|||
// ---------------------
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if(~rst_ni) begin
|
||||
word_op_q <= ADD;
|
||||
word_op_q <= '0;
|
||||
end else begin
|
||||
word_op_q <= word_op_d;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
/* File : mult.sv
|
||||
* Ver : 1.0
|
||||
* Date : 15.03.2016
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2017 ETH Zurich, University of Bologna
|
||||
*
|
||||
* Description: this is a simple serial divider for signed integers.
|
||||
*
|
||||
*
|
||||
* Authors : Michael Schaffner (schaffner@iis.ee.ethz.ch)
|
||||
* Andreas Traber (atraber@iis.ee.ethz.ch)
|
||||
*
|
||||
*/
|
||||
module serial_divider #(
|
||||
parameter int unsigned C_WIDTH = 32,
|
||||
parameter int unsigned C_LOG_WIDTH = 6
|
||||
)(
|
||||
input logic Clk_CI,
|
||||
input logic Rst_RBI,
|
||||
// input IF
|
||||
input logic [TRANS_ID_BITS-1:0] TransId_DI,
|
||||
input logic [C_WIDTH-1:0] OpA_DI,
|
||||
input logic [C_WIDTH-1:0] OpB_DI,
|
||||
input logic [C_LOG_WIDTH-1:0] OpBShift_DI,
|
||||
input logic OpBIsZero_SI,
|
||||
//
|
||||
input logic OpBSign_SI, // gate this to 0 in case of unsigned ops
|
||||
input logic [1:0] OpCode_SI, // 0: udiv, 2: urem, 1: div, 3: rem
|
||||
// handshake
|
||||
input logic InVld_SI,
|
||||
input logic Flush_SI,
|
||||
// output IF
|
||||
output logic OutRdy_SO,
|
||||
input logic OutRdy_SI,
|
||||
output logic OutVld_SO,
|
||||
output logic [TRANS_ID_BITS-1:0] TransId_DO,
|
||||
output logic [C_WIDTH-1:0] Res_DO
|
||||
);
|
||||
|
||||
// ----------------------------------
|
||||
// Signal Declarations
|
||||
// ----------------------------------
|
||||
logic [C_WIDTH-1:0] ResReg_DP, ResReg_DN;
|
||||
logic [C_WIDTH-1:0] ResReg_DP_rev;
|
||||
logic [C_WIDTH-1:0] AReg_DP, AReg_DN;
|
||||
logic [C_WIDTH-1:0] BReg_DP, BReg_DN;
|
||||
logic OpBIsZero_SP, OpBIsZero_SN;
|
||||
|
||||
logic [TRANS_ID_BITS-1:0] TransId_DP, TransId_DN;
|
||||
|
||||
logic RemSel_SN, RemSel_SP;
|
||||
logic CompInv_SN, CompInv_SP;
|
||||
logic ResInv_SN, ResInv_SP;
|
||||
|
||||
logic [C_WIDTH-1:0] AddMux_D;
|
||||
logic [C_WIDTH-1:0] AddOut_D;
|
||||
logic [C_WIDTH-1:0] AddTmp_D;
|
||||
logic [C_WIDTH-1:0] BMux_D;
|
||||
logic [C_WIDTH-1:0] OutMux_D;
|
||||
|
||||
logic [C_LOG_WIDTH-1:0] Cnt_DP, Cnt_DN;
|
||||
logic CntZero_S;
|
||||
|
||||
logic ARegEn_S, BRegEn_S, ResRegEn_S, ABComp_S, PmSel_S, LoadEn_S;
|
||||
|
||||
enum logic [1:0] {IDLE, DIVIDE, FINISH} State_SN, State_SP;
|
||||
|
||||
|
||||
// -----------------
|
||||
// Datapath
|
||||
// -----------------
|
||||
assign PmSel_S = LoadEn_S & ~(OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI));
|
||||
|
||||
// muxes
|
||||
assign AddMux_D = (LoadEn_S) ? OpA_DI : BReg_DP;
|
||||
|
||||
// attention: logical shift in case of negative operand B!
|
||||
assign BMux_D = (LoadEn_S) ? OpB_DI : {CompInv_SP, (BReg_DP[$high(BReg_DP):1])};
|
||||
|
||||
assign ResReg_DP_rev = {<<{ResReg_DP}};
|
||||
assign OutMux_D = (RemSel_SP) ? AReg_DP : ResReg_DP_rev;
|
||||
|
||||
// invert if necessary
|
||||
assign Res_DO = (ResInv_SP) ? -$signed(OutMux_D) : OutMux_D;
|
||||
|
||||
// main comparator
|
||||
assign ABComp_S = ((AReg_DP == BReg_DP) | ((AReg_DP > BReg_DP) ^ CompInv_SP)) & ((|AReg_DP) | OpBIsZero_SP);
|
||||
|
||||
// main adder
|
||||
assign AddTmp_D = (LoadEn_S) ? 0 : AReg_DP;
|
||||
assign AddOut_D = (PmSel_S) ? AddTmp_D + AddMux_D : AddTmp_D - $signed(AddMux_D);
|
||||
|
||||
// -----------------
|
||||
// Counter
|
||||
// -----------------
|
||||
assign Cnt_DN = (LoadEn_S) ? OpBShift_DI :
|
||||
(~CntZero_S) ? Cnt_DP - 1 : Cnt_DP;
|
||||
|
||||
assign CntZero_S = ~(|Cnt_DP);
|
||||
|
||||
// -----------------
|
||||
// FSM
|
||||
// -----------------
|
||||
always_comb begin : p_fsm
|
||||
// default
|
||||
State_SN = State_SP;
|
||||
|
||||
OutVld_SO = 1'b0;
|
||||
OutRdy_SO = 1'b0;
|
||||
|
||||
LoadEn_S = 1'b0;
|
||||
|
||||
ARegEn_S = 1'b0;
|
||||
BRegEn_S = 1'b0;
|
||||
ResRegEn_S = 1'b0;
|
||||
|
||||
case (State_SP)
|
||||
|
||||
IDLE: begin
|
||||
OutRdy_SO = 1'b1;
|
||||
|
||||
if (InVld_SI) begin
|
||||
OutRdy_SO = 1'b0;
|
||||
OutVld_SO = 1'b0;
|
||||
ARegEn_S = 1'b1;
|
||||
BRegEn_S = 1'b1;
|
||||
LoadEn_S = 1'b1;
|
||||
State_SN = DIVIDE;
|
||||
end
|
||||
end
|
||||
|
||||
DIVIDE: begin
|
||||
|
||||
ARegEn_S = ABComp_S;
|
||||
BRegEn_S = 1'b1;
|
||||
ResRegEn_S = 1'b1;
|
||||
|
||||
// calculation finished
|
||||
// one more divide cycle (C_WIDTH th divide cycle)
|
||||
if (CntZero_S) begin
|
||||
State_SN = FINISH;
|
||||
end
|
||||
end
|
||||
|
||||
FINISH: begin
|
||||
OutVld_SO = 1'b1;
|
||||
|
||||
if (OutRdy_SI) begin
|
||||
State_SN = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
default : /* default */ ;
|
||||
|
||||
endcase
|
||||
|
||||
if (Flush_SI) begin
|
||||
OutRdy_SO = 1'b0;
|
||||
OutVld_SO = 1'b0;
|
||||
ARegEn_S = 1'b0;
|
||||
BRegEn_S = 1'b0;
|
||||
LoadEn_S = 1'b0;
|
||||
State_SN = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
// -----------------
|
||||
// Registers
|
||||
// -----------------
|
||||
// get flags
|
||||
assign RemSel_SN = (LoadEn_S) ? OpCode_SI[1] : RemSel_SP;
|
||||
assign CompInv_SN = (LoadEn_S) ? OpBSign_SI : CompInv_SP;
|
||||
assign OpBIsZero_SN = (LoadEn_S) ? OpBIsZero_SI : OpBIsZero_SP;
|
||||
assign ResInv_SN = (LoadEn_S) ? (~OpBIsZero_SI | OpCode_SI[1]) & OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI) : ResInv_SP;
|
||||
|
||||
// transaction id
|
||||
assign TransId_DN = (LoadEn_S) ? TransId_DI : TransId_DP;
|
||||
assign TransId_DO = TransId_DP;
|
||||
|
||||
assign AReg_DN = (ARegEn_S) ? AddOut_D : AReg_DP;
|
||||
assign BReg_DN = (BRegEn_S) ? BMux_D : BReg_DP;
|
||||
assign ResReg_DN = (LoadEn_S) ? '0 :
|
||||
(ResRegEn_S) ? {ABComp_S, ResReg_DP[$high(ResReg_DP):1]} : ResReg_DP;
|
||||
|
||||
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin : p_regs
|
||||
if (~Rst_RBI) begin
|
||||
State_SP <= IDLE;
|
||||
AReg_DP <= '0;
|
||||
BReg_DP <= '0;
|
||||
ResReg_DP <= '0;
|
||||
Cnt_DP <= '0;
|
||||
TransId_DP <= '0;
|
||||
RemSel_SP <= 1'b0;
|
||||
CompInv_SP <= 1'b0;
|
||||
ResInv_SP <= 1'b0;
|
||||
OpBIsZero_SP <= 1'b0;
|
||||
end else begin
|
||||
State_SP <= State_SN;
|
||||
AReg_DP <= AReg_DN;
|
||||
BReg_DP <= BReg_DN;
|
||||
ResReg_DP <= ResReg_DN;
|
||||
Cnt_DP <= Cnt_DN;
|
||||
TransId_DP <= TransId_DN;
|
||||
RemSel_SP <= RemSel_SN;
|
||||
CompInv_SP <= CompInv_SN;
|
||||
ResInv_SP <= ResInv_SN;
|
||||
OpBIsZero_SP <= OpBIsZero_SN;
|
||||
end
|
||||
end
|
||||
|
||||
// ------------
|
||||
// Assertions
|
||||
// ------------
|
||||
//pragma translate_off
|
||||
initial begin : p_assertions
|
||||
assert (C_LOG_WIDTH == $clog2(C_WIDTH+1)) else $error("C_LOG_WIDTH must be $clog2(C_WIDTH+1)");
|
||||
end
|
||||
//pragma translate_on
|
||||
|
||||
endmodule
|
||||
|
||||
// --------------------------------------------------
|
||||
// Multiplication Unit with one pipeline register
|
||||
// --------------------------------------------------
|
||||
module mul (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input logic mult_valid_i,
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
output logic [63:0] result_o,
|
||||
output logic mult_valid_o,
|
||||
output logic mult_ready_o,
|
||||
output logic [TRANS_ID_BITS-1:0] mult_trans_id_o
|
||||
|
||||
);
|
||||
// Pipeline register
|
||||
logic [TRANS_ID_BITS-1:0] trans_id_q;
|
||||
logic mult_valid_q;
|
||||
fu_op operator_d, operator_q;
|
||||
logic [127:0] mult_result_d, mult_result_q;
|
||||
|
||||
// control registers
|
||||
logic sign_a, sign_b;
|
||||
logic mult_valid;
|
||||
|
||||
// control signals
|
||||
assign mult_valid_o = mult_valid_q;
|
||||
assign mult_trans_id_o = trans_id_q;
|
||||
assign mult_ready_o = 1'b1;
|
||||
|
||||
assign mult_valid = mult_valid_i && (operator_i inside {MUL, MULH, MULHU, MULHSU, MULW});
|
||||
// datapath
|
||||
logic [127:0] mult_result;
|
||||
assign mult_result = $signed({operand_a_i[63] & sign_a, operand_a_i}) * $signed({operand_b_i[63] & sign_b, operand_b_i});
|
||||
|
||||
// Sign Select MUX
|
||||
always_comb begin
|
||||
sign_a = 1'b0;
|
||||
sign_b = 1'b0;
|
||||
|
||||
// signed multiplication
|
||||
if (operator_i == MULH) begin
|
||||
sign_a = 1'b1;
|
||||
sign_b = 1'b1;
|
||||
// signed - unsigned multiplication
|
||||
end else if (operator_i == MULHSU) begin
|
||||
sign_a = 1'b1;
|
||||
// unsigned multiplication
|
||||
end else begin
|
||||
sign_a = 1'b0;
|
||||
sign_b = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// single stage version
|
||||
assign mult_result_d = $signed({operand_a_i[63] & sign_a, operand_a_i}) *
|
||||
$signed({operand_b_i[63] & sign_b, operand_b_i});
|
||||
|
||||
|
||||
assign operator_d = operator_i;
|
||||
always_comb begin : p_selmux
|
||||
unique case (operator_q)
|
||||
MULH, MULHU, MULHSU: result_o = mult_result_q[127:64];
|
||||
MULW: result_o = sext32(mult_result_q[31:0]);
|
||||
// MUL performs an XLEN-bit×XLEN-bit multiplication and places the lower XLEN bits in the destination register
|
||||
default: result_o = mult_result_q[63:0];// including MUL
|
||||
endcase
|
||||
end
|
||||
|
||||
// -----------------------
|
||||
// Output pipeline register
|
||||
// -----------------------
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
mult_valid_q <= '0;
|
||||
trans_id_q <= '0;
|
||||
operator_q <= MUL;
|
||||
mult_result_q <= '0;
|
||||
end else begin
|
||||
// Input silencing
|
||||
trans_id_q <= trans_id_i;
|
||||
// Output Register
|
||||
mult_valid_q <= mult_valid;
|
||||
operator_q <= operator_d;
|
||||
mult_result_q <= mult_result_d;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
105
src/multiplier.sv
Normal file
105
src/multiplier.sv
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
|
||||
//
|
||||
// Description: Multiplication Unit with one pipeline register
|
||||
// This unit relies on retiming features of the synthesizer
|
||||
//
|
||||
|
||||
import ariane_pkg::*;
|
||||
|
||||
module mul (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic [TRANS_ID_BITS-1:0] trans_id_i,
|
||||
input logic mult_valid_i,
|
||||
input fu_op operator_i,
|
||||
input logic [63:0] operand_a_i,
|
||||
input logic [63:0] operand_b_i,
|
||||
output logic [63:0] result_o,
|
||||
output logic mult_valid_o,
|
||||
output logic mult_ready_o,
|
||||
output logic [TRANS_ID_BITS-1:0] mult_trans_id_o
|
||||
);
|
||||
// Pipeline register
|
||||
logic [TRANS_ID_BITS-1:0] trans_id_q;
|
||||
logic mult_valid_q;
|
||||
fu_op operator_d, operator_q;
|
||||
logic [127:0] mult_result_d, mult_result_q;
|
||||
|
||||
// control registers
|
||||
logic sign_a, sign_b;
|
||||
logic mult_valid;
|
||||
|
||||
// control signals
|
||||
assign mult_valid_o = mult_valid_q;
|
||||
assign mult_trans_id_o = trans_id_q;
|
||||
assign mult_ready_o = 1'b1;
|
||||
|
||||
assign mult_valid = mult_valid_i && (operator_i inside {MUL, MULH, MULHU, MULHSU, MULW});
|
||||
// datapath
|
||||
logic [127:0] mult_result;
|
||||
assign mult_result = $signed({operand_a_i[63] & sign_a, operand_a_i}) * $signed({operand_b_i[63] & sign_b, operand_b_i});
|
||||
|
||||
// Sign Select MUX
|
||||
always_comb begin
|
||||
sign_a = 1'b0;
|
||||
sign_b = 1'b0;
|
||||
|
||||
// signed multiplication
|
||||
if (operator_i == MULH) begin
|
||||
sign_a = 1'b1;
|
||||
sign_b = 1'b1;
|
||||
// signed - unsigned multiplication
|
||||
end else if (operator_i == MULHSU) begin
|
||||
sign_a = 1'b1;
|
||||
// unsigned multiplication
|
||||
end else begin
|
||||
sign_a = 1'b0;
|
||||
sign_b = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// single stage version
|
||||
assign mult_result_d = $signed({operand_a_i[63] & sign_a, operand_a_i}) *
|
||||
$signed({operand_b_i[63] & sign_b, operand_b_i});
|
||||
|
||||
|
||||
assign operator_d = operator_i;
|
||||
always_comb begin : p_selmux
|
||||
unique case (operator_q)
|
||||
MULH, MULHU, MULHSU: result_o = mult_result_q[127:64];
|
||||
MULW: result_o = sext32(mult_result_q[31:0]);
|
||||
// MUL performs an XLEN-bit×XLEN-bit multiplication and places the lower XLEN bits in the destination register
|
||||
default: result_o = mult_result_q[63:0];// including MUL
|
||||
endcase
|
||||
end
|
||||
|
||||
// -----------------------
|
||||
// Output pipeline register
|
||||
// -----------------------
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
mult_valid_q <= '0;
|
||||
trans_id_q <= '0;
|
||||
operator_q <= MUL;
|
||||
mult_result_q <= '0;
|
||||
end else begin
|
||||
// Input silencing
|
||||
trans_id_q <= trans_id_i;
|
||||
// Output Register
|
||||
mult_valid_q <= mult_valid;
|
||||
operator_q <= operator_d;
|
||||
mult_result_q <= mult_result_d;
|
||||
end
|
||||
end
|
||||
endmodule
|
|
@ -17,8 +17,9 @@ import ariane_pkg::*;
|
|||
module perf_counters #(
|
||||
int unsigned NR_EXTERNAL_COUNTERS = 1
|
||||
)(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic debug_mode_i, // debug mode
|
||||
// SRAM like interface
|
||||
input logic [11:0] addr_i, // read/write address
|
||||
input logic we_i, // write enable
|
||||
|
@ -34,65 +35,80 @@ module perf_counters #(
|
|||
// from MMU
|
||||
input logic itlb_miss_i,
|
||||
input logic dtlb_miss_i,
|
||||
// from issue stage
|
||||
input logic sb_full_i,
|
||||
// from frontend
|
||||
input logic if_empty_i,
|
||||
// from PC Gen
|
||||
input exception_t ex_i,
|
||||
input logic eret_i,
|
||||
input branchpredict_t resolved_branch_i
|
||||
);
|
||||
|
||||
logic [11:0][63:0] perf_counter_d, perf_counter_q;
|
||||
logic [13:0][63:0] perf_counter_d, perf_counter_q;
|
||||
|
||||
always_comb begin : perf_counters
|
||||
perf_counter_d = perf_counter_q;
|
||||
data_o = 'b0;
|
||||
|
||||
// ------------------------------
|
||||
// Update Performance Counters
|
||||
// ------------------------------
|
||||
if (l1_icache_miss_i)
|
||||
perf_counter_d[riscv::PERF_L1_ICACHE_MISS] = perf_counter_q[riscv::PERF_L1_ICACHE_MISS] + 1'b1;
|
||||
// don't increment counters in debug mode
|
||||
if (!debug_mode_i) begin
|
||||
// ------------------------------
|
||||
// Update Performance Counters
|
||||
// ------------------------------
|
||||
if (l1_icache_miss_i)
|
||||
perf_counter_d[riscv::PERF_L1_ICACHE_MISS] = perf_counter_q[riscv::PERF_L1_ICACHE_MISS] + 1'b1;
|
||||
|
||||
if (l1_dcache_miss_i)
|
||||
perf_counter_d[riscv::PERF_L1_DCACHE_MISS] = perf_counter_q[riscv::PERF_L1_DCACHE_MISS] + 1'b1;
|
||||
if (l1_dcache_miss_i)
|
||||
perf_counter_d[riscv::PERF_L1_DCACHE_MISS] = perf_counter_q[riscv::PERF_L1_DCACHE_MISS] + 1'b1;
|
||||
|
||||
if (itlb_miss_i)
|
||||
perf_counter_d[riscv::PERF_ITLB_MISS] = perf_counter_q[riscv::PERF_ITLB_MISS] + 1'b1;
|
||||
if (itlb_miss_i)
|
||||
perf_counter_d[riscv::PERF_ITLB_MISS] = perf_counter_q[riscv::PERF_ITLB_MISS] + 1'b1;
|
||||
|
||||
if (dtlb_miss_i)
|
||||
perf_counter_d[riscv::PERF_DTLB_MISS] = perf_counter_q[riscv::PERF_DTLB_MISS] + 1'b1;
|
||||
if (dtlb_miss_i)
|
||||
perf_counter_d[riscv::PERF_DTLB_MISS] = perf_counter_q[riscv::PERF_DTLB_MISS] + 1'b1;
|
||||
|
||||
// instruction related perf counters
|
||||
for (int unsigned i = 0; i < NR_COMMIT_PORTS-1; i++) begin
|
||||
if (commit_ack_i[i]) begin
|
||||
if (commit_instr_i[i].fu == LOAD)
|
||||
perf_counter_d[riscv::PERF_LOAD] = perf_counter_q[riscv::PERF_LOAD] + 1'b1;
|
||||
// instruction related perf counters
|
||||
for (int unsigned i = 0; i < NR_COMMIT_PORTS-1; i++) begin
|
||||
if (commit_ack_i[i]) begin
|
||||
if (commit_instr_i[i].fu == LOAD)
|
||||
perf_counter_d[riscv::PERF_LOAD] = perf_counter_q[riscv::PERF_LOAD] + 1'b1;
|
||||
|
||||
if (commit_instr_i[i].fu == STORE)
|
||||
perf_counter_d[riscv::PERF_STORE] = perf_counter_q[riscv::PERF_STORE] + 1'b1;
|
||||
if (commit_instr_i[i].fu == STORE)
|
||||
perf_counter_d[riscv::PERF_STORE] = perf_counter_q[riscv::PERF_STORE] + 1'b1;
|
||||
|
||||
if (commit_instr_i[i].fu == CTRL_FLOW)
|
||||
perf_counter_d[riscv::PERF_BRANCH_JUMP] = perf_counter_q[riscv::PERF_BRANCH_JUMP] + 1'b1;
|
||||
if (commit_instr_i[i].fu == CTRL_FLOW)
|
||||
perf_counter_d[riscv::PERF_BRANCH_JUMP] = perf_counter_q[riscv::PERF_BRANCH_JUMP] + 1'b1;
|
||||
|
||||
// The standard software calling convention uses register x1 to hold the return address on a call
|
||||
// the unconditional jump is decoded as ADD op
|
||||
if (commit_instr_i[i].fu == CTRL_FLOW && commit_instr_i[i].op == '0 && commit_instr_i[i].rd == 'b1)
|
||||
perf_counter_d[riscv::PERF_CALL] = perf_counter_q[riscv::PERF_CALL] + 1'b1;
|
||||
// The standard software calling convention uses register x1 to hold the return address on a call
|
||||
// the unconditional jump is decoded as ADD op
|
||||
if (commit_instr_i[i].fu == CTRL_FLOW && commit_instr_i[i].op == '0 && commit_instr_i[i].rd == 'b1)
|
||||
perf_counter_d[riscv::PERF_CALL] = perf_counter_q[riscv::PERF_CALL] + 1'b1;
|
||||
|
||||
// Return from call
|
||||
if (commit_instr_i[i].op == JALR && commit_instr_i[i].rs1 == 'b1)
|
||||
perf_counter_d[riscv::PERF_RET] = perf_counter_q[riscv::PERF_RET] + 1'b1;
|
||||
// Return from call
|
||||
if (commit_instr_i[i].op == JALR && commit_instr_i[i].rs1 == 'b1)
|
||||
perf_counter_d[riscv::PERF_RET] = perf_counter_q[riscv::PERF_RET] + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (ex_i.valid)
|
||||
perf_counter_d[riscv::PERF_EXCEPTION] = perf_counter_q[riscv::PERF_EXCEPTION] + 1'b1;
|
||||
|
||||
if (eret_i)
|
||||
perf_counter_d[riscv::PERF_EXCEPTION_RET] = perf_counter_q[riscv::PERF_EXCEPTION_RET] + 1'b1;
|
||||
|
||||
if (resolved_branch_i.valid && resolved_branch_i.is_mispredict)
|
||||
perf_counter_d[riscv::PERF_MIS_PREDICT] = perf_counter_q[riscv::PERF_MIS_PREDICT] + 1'b1;
|
||||
|
||||
if (sb_full_i) begin
|
||||
perf_counter_d[riscv::PERF_SB_FULL] = perf_counter_q[riscv::PERF_SB_FULL] + 1'b1;
|
||||
end
|
||||
|
||||
if (if_empty_i) begin
|
||||
perf_counter_d[riscv::PERF_IF_EMPTY] = perf_counter_q[riscv::PERF_IF_EMPTY] + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (ex_i.valid)
|
||||
perf_counter_d[riscv::PERF_EXCEPTION] = perf_counter_q[riscv::PERF_EXCEPTION] + 1'b1;
|
||||
|
||||
if (eret_i)
|
||||
perf_counter_d[riscv::PERF_EXCEPTION_RET] = perf_counter_q[riscv::PERF_EXCEPTION_RET] + 1'b1;
|
||||
|
||||
if (resolved_branch_i.valid && resolved_branch_i.is_mispredict)
|
||||
perf_counter_d[riscv::PERF_MIS_PREDICT] = perf_counter_q[riscv::PERF_MIS_PREDICT] + 1'b1;
|
||||
|
||||
// Read Port
|
||||
if (!we_i) begin
|
||||
data_o = perf_counter_q[addr_i[2:0]];
|
||||
|
|
|
@ -21,6 +21,7 @@ module scoreboard #(
|
|||
)(
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
output logic sb_full_o,
|
||||
input logic flush_unissued_instr_i, // flush only un-issued instructions
|
||||
input logic flush_i, // flush whole scoreboard
|
||||
input logic unresolved_branch_i, // we have an unresolved branch
|
||||
|
@ -79,6 +80,8 @@ module scoreboard #(
|
|||
// the issue queue is full don't issue any new instructions
|
||||
assign issue_full = (issue_cnt_q == NR_ENTRIES-1);
|
||||
|
||||
assign sb_full_o = issue_full;
|
||||
|
||||
// output commit instruction directly
|
||||
always_comb begin : commit_ports
|
||||
for (logic [BITS_ENTRIES-1:0] i = 0; i < NR_COMMIT_PORTS; i++)
|
||||
|
|
258
src/serdiv.sv
Normal file
258
src/serdiv.sv
Normal file
|
@ -0,0 +1,258 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
|
||||
// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich
|
||||
//
|
||||
// Date: 18.10.2018
|
||||
// Description: simple 64bit serial divider
|
||||
|
||||
import ariane_pkg::*;
|
||||
|
||||
module serdiv #(
|
||||
parameter WIDTH = 64
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
// input IF
|
||||
input logic [TRANS_ID_BITS-1:0] id_i,
|
||||
input logic [WIDTH-1:0] op_a_i,
|
||||
input logic [WIDTH-1:0] op_b_i,
|
||||
input logic [1:0] opcode_i, // 0: udiv, 2: urem, 1: div, 3: rem
|
||||
// handshake
|
||||
input logic in_vld_i, // there is a cycle delay from in_rdy_o->in_vld_i, see issue_read_operands.sv stage
|
||||
output logic in_rdy_o,
|
||||
input logic flush_i,
|
||||
// output IF
|
||||
output logic out_vld_o,
|
||||
input logic out_rdy_i,
|
||||
output logic [TRANS_ID_BITS-1:0] id_o,
|
||||
output logic [WIDTH-1:0] res_o
|
||||
);
|
||||
|
||||
/////////////////////////////////////
|
||||
// signal declarations
|
||||
/////////////////////////////////////
|
||||
|
||||
enum logic [1:0] {IDLE, DIVIDE, FINISH} state_d, state_q;
|
||||
|
||||
logic [WIDTH-1:0] res_q, res_d;
|
||||
logic [WIDTH-1:0] op_a_q, op_a_d;
|
||||
logic [WIDTH-1:0] op_b_q, op_b_d;
|
||||
logic op_a_sign, op_b_sign;
|
||||
logic op_b_zero, op_b_zero_q, op_b_zero_d;
|
||||
|
||||
logic [TRANS_ID_BITS-1:0] id_q, id_d;
|
||||
|
||||
logic rem_sel_d, rem_sel_q;
|
||||
logic comp_inv_d, comp_inv_q;
|
||||
logic res_inv_d, res_inv_q;
|
||||
|
||||
logic [WIDTH-1:0] add_mux;
|
||||
logic [WIDTH-1:0] add_out;
|
||||
logic [WIDTH-1:0] add_tmp;
|
||||
logic [WIDTH-1:0] b_mux;
|
||||
logic [WIDTH-1:0] out_mux;
|
||||
|
||||
logic [$clog2(WIDTH+1)-1:0] cnt_q, cnt_d;
|
||||
logic cnt_zero;
|
||||
|
||||
logic [WIDTH-1:0] lzc_a_input, lzc_b_input, op_b;
|
||||
logic [$clog2(WIDTH)-1:0] lzc_a_result, lzc_b_result;
|
||||
logic [$clog2(WIDTH+1)-1:0] shift_a;
|
||||
logic [$clog2(WIDTH+1):0] div_shift;
|
||||
|
||||
logic a_reg_en, b_reg_en, res_reg_en, ab_comp, pm_sel, load_en;
|
||||
logic lzc_a_no_one, lzc_b_no_one;
|
||||
logic div_res_zero_d, div_res_zero_q;
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
// align the input operands
|
||||
// for faster division
|
||||
/////////////////////////////////////
|
||||
|
||||
assign op_b_zero = (op_b_i == 0);
|
||||
assign op_a_sign = op_a_i[$high(op_a_i)];
|
||||
assign op_b_sign = op_b_i[$high(op_b_i)];
|
||||
|
||||
assign lzc_a_input = (opcode_i[0] & op_a_sign) ? {~op_a_i, 1'b0} : op_a_i;
|
||||
assign lzc_b_input = (opcode_i[0] & op_b_sign) ? ~op_b_i : op_b_i;
|
||||
|
||||
lzc #(
|
||||
.MODE ( 1 ), // count leading zeros
|
||||
.WIDTH ( WIDTH )
|
||||
) i_lzc_a (
|
||||
.in_i ( lzc_a_input ),
|
||||
.cnt_o ( lzc_a_result ),
|
||||
.empty_o ( lzc_a_no_one )
|
||||
);
|
||||
|
||||
lzc #(
|
||||
.MODE ( 1 ), // count leading zeros
|
||||
.WIDTH ( WIDTH )
|
||||
) i_lzc_b (
|
||||
.in_i ( lzc_b_input ),
|
||||
.cnt_o ( lzc_b_result ),
|
||||
.empty_o ( lzc_b_no_one )
|
||||
);
|
||||
|
||||
assign shift_a = (lzc_a_no_one) ? WIDTH : lzc_a_result;
|
||||
assign div_shift = (lzc_b_no_one) ? WIDTH : lzc_b_result-shift_a;
|
||||
|
||||
assign op_b = op_b_i <<< $unsigned(div_shift);
|
||||
|
||||
// the division is zero if |opB| > |opA| and can be terminated
|
||||
assign div_res_zero_d = (load_en) ? ($signed(div_shift) < 0) : div_res_zero_q;
|
||||
|
||||
/////////////////////////////////////
|
||||
// Datapath
|
||||
/////////////////////////////////////
|
||||
|
||||
assign pm_sel = load_en & ~(opcode_i[0] & (op_a_sign ^ op_b_sign));
|
||||
|
||||
// muxes
|
||||
assign add_mux = (load_en) ? op_a_i : op_b_q;
|
||||
|
||||
// attention: logical shift by one in case of negative operand B!
|
||||
assign b_mux = (load_en) ? op_b : {comp_inv_q, (op_b_q[$high(op_b_q):1])};
|
||||
|
||||
// in case of bad timing, we could output from regs -> needs a cycle more in the FSM
|
||||
assign out_mux = (rem_sel_q) ? op_a_q : res_q;
|
||||
// assign out_mux = (rem_sel_q) ? op_a_d : res_d;
|
||||
|
||||
// invert if necessary
|
||||
assign res_o = (res_inv_q) ? -$signed(out_mux) : out_mux;
|
||||
|
||||
// main comparator
|
||||
assign ab_comp = ((op_a_q == op_b_q) | ((op_a_q > op_b_q) ^ comp_inv_q)) & ((|op_a_q) | op_b_zero_q);
|
||||
|
||||
// main adder
|
||||
assign add_tmp = (load_en) ? 0 : op_a_q;
|
||||
assign add_out = (pm_sel) ? add_tmp + add_mux : add_tmp - $signed(add_mux);
|
||||
|
||||
/////////////////////////////////////
|
||||
// FSM, counter
|
||||
/////////////////////////////////////
|
||||
|
||||
assign cnt_zero = (cnt_q == 0);
|
||||
assign cnt_d = (load_en) ? div_shift :
|
||||
(~cnt_zero) ? cnt_q - 1 : cnt_q;
|
||||
|
||||
always_comb begin : p_fsm
|
||||
// default
|
||||
state_d = state_q;
|
||||
in_rdy_o = 1'b0;
|
||||
out_vld_o = 1'b0;
|
||||
load_en = 1'b0;
|
||||
a_reg_en = 1'b0;
|
||||
b_reg_en = 1'b0;
|
||||
res_reg_en = 1'b0;
|
||||
|
||||
unique case (state_q)
|
||||
IDLE: begin
|
||||
in_rdy_o = 1'b1;
|
||||
|
||||
if (in_vld_i) begin
|
||||
in_rdy_o = 1'b0;// there is a cycle delay until the valid signal is asserted by the id stage
|
||||
a_reg_en = 1'b1;
|
||||
b_reg_en = 1'b1;
|
||||
load_en = 1'b1;
|
||||
state_d = DIVIDE;
|
||||
end
|
||||
end
|
||||
DIVIDE: begin
|
||||
if(~div_res_zero_q) begin
|
||||
a_reg_en = ab_comp;
|
||||
b_reg_en = 1'b1;
|
||||
res_reg_en = 1'b1;
|
||||
end
|
||||
// can end the division now if the result is clearly 0
|
||||
if(div_res_zero_q) begin
|
||||
out_vld_o = 1'b1;
|
||||
state_d = FINISH;
|
||||
if(out_rdy_i) begin
|
||||
// in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage
|
||||
state_d = IDLE;
|
||||
end
|
||||
end else if (cnt_zero) begin
|
||||
state_d = FINISH;
|
||||
end
|
||||
end
|
||||
FINISH: begin
|
||||
out_vld_o = 1'b1;
|
||||
|
||||
if (out_rdy_i) begin
|
||||
// in_rdy_o = 1'b1;// there is a cycle delay until the valid signal is asserted by the id stage
|
||||
state_d = IDLE;
|
||||
end
|
||||
end
|
||||
default : state_d = IDLE;
|
||||
endcase
|
||||
|
||||
if (flush_i) begin
|
||||
in_rdy_o = 1'b0;
|
||||
out_vld_o = 1'b0;
|
||||
a_reg_en = 1'b0;
|
||||
b_reg_en = 1'b0;
|
||||
load_en = 1'b0;
|
||||
state_d = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
// regs, flags
|
||||
/////////////////////////////////////
|
||||
|
||||
// get flags
|
||||
assign rem_sel_d = (load_en) ? opcode_i[1] : rem_sel_q;
|
||||
assign comp_inv_d = (load_en) ? opcode_i[0] & op_b_sign : comp_inv_q;
|
||||
assign op_b_zero_d = (load_en) ? op_b_zero : op_b_zero_q;
|
||||
assign res_inv_d = (load_en) ? (~op_b_zero | opcode_i[1]) & opcode_i[0] & (op_a_sign ^ op_b_sign) : res_inv_q;
|
||||
|
||||
// transaction id
|
||||
assign id_d = (load_en) ? id_i : id_q;
|
||||
assign id_o = id_q;
|
||||
|
||||
assign op_a_d = (a_reg_en) ? add_out : op_a_q;
|
||||
assign op_b_d = (b_reg_en) ? b_mux : op_b_q;
|
||||
assign res_d = (load_en) ? '0 :
|
||||
(res_reg_en) ? {res_q[$high(res_q)-1:0], ab_comp} : res_q;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
|
||||
if (~rst_ni) begin
|
||||
state_q <= IDLE;
|
||||
op_a_q <= '0;
|
||||
op_b_q <= '0;
|
||||
res_q <= '0;
|
||||
cnt_q <= '0;
|
||||
id_q <= '0;
|
||||
rem_sel_q <= 1'b0;
|
||||
comp_inv_q <= 1'b0;
|
||||
res_inv_q <= 1'b0;
|
||||
op_b_zero_q <= 1'b0;
|
||||
div_res_zero_q <= 1'b0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
op_a_q <= op_a_d;
|
||||
op_b_q <= op_b_d;
|
||||
res_q <= res_d;
|
||||
cnt_q <= cnt_d;
|
||||
id_q <= id_d;
|
||||
rem_sel_q <= rem_sel_d;
|
||||
comp_inv_q <= comp_inv_d;
|
||||
res_inv_q <= res_inv_d;
|
||||
op_b_zero_q <= op_b_zero_d;
|
||||
div_res_zero_q <= div_res_zero_d;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -42,23 +42,10 @@ module store_buffer (
|
|||
input dcache_req_o_t req_port_i,
|
||||
output dcache_req_i_t req_port_o
|
||||
);
|
||||
// depth of store-buffers
|
||||
localparam int unsigned DEPTH_SPEC = 4;
|
||||
|
||||
`ifdef SERPENT_PULP
|
||||
// in this case we can use a small commit queue since we have a write buffer in the dcache
|
||||
// we could in principle do without the commit queue in this case, but the timing degrades if we do that due
|
||||
// to longer paths into the commit stage
|
||||
localparam int unsigned DEPTH_COMMIT = 2;
|
||||
`else
|
||||
// allocate more space for the commit buffer to be on the save side
|
||||
localparam int unsigned DEPTH_COMMIT = 4;
|
||||
`endif
|
||||
|
||||
// the store queue has two parts:
|
||||
// 1. Speculative queue
|
||||
// 2. Commit queue which is non-speculative, e.g.: the store will definitely happen.
|
||||
|
||||
struct packed {
|
||||
logic [63:0] address;
|
||||
logic [63:0] data;
|
||||
|
@ -280,7 +267,7 @@ module store_buffer (
|
|||
else $error ("[Speculative Queue] You are committing although there are no stores to commit");
|
||||
|
||||
commit_buffer_overflow: assert property (
|
||||
@(posedge clk_i) rst_ni && (commit_status_cnt_q == DEPTH_SPEC) |-> !commit_i)
|
||||
@(posedge clk_i) rst_ni && (commit_status_cnt_q == DEPTH_COMMIT) |-> !commit_i)
|
||||
else $error("[Commit Queue] You are trying to commit a store although the buffer is full");
|
||||
`endif
|
||||
//pragma translate_on
|
||||
|
|
27
tb/tb_serdiv/Makefile
Executable file
27
tb/tb_serdiv/Makefile
Executable file
|
@ -0,0 +1,27 @@
|
|||
library ?= work
|
||||
toplevel ?= tb
|
||||
src-list := tb.list
|
||||
inc-path := $(shell pwd)/hdl/
|
||||
src := $(shell xargs printf '\n%s' < $(src-list) | cut -b 1-)
|
||||
compile_flag += +cover+i_dut -incr -64 -nologo
|
||||
sim_opts += -64 -coverage -classdebug -voptargs="+acc"
|
||||
questa_version ?= ${QUESTASIM_VERSION}
|
||||
|
||||
|
||||
build: clean
|
||||
vlib${questa_version} $(library)
|
||||
vlog${questa_version} -work $(library) -pedanticerrors $(src) $(compile_flag) +incdir+$(inc-path)
|
||||
touch $(library)/.build
|
||||
|
||||
sim: build
|
||||
vsim${questa_version} -lib $(library) $(toplevel) -do "do wave.do" $(sim_opts)
|
||||
|
||||
simc: build
|
||||
vsim${questa_version} -lib $(library) $(toplevel) -c -do "run -all; exit" $(sim_opts)
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf $(library)
|
||||
|
||||
.PHONY: clean simc sim build
|
||||
|
314
tb/tb_serdiv/hdl/tb.sv
Normal file
314
tb/tb_serdiv/hdl/tb.sv
Normal file
|
@ -0,0 +1,314 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
|
||||
// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich
|
||||
//
|
||||
// Date: 18.10.2018
|
||||
// Description: testbench for serial 64bit divider
|
||||
//
|
||||
|
||||
`include "tb.svh"
|
||||
|
||||
import ariane_pkg::*;
|
||||
import tb_pkg::*;
|
||||
|
||||
// tb package
|
||||
module tb;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// config
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// leave this
|
||||
timeunit 1ps;
|
||||
timeprecision 1ps;
|
||||
|
||||
parameter VERBOSE = 1;
|
||||
parameter WIDTH = 64;
|
||||
parameter logic [WIDTH-1:0] MAX_NUM64 = '1;
|
||||
parameter logic [WIDTH-2:0] MAX_NUM63 = '1;
|
||||
parameter logic signed [WIDTH-1:0] MIN_NUM = {1'b1,{WIDTH-1{1'b0}}};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MUT signal declarations
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
logic signed [WIDTH:0] op_a, op_b;
|
||||
logic signed [WIDTH:0] op_a_tmp, op_b_tmp;
|
||||
|
||||
logic flush_i;
|
||||
logic [TRANS_ID_BITS-1:0] id_i;
|
||||
logic [TRANS_ID_BITS-1:0] id_o;
|
||||
|
||||
logic [WIDTH-1:0] op_a_i;
|
||||
logic [WIDTH-1:0] op_b_i;
|
||||
|
||||
logic [1:0] opcode_i;
|
||||
logic [1:0] opcode_tmp;
|
||||
|
||||
logic in_rdy_o;
|
||||
logic in_vld_i;
|
||||
logic out_rdy_i;
|
||||
logic out_vld_o;
|
||||
logic [WIDTH-1:0] res_o;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TB signal declarations
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
logic clk_i, rst_ni;
|
||||
logic stim_start, stim_end, end_of_sim;
|
||||
longint num_stim;
|
||||
logic acq_trig;
|
||||
string test_name;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Clock Process
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
always @*
|
||||
begin
|
||||
do begin
|
||||
clk_i = 1; #(CLK_HI);
|
||||
clk_i = 0; #(CLK_LO);
|
||||
end while (end_of_sim == 1'b0);
|
||||
// generate one extra cycle to allow response acquisition to complete
|
||||
clk_i = 1; #(CLK_HI);
|
||||
clk_i = 0; #(CLK_LO);
|
||||
end
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MUT
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
assign OpBIsZero_SI = ~(|op_b_i);
|
||||
serdiv #(.WIDTH(WIDTH)) i_dut (.*);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// application process
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
initial begin : p_stim
|
||||
longint signed k;
|
||||
bit randBit;
|
||||
|
||||
stim_start = 0;
|
||||
stim_end = 0;
|
||||
num_stim = 0;
|
||||
test_name = "";
|
||||
acq_trig = 0;
|
||||
|
||||
rst_ni = 0;
|
||||
|
||||
op_a = 0;
|
||||
op_b = 0;
|
||||
|
||||
op_a_i = 0;
|
||||
op_b_i = 0;
|
||||
opcode_i = 0;
|
||||
in_vld_i = 0;
|
||||
flush_i = 0;
|
||||
id_i = 0;
|
||||
|
||||
`APPL_WAIT_CYC(clk_i, 100)
|
||||
|
||||
rst_ni <= 1'b1;
|
||||
|
||||
`APPL_WAIT_CYC(clk_i, 100)
|
||||
|
||||
$display("TB> stimuli application started");
|
||||
stim_start <= 1'b1;
|
||||
`APPL_WAIT_CYC(clk_i, 100)
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// unsigned division test
|
||||
|
||||
`include "tb_udiv.sv"
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// unsigned modulo test
|
||||
|
||||
`include "tb_urem.sv"
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// signed division test
|
||||
|
||||
`include "tb_div.sv"
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// signed modulo test
|
||||
|
||||
`include "tb_rem.sv"
|
||||
|
||||
///////////////////////////////////////////////
|
||||
|
||||
`APPL_WAIT_CYC(clk_i, 400)
|
||||
|
||||
stim_end <= 1;
|
||||
$display("TB> stimuli application ended");
|
||||
|
||||
end
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// acquisition process
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
initial begin : p_acq
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// define vars, init...
|
||||
///////////////////////////////////////////////
|
||||
bit ok;
|
||||
string opStr;
|
||||
progress status;
|
||||
string failingTests, tmpstr;
|
||||
longint acqCnt, res, act;
|
||||
|
||||
status = new("TB");
|
||||
failingTests = "";
|
||||
|
||||
out_rdy_i = 0;
|
||||
end_of_sim = 0;
|
||||
|
||||
`ACQ_WAIT_SIG(clk_i, stim_start)
|
||||
|
||||
$display("TB> response acquisition started");
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// acquisiton and verification
|
||||
///////////////////////////////////////////////
|
||||
repeat(4) begin
|
||||
|
||||
// wait for acquisition trigger
|
||||
do begin
|
||||
`ACQ_WAIT_CYC(clk_i, 1)
|
||||
if (stim_end == 1) begin
|
||||
end_of_sim <= 1;
|
||||
$display("response acquisition ended");
|
||||
$finish();
|
||||
end
|
||||
end while(acq_trig == 1'b0);
|
||||
|
||||
acqCnt = 0;
|
||||
|
||||
$display("");
|
||||
$display("TB> ----------------------------------------------------------------------");
|
||||
$display("TB> %s", test_name);
|
||||
$display("TB> ----------------------------------------------------------------------\n");
|
||||
$display("");
|
||||
|
||||
$display("TB> checking %00d vectors",num_stim);
|
||||
$display("");
|
||||
status.reset(num_stim);
|
||||
|
||||
do begin
|
||||
|
||||
|
||||
|
||||
out_rdy_i = 1'b1;
|
||||
|
||||
`ACQ_WAIT_SIG(clk_i, in_vld_i)
|
||||
|
||||
opcode_tmp = opcode_i;
|
||||
op_a_tmp = op_a;
|
||||
op_b_tmp = op_b;
|
||||
|
||||
//////////////////////////
|
||||
// udiv / udiv
|
||||
if(opcode_i[1] == 1'b0) begin
|
||||
|
||||
res = op_a_tmp/op_b_tmp;
|
||||
|
||||
if((op_b_tmp == 0) && (opcode_i[0] == 0)) begin
|
||||
res = MAX_NUM64;
|
||||
end else if ((op_b_tmp == 0) && (opcode_i[0] == 1'b1)) begin
|
||||
res = -1;
|
||||
end else if ((op_a_tmp == MIN_NUM) && (op_b_tmp == -1) && (opcode_i[0] == 1'b1)) begin
|
||||
res = MIN_NUM;
|
||||
end
|
||||
|
||||
`ACQ_WAIT_SIG(clk_i, out_vld_o)
|
||||
|
||||
// interpret result correctly!
|
||||
if (opcode_tmp[0] == 1'b1)
|
||||
act = $signed(res_o);
|
||||
else
|
||||
act = $unsigned(res_o);
|
||||
|
||||
opStr="/";
|
||||
//////////////////////////
|
||||
// rem / urem
|
||||
end else if(opcode_i[1] == 1'b1) begin
|
||||
|
||||
res = op_a_tmp % op_b_tmp;
|
||||
|
||||
if((op_b_tmp == 0)) begin
|
||||
res = op_a_tmp;
|
||||
end
|
||||
|
||||
`ACQ_WAIT_SIG(clk_i, out_vld_o)
|
||||
|
||||
// interpret result correctly!
|
||||
if (opcode_tmp[0] == 1'b1)
|
||||
act = $signed(res_o);
|
||||
else
|
||||
act = $unsigned(res_o);
|
||||
|
||||
opStr="\%";
|
||||
end
|
||||
|
||||
ok = (res==act);
|
||||
|
||||
if(VERBOSE | !ok) begin
|
||||
if(!ok) tmpstr = $psprintf("vector: %04d> %d %s %d = %d != %d -> error!", acqCnt, op_a_tmp, opStr, op_b_tmp, res, act);
|
||||
else tmpstr = $psprintf("vector: %04d> %d %s %d = %d == %d " , acqCnt, op_a_tmp, opStr, op_b_tmp, res, act);
|
||||
$display("TB> %s", tmpstr);
|
||||
end
|
||||
|
||||
if(!ok) begin
|
||||
failingTests = $psprintf("%sTB> %s\n", failingTests, tmpstr);
|
||||
end
|
||||
|
||||
status.addRes(!ok);
|
||||
status.print();
|
||||
|
||||
// status
|
||||
acqCnt++;
|
||||
end
|
||||
while (acqCnt < num_stim);
|
||||
end
|
||||
///////////////////////////////////////////////
|
||||
|
||||
status.printToFile("summary.rep", 1);
|
||||
|
||||
if(status.totErrCnt == 0) begin
|
||||
$display("TB> ----------------------------------------------------------------------");
|
||||
$display("TB> PASSED %0d VECTORS", status.totAcqCnt);
|
||||
$display("TB> ----------------------------------------------------------------------\n");
|
||||
end else begin
|
||||
$display("TB> ----------------------------------------------------------------------\n");
|
||||
$display("TB> FAILED %0d OF %0d VECTORS\n" , status.totErrCnt, status.totAcqCnt);
|
||||
$display("TB> failing tests:");
|
||||
$display("TB", failingTests);
|
||||
$display("TB> ----------------------------------------------------------------------\n");
|
||||
end
|
||||
|
||||
end_of_sim <= 1;
|
||||
$finish();
|
||||
///////////////////////////////////////////////
|
||||
end
|
||||
|
||||
endmodule
|
66
tb/tb_serdiv/hdl/tb.svh
Normal file
66
tb/tb_serdiv/hdl/tb.svh
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2018 ETH Zurich, University of Bologna
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code is under development and not yet released to the public.
|
||||
// Until it is released, the code is under the copyright of ETH Zurich and
|
||||
// the University of Bologna, and may contain confidential and/or unpublished
|
||||
// work. Any reuse/redistribution is strictly forbidden without written
|
||||
// permission from ETH Zurich.
|
||||
//
|
||||
// Bug fixes and contributions will eventually be released under the
|
||||
// SolderPad open hardware license in the context of the PULP platform
|
||||
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
|
||||
// University of Bologna.
|
||||
//
|
||||
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
|
||||
// Date: 15.08.2018
|
||||
// Description:
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// use to ensure proper ATI timing
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`define APPL_ACQ_WAIT #(ACQ_DEL-APPL_DEL);
|
||||
|
||||
`define WAIT_CYC(CLK, N) \
|
||||
repeat(N) @(posedge(CLK));
|
||||
|
||||
`define WAIT(CLK, SIG) \
|
||||
do begin \
|
||||
@(posedge(CLK)); \
|
||||
end while(SIG == 1'b0);
|
||||
|
||||
`define WAIT_SIG(CLK,SIG) \
|
||||
do begin \
|
||||
@(posedge(CLK)); \
|
||||
end while(SIG == 1'b0);
|
||||
|
||||
`define APPL_WAIT_COMB_SIG(CLK,SIG) \
|
||||
`APPL_ACQ_WAIT \
|
||||
while(SIG == 1'b0) begin \
|
||||
@(posedge(CLK)); \
|
||||
#(ACQ_DEL); \
|
||||
end
|
||||
|
||||
`define APPL_WAIT_SIG(CLK,SIG) \
|
||||
do begin \
|
||||
@(posedge(CLK)); \
|
||||
#(APPL_DEL); \
|
||||
end while(SIG == 1'b0);
|
||||
|
||||
`define ACQ_WAIT_SIG(CLK,SIG) \
|
||||
do begin \
|
||||
@(posedge(CLK)); \
|
||||
#(ACQ_DEL); \
|
||||
end while(SIG == 1'b0);
|
||||
|
||||
|
||||
`define APPL_WAIT_CYC(CLK, N) \
|
||||
repeat(N) @(posedge(CLK)); \
|
||||
#(tb_pkg::APPL_DEL);
|
||||
|
||||
`define ACQ_WAIT_CYC(CLK, N) \
|
||||
repeat(N) @(posedge(CLK)); \
|
||||
#(tb_pkg::ACQ_DEL);
|
||||
|
117
tb/tb_serdiv/hdl/tb_div.sv
Normal file
117
tb/tb_serdiv/hdl/tb_div.sv
Normal file
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
|
||||
// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich
|
||||
//
|
||||
// Date: 18.10.2018
|
||||
// Description: testbench for serial 64bit divider
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// unsigned division test
|
||||
|
||||
// init
|
||||
num_stim = 5+1000;
|
||||
|
||||
test_name = "div test";
|
||||
|
||||
acq_trig <= 1;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
acq_trig <= 0;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
opcode_i = 1;
|
||||
|
||||
op_a = 100;
|
||||
op_b = -10;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = -100;
|
||||
op_b = -10;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = -100;
|
||||
op_b = 0;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
|
||||
op_a = MIN_NUM;
|
||||
op_b = 1;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
|
||||
op_a = MIN_NUM;
|
||||
op_b = -1;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
////////////////////
|
||||
// a couple of random stimuli
|
||||
|
||||
for (k = 0; k < 1000; k++) begin
|
||||
|
||||
|
||||
void'(randomize(op_a_i));
|
||||
void'(randomize(op_b_i));
|
||||
op_a = $signed(op_a_i);
|
||||
op_b = $signed(op_b_i);
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
end
|
||||
|
||||
`APPL_WAIT_CYC(clk_i, 400)
|
||||
|
||||
///////////////////////////////////////////////
|
148
tb/tb_serdiv/hdl/tb_pkg.sv
Normal file
148
tb/tb_serdiv/hdl/tb_pkg.sv
Normal file
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
|
||||
// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich
|
||||
//
|
||||
// Date: 18.10.2018
|
||||
// Description: testbench package with some helper functions.
|
||||
//
|
||||
|
||||
package tb_pkg;
|
||||
|
||||
// // for abs(double) function
|
||||
// import mti_cstdlib::*;
|
||||
|
||||
// for timestamps
|
||||
import "DPI-C" \time = function int _time (inout int tloc[4]);
|
||||
import "DPI-C" function string ctime(inout int tloc[4]);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// parameters
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// creates a 10ns ATI timing cycle
|
||||
time CLK_HI = 5ns; // set clock high time
|
||||
time CLK_LO = 5ns; // set clock low time
|
||||
time CLK_PERIOD = CLK_HI+CLK_LO;
|
||||
time APPL_DEL = 2ns; // set stimuli application delay
|
||||
time ACQ_DEL = 8ns; // set response aquisition delay
|
||||
|
||||
parameter ERROR_CNT_STOP_LEVEL = 1; // use 1 for debugging. 0 runs the complete simulation...
|
||||
|
||||
// tb_readport sequences
|
||||
typedef enum logic [2:0] { RANDOM_SEQ, LINEAR_SEQ, BURST_SEQ, IDLE_SEQ, WRAP_SEQ } seq_t;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// progress
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class progress;
|
||||
real newState, oldState;
|
||||
longint numResp, acqCnt, errCnt, totAcqCnt, totErrCnt;
|
||||
string name;
|
||||
|
||||
function new(string name);
|
||||
begin
|
||||
this.name = name;
|
||||
this.acqCnt = 0;
|
||||
this.errCnt = 0;
|
||||
this.newState = 0.0;
|
||||
this.oldState = 0.0;
|
||||
this.numResp = 1;
|
||||
this.totAcqCnt = 0;
|
||||
this.totErrCnt = 0;
|
||||
|
||||
end
|
||||
endfunction : new
|
||||
|
||||
function void reset(longint numResp_);
|
||||
begin
|
||||
this.acqCnt = 0;
|
||||
this.errCnt = 0;
|
||||
this.newState = 0.0;
|
||||
this.oldState = 0.0;
|
||||
this.numResp = numResp_;
|
||||
end
|
||||
endfunction : reset
|
||||
|
||||
function void addRes(int isError);
|
||||
begin
|
||||
this.acqCnt++;
|
||||
this.totAcqCnt++;
|
||||
this.errCnt += isError;
|
||||
this.totErrCnt += isError;
|
||||
|
||||
if(ERROR_CNT_STOP_LEVEL <= this.errCnt && ERROR_CNT_STOP_LEVEL > 0) begin
|
||||
$error("%s> simulation stopped (ERROR_CNT_STOP_LEVEL = %d reached).", this.name, ERROR_CNT_STOP_LEVEL);
|
||||
$stop();
|
||||
end
|
||||
end
|
||||
endfunction : addRes
|
||||
|
||||
function void print();
|
||||
begin
|
||||
this.newState = $itor(this.acqCnt) / $itor(this.numResp);
|
||||
if(this.newState - this.oldState >= 0.01) begin
|
||||
$display("%s> validated %03d%% -- %01d failed (%03.3f%%) ",
|
||||
this.name,
|
||||
$rtoi(this.newState*100.0),
|
||||
this.errCnt,
|
||||
$itor(this.errCnt) / $itor(this.acqCnt) * 100.0);
|
||||
// $fflush();
|
||||
this.oldState = this.newState;
|
||||
end
|
||||
end
|
||||
endfunction : print
|
||||
|
||||
function void printToFile(string file, bit summary = 0);
|
||||
begin
|
||||
int fptr;
|
||||
|
||||
// sanitize string
|
||||
for(fptr=0; fptr<$size(file);fptr++) begin
|
||||
if(file[fptr] == " " || file[fptr] == "/" || file[fptr] == "\\") begin
|
||||
file[fptr] = "_";
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
fptr = $fopen(file,"w");
|
||||
if(summary) begin
|
||||
$fdisplay(fptr, "Simulation Summary of %s", this.name);
|
||||
$fdisplay(fptr, "total: %01d of %01d vectors failed (%03.3f%%) ",
|
||||
this.totErrCnt,
|
||||
this.totAcqCnt,
|
||||
$itor(this.totErrCnt) / ($itor(this.totAcqCnt) * 100.0 + 0.000000001));
|
||||
if(this.totErrCnt == 0) begin
|
||||
$fdisplay(fptr, "CI: PASSED");
|
||||
end else begin
|
||||
$fdisplay(fptr, "CI: FAILED");
|
||||
end
|
||||
end else begin
|
||||
$fdisplay(fptr, "test name: %s", file);
|
||||
$fdisplay(fptr, "this test: %01d of %01d vectors failed (%03.3f%%) ",
|
||||
this.errCnt,
|
||||
this.acqCnt,
|
||||
$itor(this.errCnt) / $itor(this.acqCnt) * 100.0);
|
||||
|
||||
$fdisplay(fptr, "total so far: %01d of %01d vectors failed (%03.3f%%) ",
|
||||
this.totErrCnt,
|
||||
this.totAcqCnt,
|
||||
$itor(this.totErrCnt) / $itor(this.totAcqCnt) * 100.0);
|
||||
end
|
||||
$fclose(fptr);
|
||||
end
|
||||
endfunction : printToFile
|
||||
|
||||
endclass : progress
|
||||
|
||||
endpackage : tb_pkg
|
||||
|
116
tb/tb_serdiv/hdl/tb_rem.sv
Normal file
116
tb/tb_serdiv/hdl/tb_rem.sv
Normal file
|
@ -0,0 +1,116 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
|
||||
// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich
|
||||
//
|
||||
// Date: 18.10.2018
|
||||
// Description: testbench for serial 64bit divider
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// unsigned division test
|
||||
|
||||
// init
|
||||
num_stim = 5+1000;
|
||||
|
||||
test_name = "rem test";
|
||||
|
||||
acq_trig <= 1;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
acq_trig <= 0;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
opcode_i = 3;
|
||||
|
||||
op_a = 100;
|
||||
op_b = -10;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
in_vld_i = 0;
|
||||
|
||||
op_a = -100;
|
||||
op_b = -10;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = -100;
|
||||
op_b = 0;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = MIN_NUM;
|
||||
op_b = 1;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = MIN_NUM;
|
||||
op_b = -1;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
////////////////////
|
||||
// a couple of random stimuli
|
||||
|
||||
for (k = 0; k < 1000; k++) begin
|
||||
|
||||
void'(randomize(op_a_i));
|
||||
void'(randomize(op_b_i));
|
||||
op_a = $signed(op_a_i);
|
||||
op_b = $signed(op_b_i);
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
end
|
||||
|
||||
`APPL_WAIT_CYC(clk_i, 400)
|
||||
|
||||
///////////////////////////////////////////////
|
127
tb/tb_serdiv/hdl/tb_udiv.sv
Normal file
127
tb/tb_serdiv/hdl/tb_udiv.sv
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
|
||||
// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich
|
||||
//
|
||||
// Date: 18.10.2018
|
||||
// Description: testbench for serial 64bit divider
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// unsigned division test
|
||||
|
||||
// init
|
||||
num_stim = 6+1000;
|
||||
|
||||
test_name = "udiv test";
|
||||
|
||||
acq_trig <= 1;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
acq_trig <= 0;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
opcode_i = 0;
|
||||
|
||||
op_a = 100;
|
||||
op_b = 2;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = MAX_NUM64;
|
||||
op_b = 1;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 1;
|
||||
op_b = MAX_NUM64;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 0;
|
||||
op_b = 5456;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 875;
|
||||
op_b = 0;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 0;
|
||||
op_b = 0;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
|
||||
////////////////////
|
||||
// a couple of random stimuli
|
||||
|
||||
for (k = 0; k < 1000; k++) begin
|
||||
|
||||
void'(randomize(op_a_i));
|
||||
void'(randomize(op_b_i));
|
||||
op_a = op_a_i;
|
||||
op_b = op_b_i;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
end
|
||||
|
||||
`APPL_WAIT_CYC(clk_i, 400)
|
||||
|
||||
///////////////////////////////////////////////
|
127
tb/tb_serdiv/hdl/tb_urem.sv
Normal file
127
tb/tb_serdiv/hdl/tb_urem.sv
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Michael Schaffner (schaffner@iis.ee.ethz.ch), ETH Zurich
|
||||
// Andreas Traber (traber@iis.ee.ethz.ch), ETH Zurich
|
||||
//
|
||||
// Date: 18.10.2018
|
||||
// Description: testbench for serial 64bit divider
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// unsigned division test
|
||||
|
||||
// init
|
||||
num_stim = 6+1000;
|
||||
|
||||
test_name = "urem test";
|
||||
|
||||
acq_trig <= 1;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
acq_trig <= 0;
|
||||
`APPL_WAIT_CYC(clk_i, 2)
|
||||
|
||||
///////////////////////////////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
opcode_i = 2;
|
||||
|
||||
op_a = 100;
|
||||
op_b = 2;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = MAX_NUM64;
|
||||
op_b = 1;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 1;
|
||||
op_b = MAX_NUM64;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 0;
|
||||
op_b = 5456;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 875;
|
||||
op_b = 0;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
////////////////////
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
op_a = 0;
|
||||
op_b = 0;
|
||||
|
||||
op_a_i = op_a;
|
||||
op_b_i = op_b;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
|
||||
////////////////////
|
||||
// a couple of random stimuli
|
||||
|
||||
for (k = 0; k < 1000; k++) begin
|
||||
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
void'(randomize(op_a_i));
|
||||
void'(randomize(op_b_i));
|
||||
op_a = op_a_i;
|
||||
op_b = op_b_i;
|
||||
|
||||
in_vld_i = 1;
|
||||
`APPL_WAIT_CYC(clk_i, 1)
|
||||
in_vld_i = 0;
|
||||
`APPL_WAIT_SIG(clk_i, in_rdy_o)
|
||||
|
||||
end
|
||||
|
||||
`APPL_WAIT_CYC(clk_i, 400)
|
||||
///////////////////////////////////////////////
|
7
tb/tb_serdiv/tb.list
Normal file
7
tb/tb_serdiv/tb.list
Normal file
|
@ -0,0 +1,7 @@
|
|||
../../include/riscv_pkg.sv
|
||||
../../src/debug/dm_pkg.sv
|
||||
../../include/ariane_pkg.sv
|
||||
../../src/common_cells/src/lzc.sv
|
||||
../../src/serdiv.sv
|
||||
hdl/tb_pkg.sv
|
||||
hdl/tb.sv
|
Loading…
Add table
Add a link
Reference in a new issue