Merge branch 'initial-dev' of iis-git.ee.ethz.ch:floce/ariane into initial-dev

This commit is contained in:
Florian Zaruba 2017-05-16 18:41:32 +02:00
commit a0f5d02c7d
35 changed files with 2382 additions and 1670 deletions

View file

@ -7,8 +7,11 @@ library = work
# Top level module to compile
top_level = core_tb
test_top_level = core_tb
# utility modules
util = $(wildcard src/util/*.sv)
# test targets
tests = alu scoreboard fifo mem_arbiter store_queue lsu core
tests = alu scoreboard fifo mem_arbiter store_queue lsu core fetch_fifo
# UVM agents
agents = include/ariane_pkg.svh $(wildcard tb/agents/*/*.sv)
# path to interfaces
@ -18,17 +21,17 @@ envs = $(wildcard tb/env/*/*.sv)
# UVM Sequences
sequences = $(wildcard tb/sequences/*/*.sv)
# Test packages
test_pkg = $(wildcard tb/test/*/*sequence_pkg.sv) $(wildcard tb/test/*/*lib_pkg.sv)
test_pkg = $(wildcard tb/test/*/*sequence_pkg.sv) $(wildcard tb/test/*/*_pkg.sv)
# this list contains the standalone components
src = $(wildcard src/util/*.sv) $(wildcard src/*.sv)
src = $(wildcard src/*.sv)
# look for testbenches
tbs = $(wildcard tb/*_tb.sv)
tbs = $(wildcard tb/*_tb.sv)
# Search here for include files (e.g.: non-standalone components)
incdir = ./includes
# Test case to run
test_case = alu_test
test_case = core_test
# QuestaSim Version
questa_version = -10.5c
compile_flag = +cover=bcfst+/dut
@ -46,6 +49,7 @@ $(library):
# Build the TB and module using QuestaSim
build: $(library) build-agents build-interfaces
# Suppress message that always_latch may not be checked thoroughly by QuestaSim.
vlog${questa_version} ${compile_flag} -incr ${util} ${list_incdir} -suppress 2583
# Compile agents, interfaces and environments
vlog${questa_version} ${compile_flag} -incr ${envs} ${sequences} ${test_pkg} ${list_incdir} -suppress 2583
# Compile source files
@ -62,13 +66,13 @@ build-interfaces: ${interfaces}
# Run the specified test case
sim:
# vsim${questa_version} ${top_level}_optimized -c -do "run -a"
vsim${questa_version} ${top_level}_optimized +UVM_TESTNAME=${test_case}
vsim${questa_version} ${top_level}_optimized +UVM_TESTNAME=${test_case} -coverage -classdebug -do "do tb/wave/wave_core.do"
$(tests):
# Optimize top level
vopt${questa_version} ${compile_flag} $@_tb -o $@_tb_optimized +acc -check_synthesis
# vsim${questa_version} $@_tb_optimized
# vsim${questa_version} -c +UVM_TESTNAME=$@_test -coverage -classdebug $@_tb_optimized
# vsim${questa_version} +UVM_TESTNAME=$@_test -coverage -classdebug $@_tb_optimized
vsim${questa_version} +UVM_TESTNAME=$@_test +uvm_set_action="*,_ALL_,UVM_ERROR,UVM_DISPLAY|UVM_STOP" -c -coverage -classdebug -do "coverage save -onexit $@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]" $@_tb_optimized
build-moore:

View file

@ -34,20 +34,36 @@ package ariane_pkg;
typedef struct packed {
logic [63:0] cause; // cause of exception
logic [63:0] tval; // additional information of causing exception (e.g.: instruction causing it),
// address of ld/st fault
// address of LD/ST fault
logic valid;
} exception;
// miss-predict
// branch-predict
// this is the struct we get back from ex stage and we will use it to update
// all the necessary data structures
typedef struct packed {
logic [63:0] pc;
logic [63:0] target_address;
logic is_taken;
logic valid; // is miss-predict
} mispredict;
logic [63:0] pc; // pc of predict or mis-predict
logic [63:0] target_address; // target address at which to jump, or not
logic is_mispredict; // set if this was a mis-predict
logic is_taken; // branch is taken
logic is_lower_16; // branch instruction is compressed and resides
// in the lower 16 bit of the word
logic valid; // prediction with all its values is valid
} branchpredict;
// branchpredict scoreboard entry
// this is the struct which we will inject into the pipeline to guide the various
// units towards the correct branch decision and resolve
typedef struct packed {
logic [63:0] predict_address; // target address at which to jump, or not
logic predict_taken; // branch is taken
logic is_lower_16; // branch instruction is compressed and resides
// in the lower 16 bit of the word
logic valid; // this is a valid hint
} branchpredict_sbe;
typedef enum logic[3:0] {
NONE, LSU, ALU, MULT, CSR
NONE, LSU, ALU, CTRL_FLOW, MULT, CSR
} fu_t;
localparam EXC_OFF_RST = 8'h80;
@ -55,21 +71,34 @@ package ariane_pkg;
// ---------------
// EX Stage
// ---------------
typedef enum logic [7:0] { // basic ALU op
typedef enum logic [5:0] { // basic ALU op
ADD, SUB, ADDW, SUBW,
// logic operations
XORL, ORL, ANDL,
// shifts
SRA, SRL, SLL, SRLW, SLLW, SRAW,
// comparisons
LTS, LTU, LES, LEU, GTS, GTU, GES, GEU, EQ, NE,
LTS, LTU, GES, GEU, EQ, NE,
// jumps
JAL, JALR,
// set lower than operations
SLTS, SLTU, SLETS, SLETU,
SLTS, SLTU,
// CSR functions
MRET, SRET, URET, ECALL, CSR_WRITE, CSR_READ, CSR_SET, CSR_CLEAR,
// LSU functions
LD, SD, LW, LWU, SW, LH, LHU, SH, LB, SB, LBU
} fu_op;
// ---------------
// ID/EX/WB Stage
// ---------------
// store the decompressed instruction
typedef struct packed {
branchpredict_sbe branch_predict;
logic [63:0] address;
logic [31:0] instruction;
logic is_compressed;
logic is_illegal;
} fetch_entry;
// ---------------
// ID/EX/WB Stage
@ -89,6 +118,7 @@ package ariane_pkg;
logic use_zimm; // use zimm as operand a
logic use_pc; // set if we need to use the PC as operand a, PC from exception
exception ex; // exception has occurred
branchpredict_sbe bp; // branch predict scoreboard data structure
logic is_compressed; // signals a compressed instructions, we need this information at the commit stage if
// we want jump accordingly e.g.: +4, +2
} scoreboard_entry;
@ -103,7 +133,7 @@ package ariane_pkg;
logic [14:12] funct3;
logic [11:7] rd;
logic [6:0] opcode;
} rtype;
} rtype_t;
typedef struct packed {
logic [31:20] imm;
@ -111,7 +141,7 @@ package ariane_pkg;
logic [14:12] funct3;
logic [11:7] rd;
logic [6:0] opcode;
} itype;
} itype_t;
typedef struct packed {
logic [31:25] imm1;
@ -120,27 +150,21 @@ package ariane_pkg;
logic [14:12] funct3;
logic [11:7] imm0;
logic [6:0] opcode;
} stype;
} stype_t;
typedef struct packed {
logic [31:12] funct3;
logic [11:7] rd;
logic [6:0] opcode;
} utype;
} utype_t;
// for some reason verilator complains about this union
// since I am not using it for simulation anyway and linting only
// it is not too bad to deactivate it, but a future me (or you)
// should look into that more thoroughly
`ifndef verilator
typedef union packed {
logic [31:0] instr;
rtype rtype;
itype itype;
stype stype;
utype utype;
logic [31:0] instr;
rtype_t rtype;
itype_t itype;
stype_t stype;
utype_t utype;
} instruction;
`endif
// --------------------
// Opcodes
@ -236,10 +260,9 @@ package ariane_pkg;
logic [7:0] address;
} csr_addr_t;
// `ifndef VERILATOR
typedef union packed {
csr_reg_t address;
csr_addr_t csr_decode;
} csr_t;
// `endif
endpackage

View file

@ -16,225 +16,166 @@ import ariane_pkg::*;
module alu
(
input fu_op operator_i,
input logic [63:0] operand_a_i,
input logic [63:0] operand_b_i,
output logic [63:0] adder_result_o,
output logic [65:0] adder_result_ext_o,
output logic [63:0] result_o,
output logic comparison_result_o,
output logic is_equal_result_o
input logic [TRANS_ID_BITS-1:0] trans_id_i,
input logic alu_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 alu_valid_o,
output logic alu_ready_o,
output logic [TRANS_ID_BITS-1:0] alu_trans_id_o
);
// ALU is a single cycle instructions, hence it is always ready
logic [63:0] operand_a_rev;
logic [31:0] operand_a_rev32;
logic [64:0] operand_b_neg;
assign alu_ready_o = 1'b1;
assign alu_valid_o = alu_valid_i;
assign alu_trans_id_o = trans_id_i;
// 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];
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;
// 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];
for (k = 0; k < 32; k++)
assign operand_a_rev32[k] = operand_a_i[31-k];
endgenerate
for (k = 0; k < 32; k++)
assign operand_a_rev32[k] = operand_a_i[31-k];
endgenerate
// ------
// Adder
// ------
logic adder_op_b_negate;
logic [64:0] adder_in_a, adder_in_b;
logic [63:0] adder_result;
// ------
// Adder
// ------
logic adder_op_b_negate;
logic [64:0] adder_in_a, adder_in_b;
logic [63:0] adder_result;
always_comb
begin
adder_op_b_negate = 1'b0;
always_comb begin
adder_op_b_negate = 1'b0;
unique case (operator_i)
// ADDER OPS
SUB, SUBW,
// COMPARATOR OPs
EQ, NE,
GTU, GEU,
LTU, LEU,
GTS, GES,
LTS, LES,
SLTS, SLTU,
SLETS, SLETU: adder_op_b_negate = 1'b1;
unique case (operator_i)
// ADDER OPS
SUB, SUBW: adder_op_b_negate = 1'b1;
default: ;
endcase
end
default: ;
endcase
end
// prepare operand a
assign adder_in_a = {operand_a_i, 1'b1};
// prepare operand a
assign adder_in_a = {operand_a_i, 1'b1};
// prepare operand b
assign operand_b_neg = {operand_b_i, 1'b0} ^ {65{adder_op_b_negate}};
assign adder_in_b = operand_b_neg ;
// prepare operand b
assign operand_b_neg = {operand_b_i, 1'b0} ^ {65{adder_op_b_negate}};
assign adder_in_b = operand_b_neg ;
// actual adder
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
// actual adder
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
assign adder_result = adder_result_ext_o[64:1];
assign adder_result = adder_result_ext_o[64:1];
// ---------
// Shifts
// ---------
assign adder_result_o = adder_result;
// TODO: this can probably optimized significantly
logic shift_left; // should we shift left
logic shift_arithmetic;
// ---------
// Shifts
// ---------
logic [63:0] shift_amt; // amount of shift, to the right
logic [63:0] shift_op_a; // input of the shifter
logic [31:0] shift_op_a32; // input to the 32 bit shift operation
// TODO: this can probably optimized significantly
logic shift_left; // should we shift left
logic shift_arithmetic;
logic [63:0] shift_result;
logic [31:0] shift_result32;
logic [63:0] shift_amt; // amount of shift, to the right
logic [63:0] shift_op_a; // input of the shifter
logic [31:0] shift_op_a32; // input to the 32 bit shift operation
logic [64:0] shift_right_result;
logic [32:0] shift_right_result32;
logic [63:0] shift_result;
logic [31:0] shift_result32;
logic [63:0] shift_left_result;
logic [31:0] shift_left_result32;
logic [64:0] shift_right_result;
logic [32:0] shift_right_result32;
assign shift_amt = operand_b_i;
logic [63:0] shift_left_result;
logic [31:0] shift_left_result32;
assign shift_left = (operator_i == SLL) | (operator_i == SLLW);
assign shift_amt = operand_b_i;
assign shift_arithmetic = (operator_i == SRA) | (operator_i == SRAW);
assign shift_left = (operator_i == SLL) | (operator_i == SLLW);
// right shifts, we let the synthesizer optimize this
logic [64:0] shift_op_a_64;
logic [32:0] shift_op_a_32;
assign shift_arithmetic = (operator_i == SRA) | (operator_i == SRAW);
// 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];
// right shifts, we let the synthesizer optimize this
logic [64:0] shift_op_a_64;
logic [32:0] shift_op_a_32;
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};
// 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_right_result = $signed(shift_op_a_64) >>> shift_amt[5: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};
assign shift_right_result32 = $signed(shift_op_a_32) >>> shift_amt[4:0];
// bit reverse the shift_right_result for left shifts
genvar j;
generate
for(j = 0; j < 64; j++)
assign shift_left_result[j] = shift_right_result[63-j];
assign shift_right_result = $signed(shift_op_a_64) >>> shift_amt[5:0];
for(j = 0; j < 32; j++)
assign shift_left_result32[j] = shift_right_result32[31-j];
assign shift_right_result32 = $signed(shift_op_a_32) >>> shift_amt[4:0];
// bit reverse the shift_right_result for left shifts
genvar j;
generate
for(j = 0; j < 64; j++)
assign shift_left_result[j] = shift_right_result[63-j];
endgenerate
for(j = 0; j < 32; j++)
assign shift_left_result32[j] = shift_right_result32[31-j];
assign shift_result = shift_left ? shift_left_result : shift_right_result[63:0];
assign shift_result32 = shift_left ? shift_left_result32 : shift_right_result32[31:0];
endgenerate
// ------------
// Comparisons
// ------------
logic is_greater_equal; // handles both signed and unsigned forms
logic cmp_signed;
assign shift_result = shift_left ? shift_left_result : shift_right_result[63:0];
assign shift_result32 = shift_left ? shift_left_result32 : shift_right_result32[31:0];
always_comb begin
cmp_signed = 1'b0;
// ------------
// Comparisons
// ------------
logic is_equal;
logic is_greater_equal; // handles both signed and unsigned forms
logic cmp_signed;
if (operator_i == SLTS)
cmp_signed = 1'b1;
// Is greater equal
if ((operand_a_i[63] ^ operand_b_i[63]) == 0)
is_greater_equal = (adder_result[63] == 0);
else
is_greater_equal = operand_a_i[63] ^ (cmp_signed);
end
always_comb
begin
cmp_signed = 1'b0;
// -----------
// Result MUX
// -----------
always_comb begin
result_o = '0;
unique case (operator_i)
GTS,
GES,
LTS,
LES,
SLTS,
SLETS: begin
cmp_signed = 1'b1;
end
unique case (operator_i)
// 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;
default:;
endcase
end
// Adder Operations
ADD, SUB: result_o = adder_result;
// Add word: Ignore the upper bits and sign extend to 64 bit
ADDW, SUBW: result_o = {{32{adder_result[31]}}, adder_result[31:0]};
// Shift Operations
SLL,
SRL, SRA: result_o = shift_result;
// Shifts 32 bit
SLLW,
SRLW, SRAW: result_o = {{32{shift_result32[31]}}, shift_result32[31:0]};
assign is_equal = (adder_result == 64'b0);
assign is_equal_result_o = is_equal;
// Comparison Operations
SLTS, SLTU: result_o = {63'b0, (~is_greater_equal)};
// Is greater equal
always_comb
begin
if ((operand_a_i[63] ^ operand_b_i[63]) == 0)
is_greater_equal = (adder_result[63] == 0);
else
is_greater_equal = operand_a_i[63] ^ (cmp_signed);
end
// generate comparison result
logic cmp_result;
always_comb
begin
cmp_result = is_equal;
unique case (operator_i)
EQ: cmp_result = is_equal;
NE: cmp_result = (~is_equal);
GTS, GTU: cmp_result = is_greater_equal && (~is_equal);
GES, GEU: cmp_result = is_greater_equal;
LTS, SLTS,
LTU, SLTU: cmp_result = (~is_greater_equal);
SLETS,
SLETU,
LES, LEU: cmp_result = (~is_greater_equal) || is_equal;
default: ;
endcase
end
assign comparison_result_o = cmp_result;
// -----------
// Result MUX
// -----------
always_comb
begin
result_o = '0;
unique case (operator_i)
// 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;
// Adder Operations
ADD, SUB: result_o = adder_result;
// Add word: Ignore the upper bits and sign extend to 64 bit
ADDW, SUBW: result_o = {{32{adder_result[31]}}, adder_result[31:0]};
// Shift Operations
SLL,
SRL, SRA: result_o = shift_result;
// Shifts 32 bit
SLLW,
SRLW, SRAW: result_o = {{32{shift_result32[31]}}, shift_result32[31:0]};
// Comparison Operations
EQ, NE,
GTU, GEU,
LTU, LEU,
GTS, GES,
LTS, LES,
SLTS, SLTU,
SLETS, SLETU: result_o = {63'b0, cmp_result};
default: ; // default case to suppress unique warning
endcase
end
default: ; // default case to suppress unique warning
endcase
end
endmodule

View file

@ -18,6 +18,9 @@
// University of Bologna.
//
import ariane_pkg::*;
`ifndef SYNTHESIS
import instruction_tracer_pkg::*;
`endif
module ariane
#(
@ -82,18 +85,18 @@ module ariane
logic flush;
logic fetch_enable;
logic halt_if;
logic [63:0] pc_if;
exception ex_commit; // exception from commit stage
branchpredict resolved_branch;
// --------------
// PCGEN <-> IF
// --------------
logic [63:0] pc_pcgen_if;
logic set_pc_pcgen_if;
logic is_branch_pcgen_if;
logic [63:0] fetch_address_pcgen_if;
branchpredict_sbe branch_predict_pcgen_if;
logic if_ready_if_pcgen;
logic fetch_valid_pcgen_if;
// --------------
// PCGEN <-> EX
// --------------
mispredict mispredict_ex_pcgen;
// --------------
// PCGEN <-> CSR
// --------------
@ -102,31 +105,33 @@ module ariane
// --------------
// IF <-> ID
// --------------
logic busy_if_id;
fetch_entry fetch_entry_if_id;
logic ready_id_if;
logic [31:0] fetch_rdata_id_if;
logic instr_valid_if_id;
logic [31:0] instr_rdata_if_id;
logic illegal_c_insn_if_id;
logic is_compressed_if_id;
logic illegal_c_insn_id_if;
logic [63:0] pc_id_if_id;
logic fetch_valid_if_id;
logic decode_ack_id_if;
exception exception_if_id;
// --------------
// ID <-> EX
// --------------
logic [63:0] imm_id_ex;
logic ready_id_ex;
logic [TRANS_ID_BITS-1:0] trans_id_id_ex;
fu_op operator_id_ex;
logic [63:0] operand_a_id_ex;
logic [63:0] operand_b_id_ex;
logic [63:0] operand_c_id_ex;
logic [63:0] pc_id_ex;
logic is_compressed_instr_id_ex;
// 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 alu_exception_ex_id;
// Branches and Jumps
logic branch_valid_id_ex;
branchpredict_sbe 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;
@ -178,7 +183,6 @@ module ariane
logic flag_mxr_csr_ex;
logic [37:0] pd_ppn_csr_ex;
logic [0:0] asid_csr_ex;
logic flush_tlb_csr_ex;
logic [11:0] csr_addr_ex_csr;
// --------------
// COMMIT <-> CSR
@ -193,6 +197,12 @@ module ariane
// EX <-> CSR
// --------------
// * -> CTRL
logic flush_csr_ctrl;
logic flush_unissued_instr_ctrl_id;
logic flush_scoreboard_ctrl_id;
logic flush_ctrl_if;
// TODO: Preliminary signal assignments
logic flush_tlb;
assign flush_tlb = 1'b0;
@ -203,14 +213,15 @@ module ariane
// NPC Generation
// --------------
pcgen pcgen_i (
.fetch_enable_i ( fetch_enable ),
.flush_i ( flush ),
.pc_if_i ( pc_if ),
.mispredict_i ( mispredict_ex_pcgen ),
.pc_if_o ( pc_pcgen_if ),
.set_pc_o ( set_pc_pcgen_if ),
.is_branch_o ( is_branch_o ),
.if_ready_i ( ~if_ready_if_pcgen ),
.resolved_branch_i ( resolved_branch ),
.fetch_address_o ( fetch_address_pcgen_if ),
.fetch_valid_o ( fetch_valid_pcgen_if ),
.branch_predict_o ( branch_predict_pcgen_if ),
.boot_addr_i ( boot_addr_i ),
.epc_i ( epc_i ),
.epc_i ( epc_commit_pcgen ),
.trap_vector_base_i ( trap_vector_base_commit_pcgen ),
.ex_i ( ex_commit ),
.*
@ -219,26 +230,22 @@ module ariane
// IF
// ---------
if_stage if_stage_i (
.flush_i ( flush ),
.req_i ( fetch_enable ),
.if_busy_o ( ), // ?
.id_ready_i ( ready_id_if ),
.halt_if_i ( halt_if ),
.set_pc_i ( set_pc_pcgen_if ),
.fetch_addr_i ( pc_pcgen_if ),
.instr_req_o ( fetch_req_if_ex ),
.instr_addr_o ( fetch_vaddr_if_ex ),
.instr_gnt_i ( fetch_gnt_ex_if ),
.instr_rvalid_i ( fetch_valid_ex_if ),
.instr_rdata_i ( fetch_rdata_ex_if ),
.flush_i ( flush_ctrl_if ),
.if_busy_o ( if_ready_if_pcgen ),
.id_ready_i ( ready_id_if ),
.fetch_address_i ( fetch_address_pcgen_if ),
.fetch_valid_i ( fetch_valid_pcgen_if ),
.branch_predict_i ( branch_predict_pcgen_if ),
.instr_req_o ( fetch_req_if_ex ),
.instr_addr_o ( fetch_vaddr_if_ex ),
.instr_gnt_i ( fetch_gnt_ex_if ),
.instr_rvalid_i ( fetch_valid_ex_if ),
.instr_rdata_i ( fetch_rdata_ex_if ),
.instr_valid_id_o ( instr_valid_if_id ),
.instr_rdata_id_o ( instr_rdata_if_id ),
.is_compressed_id_o ( is_compressed_if_id ),
.illegal_c_insn_id_o ( illegal_c_insn_if_id ),
.pc_if_o ( pc_if ),
.pc_id_o ( pc_id_if_id ),
.ex_o ( exception_if_id ),
.fetch_entry_o ( fetch_entry_if_id ),
.fetch_entry_valid_i ( fetch_valid_if_id ),
.instr_ack_i ( decode_ack_id_if ),
.ex_o ( exception_if_id ),
.*
);
// ---------
@ -250,96 +257,112 @@ module ariane
.NR_WB_PORTS ( NR_WB_PORTS )
)
id_stage_i (
.test_en_i ( test_en_i ),
.flush_i ( flush ),
.instruction_i ( instr_rdata_if_id ),
.instruction_valid_i ( instr_valid_if_id ),
.is_compressed_i ( is_compressed_if_id ),
.pc_if_i ( pc_if ), // PC from if
.ex_if_i ( exception_if_id ), // exception from if
.ready_o ( ready_id_if ),
.test_en_i ( test_en_i ),
.flush_i ( flush ),
.flush_unissued_instr_i ( flush_unissued_instr_ctrl_id ),
.flush_scoreboard_i ( flush_scoreboard_ctrl_id ),
.fetch_entry_i ( fetch_entry_if_id ),
.fetch_entry_valid_i ( fetch_valid_if_id ),
.decoded_instr_ack_o ( decode_ack_id_if ),
.ex_if_i ( exception_if_id ), // exception from if
.ready_o ( ready_id_if ),
// Functional Units
.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 ),
.operator_o ( operator_id_ex ),
.operand_a_o ( operand_a_id_ex ),
.operand_b_o ( operand_b_id_ex ),
.operand_c_o ( operand_c_id_ex ),
.imm_o ( imm_id_ex ),
.trans_id_o ( trans_id_id_ex ),
.pc_o ( pc_id_ex ),
.is_compressed_instr_o ( is_compressed_instr_id_ex ),
// 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
.branch_predict_o ( branch_predict_id_ex ), // branch predict to ex
.resolve_branch_i ( resolve_branch_ex_id ), // in order to resolve the branch
// LSU
.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 ),
// CSR
.csr_ready_i ( csr_ready_ex_id ),
.csr_valid_o ( csr_valid_id_ex ),
.alu_ready_i ( alu_ready_ex_id ),
.alu_valid_o ( alu_valid_id_ex ),
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id, csr_trans_id_ex_id }),
.wdata_i ( {alu_result_ex_id, lsu_result_ex_id, csr_result_ex_id }),
.ex_ex_i ( {alu_exception_ex_id, lsu_exception_ex_id, {$bits(exception){1'b0}} }),
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, csr_valid_ex_id }),
.lsu_ready_i ( lsu_ready_ex_id ),
.lsu_valid_o ( lsu_valid_id_ex ),
.waddr_a_i ( waddr_a_commit_id ),
.wdata_a_i ( wdata_a_commit_id ),
.we_a_i ( we_a_commit_id ),
.mult_ready_i ( mult_ready_ex_id ),
.mult_valid_o ( mult_valid_id_ex ),
.csr_ready_i ( csr_ready_ex_id ),
.csr_valid_o ( csr_valid_id_ex ),
.trans_id_i ( {alu_trans_id_ex_id, lsu_trans_id_ex_id , csr_trans_id_ex_id} ),
.wdata_i ( {alu_result_ex_id, lsu_result_ex_id, csr_result_ex_id} ),
.ex_ex_i ( {{$bits(exception){1'b0}}, lsu_exception_ex_id, {$bits(exception){1'b0}} } ),
.wb_valid_i ( {alu_valid_ex_id, lsu_valid_ex_id, csr_valid_ex_id} ),
.waddr_a_i ( waddr_a_commit_id ),
.wdata_a_i ( wdata_a_commit_id ),
.we_a_i ( we_a_commit_id ),
.commit_instr_o ( commit_instr_id_commit ),
.commit_ack_i ( commit_ack_commit_id ),
.commit_instr_o ( commit_instr_id_commit ),
.commit_ack_i ( commit_ack_commit_id ),
.*
);
// ---------
// EX
// ---------
ex_stage ex_stage_i (
.flush_i ( flush ),
.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 ),
.comparison_result_o ( ),
.flush_i ( flush ),
.operator_i ( operator_id_ex ),
.operand_a_i ( operand_a_id_ex ),
.operand_b_i ( operand_b_id_ex ),
.operand_c_i ( operand_c_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 ),
// 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_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 ),
// 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 ),
// 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_exception_o ( lsu_exception_ex_id ),
.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_exception_o ( lsu_exception_ex_id ),
// CSR
.csr_ready_o ( csr_ready_ex_id ),
.csr_valid_i ( csr_valid_id_ex ),
.csr_trans_id_o ( csr_trans_id_ex_id ),
.csr_result_o ( csr_result_ex_id ),
.csr_valid_o ( csr_valid_ex_id ),
.csr_addr_o ( csr_addr_ex_csr ),
.csr_commit_i ( csr_commit_commit_ex ), // from commit
.csr_ready_o ( csr_ready_ex_id ),
.csr_valid_i ( csr_valid_id_ex ),
.csr_trans_id_o ( csr_trans_id_ex_id ),
.csr_result_o ( csr_result_ex_id ),
.csr_valid_o ( csr_valid_ex_id ),
.csr_addr_o ( csr_addr_ex_csr ),
.csr_commit_i ( csr_commit_commit_ex ), // from commit
// memory management
.enable_translation_i ( enable_translation_csr_ex ), // from CSR
.fetch_req_i ( fetch_req_if_ex ),
.fetch_gnt_o ( fetch_gnt_ex_if ),
.fetch_valid_o ( fetch_valid_ex_if ),
.fetch_err_o ( fetch_err_ex_if ),
.fetch_vaddr_i ( fetch_vaddr_if_ex ),
.fetch_rdata_o ( fetch_rdata_ex_if ),
.priv_lvl_i ( priv_lvl ), // from CSR
.flag_pum_i ( flag_pum_csr_ex ), // from CSR
.flag_mxr_i ( flag_mxr_csr_ex ), // from CSR
.pd_ppn_i ( pd_ppn_csr_ex ), // from CSR
.asid_i ( asid_csr_ex ), // from CSR
.flush_tlb_i ( flush_tlb ),
.enable_translation_i ( enable_translation_csr_ex ), // from CSR
.fetch_req_i ( fetch_req_if_ex ),
.fetch_gnt_o ( fetch_gnt_ex_if ),
.fetch_valid_o ( fetch_valid_ex_if ),
.fetch_err_o ( fetch_err_ex_if ),
.fetch_vaddr_i ( fetch_vaddr_if_ex ),
.fetch_rdata_o ( fetch_rdata_ex_if ),
.priv_lvl_i ( priv_lvl ), // from CSR
.flag_pum_i ( flag_pum_csr_ex ), // from CSR
.flag_mxr_i ( flag_mxr_csr_ex ), // from CSR
.pd_ppn_i ( pd_ppn_csr_ex ), // from CSR
.asid_i ( asid_csr_ex ), // from CSR
.flush_tlb_i ( flush_tlb ),
.mult_ready_o ( mult_ready_ex_id ),
.mult_valid_i ( mult_valid_id_ex ),
.mult_ready_o ( mult_ready_ex_id ),
.mult_valid_i ( mult_valid_id_ex ),
.*
);
// ---------
@ -369,7 +392,7 @@ module ariane
.ASID_WIDTH ( ASID_WIDTH )
)
csr_regfile_i (
.flush_o ( ),
.flush_o ( flush_csr_ctrl ),
.ex_i ( ex_commit ),
.csr_op_i ( csr_op_commit_csr ),
.csr_addr_i ( csr_addr_ex_csr ),
@ -393,16 +416,47 @@ module ariane
// Controller
// ------------
logic flush_commit_i;
logic mispredict_i;
mispredict mispredict_o;
controller i_controller (
.clk_i (clk_i ),
.rst_ni (rst_ni ),
.flush_commit_i(flush_commit_i),
.mispredict_i (mispredict_i ),
.mispredict_o (mispredict_o )
);
controller controller_i (
.flush_bp_o ( ),
.flush_scoreboard_o ( flush_scoreboard_ctrl_id ),
.flush_unissued_instr_o ( flush_unissued_instr_ctrl_id ),
.flush_if_o ( flush_ctrl_if ),
.flush_id_o ( ),
.flush_ex_o ( ),
.flush_ready_lsu_i ( ),
.flush_commit_i ( flush_commit_i ),
.flush_csr_i ( flush_csr_ctrl ),
.resolved_branch_i ( resolved_branch ),
.*
);
// -------------------
// Instruction Tracer
// -------------------
`ifndef SYNTHESIS
instruction_tracer_if tracer_if (clk_i);
// assign instruction tracer interface
assign tracer_if.rstn = rst_ni;
assign tracer_if.commit_instr = commit_instr_id_commit;
assign tracer_if.commit_ack = commit_ack_commit_id;
assign tracer_if.fetch = fetch_entry_if_id;
assign tracer_if.fetch_valid = fetch_valid_if_id;
assign tracer_if.fetch_ack = decode_ack_id_if;
assign tracer_if.waddr = waddr_a_commit_id;
assign tracer_if.wdata = wdata_a_commit_id;
assign tracer_if.we = we_a_commit_id;
program instr_tracer (instruction_tracer_if tracer_if);
instruction_tracer it = new (tracer_if);
initial begin
it.trace();
end
endprogram
instr_tracer instr_tracer_i (tracer_if);
`endif
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin

128
src/branch_engine.sv Normal file
View file

@ -0,0 +1,128 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 09.05.2017
// Description: Branch target calculation and comparison
//
//
// Copyright (C) 2017 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.
//
import ariane_pkg::*;
module branch_engine (
input fu_op operator_i,
input logic [63:0] operand_a_i,
input logic [63:0] operand_b_i,
input logic [63:0] operand_c_i,
input logic [63:0] imm_i,
input logic [63:0] pc_i,
input logic is_compressed_instr_i,
input logic fu_valid_i, // any functional unit is valid, check that there is no accidental mis-predict
input logic valid_i,
input branchpredict_sbe branch_predict_i, // this is the address we predicted
output branchpredict resolved_branch_o, // this is the actual address we are targeting
output logic resolve_branch_o, // to ID to clear that we resolved the branch and we can
// accept new entries to the scoreboard
output exception branch_ex_o // branch exception out
);
logic [63:0] target_address;
logic [63:0] next_pc;
logic comparison_result; // result of comparison
logic sgn; // sign extend
always_comb begin : branch_resolve
// by default e.g.: when this is a jump, the branch is taken
// so set the comparison result to 1
comparison_result = 1'b1;
// sign switch
sgn = 1'b1;
// if this is an unsigned operation clear the sign bit
// this should ease data-path extraction
if (operator_i inside {LTU, GEU})
sgn = 1'b0;
// get the right comparison result
case (operator_i)
EQ: comparison_result = operand_a_i == operand_b_i;
NE: comparison_result = operand_a_i != operand_b_i;
LTS: comparison_result = ($signed({sgn & operand_a_i[63], operand_a_i}) < $signed({sgn & operand_b_i[63], operand_b_i}));
GES: comparison_result = ($signed({sgn & operand_a_i[63], operand_a_i}) >= $signed({sgn & operand_b_i[63], operand_b_i}));
default: comparison_result = 1'b1;
endcase
end
// here we handle the various possibilities of mis-predicts
always_comb begin : mispredict_handler
target_address = 64'b0;
resolved_branch_o.pc = 64'b0;
resolved_branch_o.target_address = 64'b0;
resolved_branch_o.is_taken = 1'b0;
resolved_branch_o.valid = valid_i;
resolved_branch_o.is_mispredict = 1'b0;
resolved_branch_o.is_lower_16 = 1'b0;
resolve_branch_o = 1'b0;
// 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(operand_c_i) + $signed(imm_i));
if (valid_i) begin
// save PC - we need this to get the target row in the branch target buffer
// we play this trick with the branch instruction which wraps a byte boundary:
// |---------- Place the prediction on this PC
// \/
// ____________________________________________________
// |branch [15:0] | branch[31:16] | compressed 1[15:0] |
// |____________________________________________________
// This will relief the prefetcher to re-fetch partially fetched unaligned branch instructions e.g.:
// we don't have a back arch between prefetcher and decoder/instruction FIFO.
resolved_branch_o.pc = (is_compressed_instr_i || pc_i[1] == 1'b0) ? pc_i : ({pc_i[63:2], 2'b0} + 64'h4);
// save if the branch instruction was in the lower 16 bit of the instruction word
// the first case is a compressed instruction which is in slot 0
// the other case is a misaligned uncompressed instruction which we only predict in the next cycle (see notes above)
resolved_branch_o.is_lower_16 = (is_compressed_instr_i && pc_i[1] == 1'b0) || (!is_compressed_instr_i && pc_i[1] == 1'b1);
// write target address which goes to pc gen
resolved_branch_o.target_address = (comparison_result) ? target_address : next_pc;
resolved_branch_o.is_taken = comparison_result;
// we've detected a branch in ID with the following parameters
// we mis-predicted e.g.: the predicted address is unequal to the actual address
if (target_address[0] == 1'b0) begin
// TODO in case of branch which is not taken it is not necessary to check for the address
if (target_address != branch_predict_i.predict_address // we mis-predicted the address of the branch
|| branch_predict_i.predict_taken != comparison_result // we mis-predicted the outcome of the branch
|| branch_predict_i.valid == 1'b0 // this means branch-prediction thought it was no
// branch but in reality it was one
) begin
resolved_branch_o.is_mispredict = 1'b1;
end
end
// to resolve the branch in ID -> only do this if this was indeed a branch (hence vald_i is asserted)
resolve_branch_o = 1'b1;
// the other case would be that this instruction was no branch but branch prediction thought that it was one
// this is essentially also a mis-predict
end else if (fu_valid_i && branch_predict_i.valid) begin
// re-set the branch to the next PC
resolved_branch_o.is_mispredict = 1'b1;
resolved_branch_o.target_address = next_pc;
end
end
// use ALU exception signal for storing instruction fetch exceptions if
// the target address is not aligned to a 2 byte boundary
always_comb begin : exception_handling
branch_ex_o.cause = INSTR_ADDR_MISALIGNED;
branch_ex_o.valid = 1'b0;
branch_ex_o.tval = pc_i;
// only throw exception if this is indeed a branch
if (valid_i && target_address[0] != 1'b0)
branch_ex_o.valid = 1'b1;
end
endmodule

View file

@ -19,20 +19,18 @@
import ariane_pkg::*;
module btb #(
parameter int NR_ENTRIES = 64,
parameter int NR_ENTRIES = 1024,
parameter int BITS_SATURATION_COUNTER = 2
)
(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the btb
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the btb
input logic [63:0] vpc_i, // virtual PC from IF stage
input mispredict mispredict_i, // a miss-predict happened -> update data structure
input logic [63:0] vpc_i, // virtual PC from IF stage
input branchpredict branch_predict_i, // a mis-predict happened -> update data structure
output logic is_branch_o, // instruction at vpc_i is a branch
output logic predict_taken_o, // the branch is taken
output logic [63:0] branch_target_address_o // instruction has the following target address
output branchpredict_sbe branch_predict_o // branch prediction for issuing to the pipeline
);
// number of bits which are not used for indexing
localparam OFFSET = 2;
@ -43,6 +41,7 @@ module btb #(
logic valid;
logic [63:0] target_address;
logic [BITS_SATURATION_COUNTER-1:0] saturation_counter;
logic is_lower_16;
} btb_n [NR_ENTRIES-1:0], btb_q [NR_ENTRIES-1:0];
logic [$clog2(NR_ENTRIES)-1:0] index, update_pc;
@ -51,46 +50,52 @@ module btb #(
// get actual index positions
// we ignore the 0th bit since all instructions are aligned on
// a half word boundary
assign update_pc = mispredict_i.pc[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
assign update_pc = branch_predict_i.pc[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
assign index = vpc_i[$clog2(NR_ENTRIES) + OFFSET - 1:OFFSET];
// we combinatorially predict the branch and the target address
assign is_branch_o = btb_q[$unsigned(index)].valid;
assign predict_taken_o = btb_q[$unsigned(index)].saturation_counter[BITS_SATURATION_COUNTER-1];
assign branch_target_address_o = btb_q[$unsigned(index)].target_address;
assign branch_predict_o.valid = btb_q[index].valid;
assign branch_predict_o.predict_taken = btb_q[index].saturation_counter[BITS_SATURATION_COUNTER-1];
assign branch_predict_o.predict_address = btb_q[index].target_address;
assign branch_predict_o.is_lower_16 = btb_q[index].is_lower_16;
// update on a miss-predict
always_comb begin : update_mispredict
// update on a mis-predict
always_comb begin : update_branch_predict
btb_n = btb_q;
saturation_counter = btb_q[$unsigned(update_pc)].saturation_counter;
saturation_counter = btb_q[update_pc].saturation_counter;
if (mispredict_i.valid) begin
btb_n[$unsigned(update_pc)].valid = 1'b1;
if (branch_predict_i.valid) begin
btb_n[update_pc].valid = 1'b1;
// update saturation counter
// first check if counter is already saturated in the positive regime e.g.: branch taken
if (saturation_counter == {BITS_SATURATION_COUNTER{1'b1}} && ~mispredict_i.is_taken) begin
if (saturation_counter == {BITS_SATURATION_COUNTER{1'b1}}) begin
// we can safely decrease it
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter - 1;
if (~branch_predict_i.is_taken)
btb_n[update_pc].saturation_counter = saturation_counter - 1;
// then check if it saturated in the negative regime e.g.: branch not taken
end else if (saturation_counter == {BITS_SATURATION_COUNTER{1'b0}} && mispredict_i.is_taken) begin
end else if (saturation_counter == {BITS_SATURATION_COUNTER{1'b0}}) begin
// we can safely increase it
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
if (branch_predict_i.is_taken)
btb_n[update_pc].saturation_counter = saturation_counter + 1;
end else begin // otherwise we are not in any boundaries and can decrease or increase it
if (mispredict_i.is_taken)
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter + 1;
if (branch_predict_i.is_taken)
btb_n[update_pc].saturation_counter = saturation_counter + 1;
else
btb_n[$unsigned(update_pc)].saturation_counter = saturation_counter - 1;
btb_n[update_pc].saturation_counter = saturation_counter - 1;
end
// the target address is simply updated
btb_n[$unsigned(update_pc)].target_address = mispredict_i.target_address;
btb_n[update_pc].target_address = branch_predict_i.target_address;
// as is the information whether this was a compressed branch
btb_n[update_pc].is_lower_16 = branch_predict_i.is_lower_16;
end
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
// TODO: think about the reset value
btb_q <= '{default: 0};
// Bias the branches to be taken upon first arrival
for (int i = 0; i < NR_ENTRIES; i++)
btb_q[i] <= '{1'b0, 64'b0, 2'b10, 1'b0};
end else begin
// evict all entries
if (flush_i) begin

View file

@ -115,4 +115,27 @@ module commit_stage (
end
end
endmodule
`ifndef SYNTHESIS
always_ff @(posedge clk_i) begin : exception_displayer
string cause;
// we encountered an exception
// format cause
if (exception_o.valid) begin
case (exception_o.cause)
INSTR_ADDR_MISALIGNED: cause = "Instruction Address Misaligned";
INSTR_ACCESS_FAULT: cause = "Instruction Access Fault";
ILLEGAL_INSTR: cause = "Illegal Instruction";
BREAKPOINT: cause = "Breakpoint";
LD_ADDR_MISALIGNED: cause = "Load Address Misaligned";
LD_ACCESS_FAULT: cause = "Load Access Fault";
ST_ADDR_MISALIGNED: cause = "Store Address Misaligned";
ST_ACCESS_FAULT: cause = "Store Access Fault";
ENV_CALL_UMODE: cause = "Environment Call UMode";
ENV_CALL_SMODE: cause = "Environment Call SMode";
ENV_CALL_MMODE: cause = "Environment Call MMode";
endcase
$display("Exception @%t, PC: %0h, TVal: %0h, Cause: %s", $time, commit_instr_i.pc, exception_o.tval, cause);
end
end
`endif
endmodule

View file

@ -27,18 +27,15 @@ import ariane_pkg::*;
module compressed_decoder
(
input logic [31:0] instr_i,
input logic [15:0] instr_i,
output logic [31:0] instr_o,
output logic is_compressed_o,
output logic illegal_instr_o
);
// -------------------
// Compressed Decoder
// -------------------
always_comb
begin
always_comb begin
illegal_instr_o = 1'b0;
instr_o = '0;
@ -253,13 +250,7 @@ module compressed_decoder
endcase
end
default: begin
// 32 bit (or more) instruction
instr_o = instr_i;
end
default: ;
endcase
end
assign is_compressed_o = (instr_i[1:0] != 2'b11);
endmodule

View file

@ -20,16 +20,33 @@
import ariane_pkg::*;
module controller (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_commit_i, // flush request from commit stage in
input logic mispredict_i,
output logic flush_bp_o, // flush branch prediction data structures
output logic flush_unissued_instr_o,
output logic flush_scoreboard_o,
output logic flush_if_o,
output logic flush_id_o,
output logic flush_ex_o,
output mispredict mispredict_o // to pcgen update branch history table
input logic flush_ready_lsu_i, // we need to wait for this signal from LSU
input logic flush_commit_i, // flush request from commit stage in
input logic flush_csr_i,
input branchpredict resolved_branch_i
);
assign flush_bp_o = 1'b0;
// flush on mispredict
always_comb begin : flush_ctrl
flush_unissued_instr_o = 1'b0;
flush_scoreboard_o = 1'b0;
flush_if_o = 1'b0;
// flush on mispredict
if (resolved_branch_i.is_mispredict) begin
flush_unissued_instr_o = 1'b1;
flush_if_o = 1'b1;
end
// flush on exception
end
// flush on exception
endmodule

View file

@ -11,13 +11,15 @@
import ariane_pkg::*;
module decoder (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic [63:0] pc_i, // PC from IF
input logic is_compressed_i, // is a compressed instruction
input logic [31:0] instruction_i, // instruction from IF
input exception ex_i, // if an exception occured in if
output scoreboard_entry instruction_o // scoreboard entry to scoreboard
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic [63:0] pc_i, // PC from IF
input logic is_compressed_i, // is a compressed instruction
input logic [31:0] instruction_i, // instruction from IF
input branchpredict_sbe branch_predict_i,
input exception ex_i, // if an exception occured in if
output scoreboard_entry instruction_o, // scoreboard entry to scoreboard
output logic is_control_flow_instr_o // this instruction will change the control flow
);
logic illegal_instr;
instruction instr;
@ -45,6 +47,7 @@ module decoder (
always_comb begin : decoder
imm_select = NOIMM;
is_control_flow_instr_o = 1'b0;
illegal_instr = 1'b0;
instruction_o.pc = pc_i;
instruction_o.fu = NONE;
@ -56,6 +59,7 @@ module decoder (
instruction_o.trans_id = 5'b0;
instruction_o.is_compressed = is_compressed_i;
instruction_o.use_zimm = 1'b0;
instruction_o.bp = branch_predict_i;
if (~ex_i.valid) begin
case (instr.rtype.opcode)
@ -294,17 +298,40 @@ module decoder (
OPCODE_BRANCH: begin
// TODO: Implement
imm_select = BIMM;
end
imm_select = BIMM;
instruction_o.fu = CTRL_FLOW;
is_control_flow_instr_o = 1'b1;
case (instr.stype.funct3)
3'b000: instruction_o.op = EQ;
3'b001: instruction_o.op = NE;
3'b100: instruction_o.op = LTS;
3'b101: instruction_o.op = GES;
3'b110: instruction_o.op = LTU;
3'b111: instruction_o.op = GEU;
default: begin
is_control_flow_instr_o = 1'b0;
illegal_instr = 1'b1;
end
endcase
end
// Jump and link register
OPCODE_JALR: begin
// TODO: Implement
imm_select = UIMM;
instruction_o.fu = CTRL_FLOW;
instruction_o.op = JALR;
imm_select = UIMM;
instruction_o.use_pc = 1'b1;
instruction_o.rd = instr.itype.rd;
is_control_flow_instr_o = 1'b1;
end
// Jump and link
OPCODE_JAL: begin
// TODO: Implement
imm_select = JIMM;
instruction_o.fu = CTRL_FLOW;
instruction_o.op = JAL;
imm_select = JIMM;
instruction_o.use_pc = 1'b1;
instruction_o.rd = instr.utype.rd;
is_control_flow_instr_o = 1'b1;
end
OPCODE_AUIPC: begin
@ -377,8 +404,8 @@ module decoder (
// Exception handling
// --------------------------------
always_comb begin : exception_handling
instruction_o.ex = ex_i;
instruction_o.valid = 1'b0;
instruction_o.ex = ex_i;
instruction_o.valid = 1'b0;
// look if we didn't already get an exception in any previous
// stage - we should not overwrite it as we retain order regarding the exception
if (~ex_i.valid && illegal_instr) begin
@ -388,6 +415,8 @@ module decoder (
instruction_o.ex.valid = 1'b1;
// we decoded an illegal exception here
instruction_o.ex.cause = ILLEGAL_INSTR;
// if we decoded an illegal instruction save the faulting instruction to tval
instruction_o.ex.tval = instruction_i;
end
end
endmodule

View file

@ -29,20 +29,28 @@ module ex_stage #(
input fu_op operator_i,
input logic [63:0] operand_a_i,
input logic [63:0] operand_b_i,
input logic [63:0] operand_c_i,
input logic [63:0] imm_i,
input logic [TRANS_ID_BITS-1:0] trans_id_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 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 logic comparison_result_o,
output logic [TRANS_ID_BITS-1:0] alu_trans_id_o, // ID of scoreboard entry at which to write back
output exception alu_exception_o,
// Branches and Jumps
input logic branch_valid_i, // we are using the branch unit
input branchpredict_sbe branch_predict_i, // branch prediction in
output branchpredict resolved_branch_o, // the branch engine uses the write back from the ALU
output logic resolve_branch_o, // to ID signaling that we resolved the branch
// 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 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,
input logic lsu_commit_i,
@ -91,26 +99,29 @@ module ex_stage #(
input logic mult_valid_i // Output is valid
);
// ALU is a single cycle instructions, hence it is always ready
assign alu_ready_o = 1'b1;
assign alu_valid_o = alu_valid_i;
assign alu_trans_id_o = trans_id_i;
// -----
// ALU
// -----
alu alu_i (
.adder_result_o ( ),
.adder_result_ext_o ( ),
.result_o ( alu_result_o ),
.comparison_result_o ( comparison_result_o ),
.is_equal_result_o ( ),
.result_o ( alu_result_o ),
.*
);
// --------------------
// Branch Engine
// --------------------
branch_engine branch_engine_i (
.fu_valid_i ( alu_valid_i & lsu_valid_i & csr_valid_i ),
.valid_i ( branch_valid_i ),
.branch_ex_o ( alu_exception_o ), // we use the ALU exception WB for the branch exception
.*
);
// ----------------
// Multiplication
// ----------------
// TODO
// ----------------
// Load-Store Unit
// ----------------
@ -118,6 +129,7 @@ module ex_stage #(
.commit_i ( lsu_commit_i ),
.*
);
// -----
// CSR
// -----
@ -127,4 +139,5 @@ module ex_stage #(
.*
);
endmodule

View file

@ -1,242 +1,318 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 unpublished work. //
// Any reuse/redistribution should only be under explicit permission. //
// //
// Bug fixes and contributions will eventually be released under the //
// SolderPad open hardware license and under the copyright of ETH Zurich //
// and the University of Bologna. //
// //
// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch //
// //
// Design Name: Fetch Fifo for 32 bit memory interface //
// Project Name: zero-riscy //
// Language: SystemVerilog //
// //
// Description: Fetch fifo //
////////////////////////////////////////////////////////////////////////////////
// Author: Florian Zaruba, ETH Zurich
// Date: 14.05.2017
// Description: Dual Port fetch FIFO with instruction aligner and support for compressed instructions
//
// Copyright (C) 2017 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.
//
import ariane_pkg::*;
// input port: send address one cycle before the data
// clear_i clears the FIFO for the following cycle. in_addr_i can be sent in
// this cycle already
module fetch_fifo
(
input logic clk,
input logic rst_n,
input logic clk_i,
input logic rst_ni,
// control signals
input logic clear_i, // clears the contents of the fifo
// input port
input logic [63:0] in_addr_i,
input logic [31:0] in_rdata_i,
input logic in_valid_i,
output logic in_ready_o,
input logic flush_i, // clears the contents of the FIFO -> quasi reset
// branch prediction at in_addr_i address, as this is an address and not PC it can be the case
// that we have two compressed instruction (or one compressed instruction and one unaligned instruction) so we need
// keep two prediction inputs: [c1|c0] <- prediction for c1 and c0
input branchpredict_sbe branch_predict_i,
input logic [63:0] in_addr_i,
input logic [31:0] in_rdata_i,
input logic in_valid_i,
output logic in_ready_o,
// output port
output logic [63:0] out_addr_o,
output logic [31:0] out_rdata_o,
output logic out_valid_o,
input logic out_ready_i,
output fetch_entry fetch_entry_o,
output logic out_valid_o,
input logic out_ready_i
);
output logic out_valid_stored_o // same as out_valid_o, except that if something is incoming now it is not
// included. This signal is available immediately as it comes directly out of FFs
);
localparam DEPTH = 8; // must be a power of two
localparam DEPTH = 3; // must be 3 or greater
/* verilator lint_off LITENDIAN */
// index 0 is used for output
logic [0:DEPTH-1] [63:0] addr_n, addr_int, addr_Q;
logic [0:DEPTH-1] [31:0] rdata_n, rdata_int, rdata_Q;
logic [0:DEPTH-1] valid_n, valid_int, valid_Q;
// input registers - bounding the path from memory
branchpredict_sbe branch_predict_n, branch_predict_q;
logic [63:0] in_addr_n, in_addr_q;
logic [31:0] in_rdata_n, in_rdata_q;
logic in_valid_n, in_valid_q;
// compressed to decompressed instruction
logic [31:0] decompressed_instruction [2];
logic is_illegal [2];
logic [63:0] addr_next;
logic [31:0] rdata, rdata_unaligned;
logic valid, valid_unaligned;
fetch_entry mem_n[DEPTH-1:0], mem_q[DEPTH-1:0];
logic [$clog2(DEPTH)-1:0] read_pointer_n, read_pointer_q;
logic [$clog2(DEPTH)-1:0] write_pointer_n, write_pointer_q;
logic [$clog2(DEPTH)-1:0] status_cnt_n, status_cnt_q; // this integer will be truncated by the synthesis tool
logic aligned_is_compressed, unaligned_is_compressed;
logic aligned_is_compressed_st, unaligned_is_compressed_st;
/* lint_on */
//----------------------------------------------------------------------------
// output port
//----------------------------------------------------------------------------
// status signals
logic full, empty;
// the last instruction was unaligned
logic unaligned_n, unaligned_q;
// save the unaligned part of the instruction to this ff
logic [15:0] unaligned_instr_n, unaligned_instr_q;
// save the address of the unaligned instruction
logic [63:0] unaligned_address_n, unaligned_address_q;
// we always need two empty places
// as it could happen that we get two compressed instructions/cycle
/* verilator lint_off WIDTH */
assign full = (status_cnt_q >= DEPTH - 3);
assign empty = (status_cnt_q == 0);
/* verilator lint_on WIDTH */
// the output is valid if we are are not empty
assign out_valid_o = !empty;
// we need space for at least two instructions: the full flag is conditioned on that
// but if we pop in the current cycle and we have one place left we can still fit two instructions alt
assign in_ready_o = !full;
assign rdata = (valid_Q[0]) ? rdata_Q[0] : in_rdata_i;
assign valid = valid_Q[0] || in_valid_i;
assign rdata_unaligned = (valid_Q[1]) ? {rdata_Q[1][15:0], rdata[31:16]} : {in_rdata_i[15:0], rdata[31:16]};
// it is implied that rdata_valid_Q[0] is set
assign valid_unaligned = (valid_Q[1] || (valid_Q[0] && in_valid_i));
assign unaligned_is_compressed = rdata[17:16] != 2'b11;
assign aligned_is_compressed = rdata[1:0] != 2'b11;
assign unaligned_is_compressed_st = rdata_Q[0][17:16] != 2'b11;
assign aligned_is_compressed_st = rdata_Q[0][1:0] != 2'b11;
//----------------------------------------------------------------------------
// instruction aligner (if unaligned)
//----------------------------------------------------------------------------
always_comb
begin
// serve the aligned case even though the output address is unaligned when
// the next instruction will be from a hardware loop target
// in this case the current instruction is already prealigned in element 0
if (out_addr_o[1]) begin
// unaligned case
out_rdata_o = rdata_unaligned;
if (unaligned_is_compressed)
out_valid_o = valid;
else
out_valid_o = valid_unaligned;
end else begin
// aligned case
out_rdata_o = rdata;
out_valid_o = valid;
end
end
assign out_addr_o = (valid_Q[0]) ? addr_Q[0] : in_addr_i;
// this valid signal must not depend on signals from outside!
always_comb
begin
out_valid_stored_o = 1'b1;
if (out_addr_o[1]) begin
if (unaligned_is_compressed_st)
out_valid_stored_o = 1'b1;
else
out_valid_stored_o = valid_Q[1];
end else begin
out_valid_stored_o = valid_Q[0];
end
end
//----------------------------------------------------------------------------
// input port
//----------------------------------------------------------------------------
// we accept data as long as our fifo is not full
// we don't care about clear here as the data will be received one cycle
// later anyway
assign in_ready_o = ~valid_Q[DEPTH-2];
//----------------------------------------------------------------------------
// FIFO management
//----------------------------------------------------------------------------
int j;
always_comb
begin
addr_int = addr_Q;
rdata_int = rdata_Q;
valid_int = valid_Q;
if (in_valid_i) begin
for(j = 0; j < DEPTH; j++) begin
if (~valid_Q[j]) begin
addr_int[j] = in_addr_i;
rdata_int[j] = in_rdata_i;
valid_int[j] = 1'b1;
break;
// ----------------
// Input Registers
// ----------------
always_comb begin
// if we are ready to accept new data - do so!
in_addr_n = in_addr_i;
in_rdata_n = in_rdata_i;
in_valid_n = in_valid_i;
branch_predict_n = branch_predict_i;
// flush the input registers
if (flush_i) begin
in_valid_n = 1'b0;
end
end
end
end
// --------------------
// Compressed Decoders
// --------------------
// compressed instruction decoding, or more precisely compressed instruction expander
// since it does not matter where we decompress instructions, we do it here to ease timing closure
genvar i;
generate
for (i = 0; i < 2; i++) begin
compressed_decoder compressed_decoder_i (
.instr_i ( in_rdata_q[(16*(i+1)-1):(i*16)] ),
.instr_o ( decompressed_instruction[i] ),
.illegal_instr_o ( is_illegal[i] )
);
end
endgenerate
assign addr_next = {addr_int[0][63:2], 2'b00} + 64'h4;
// --------------------------------------------
// FIFO Management + Instruction (re)-aligner
// --------------------------------------------
always_comb begin : output_port
// counter
automatic logic [$clog2(DEPTH)-1:0] status_cnt = status_cnt_q;
automatic logic [$clog2(DEPTH)-1:0] write_pointer = write_pointer_q;
// move everything by one step
always_comb
begin
addr_n = addr_int;
rdata_n = rdata_int;
valid_n = valid_int;
write_pointer_n = write_pointer_q;
read_pointer_n = read_pointer_q;
mem_n = mem_q;
unaligned_n = unaligned_q;
unaligned_instr_n = unaligned_instr_q;
unaligned_address_n = unaligned_address_q;
// ---------------------------------
// Input port & Instruction Aligner
// ---------------------------------
// do we actually want the first instruction or was the address a half word access?
if (in_valid_q && in_addr_q[1] == 1'b0) begin
if (!unaligned_q) begin
// we got a valid instruction so we can satisfy the unaligned instruction
unaligned_n = 1'b0;
// check if the instruction is compressed
if (in_rdata_q[1:0] != 2'b11) begin
// it is compressed
mem_n[write_pointer_q] = {
branch_predict_q, in_addr_q, decompressed_instruction[0], 1'b1, is_illegal[0]
};
if (out_ready_i && out_valid_o) begin
begin
if (addr_int[0][1]) begin
// unaligned case
if (unaligned_is_compressed) begin
addr_n[0] = {addr_next[63:2], 2'b00};
end else begin
addr_n[0] = {addr_next[63:2], 2'b10};
end
status_cnt++;
write_pointer++;
for (int i = 0; i < DEPTH - 1; i++)
begin
rdata_n[i] = rdata_int[i + 1];
end
rdata_n[DEPTH - 1] = 32'b0;
// is the second instruction also compressed, like:
// _____________________________________________
// | compressed 2 [31:16] | compressed 1[15:0] |
// |____________________________________________
// check if the lower compressed instruction was no branch otherwise we will need to squash this instruction
// but only if we predicted it to be taken, the predict was on the lower 16 bit compressed instruction
if (in_rdata_q[17:16] != 2'b11 && !(branch_predict_q.valid && branch_predict_q.predict_taken && branch_predict_q.is_lower_16)) begin
valid_n = {valid_int[1:DEPTH-1], 1'b0};
end else begin
mem_n[write_pointer_q + 1'b1] = {
branch_predict_q, {in_addr_q[63:2], 2'b10}, decompressed_instruction[1], 1'b1, is_illegal[1]
};
if (aligned_is_compressed) begin
// just increase address, do not move to next entry in FIFO
addr_n[0] = {addr_int[0][63:2], 2'b10};
end else begin
// move to next entry in FIFO
addr_n[0] = {addr_next[63:2], 2'b00};
for (int i = 0; i < DEPTH - 1; i++)
begin
rdata_n[i] = rdata_int[i + 1];
status_cnt++;
write_pointer++;
// $display("Instruction: [ c | c ] @ %t", $time);
// or is it an unaligned 32 bit instruction like
// ____________________________________________________
// |instr [15:0] | instr [31:16] | compressed 1[15:0] |
// |____________________________________________________
end else if (!(branch_predict_q.valid && branch_predict_q.predict_taken && branch_predict_q.is_lower_16)) begin
// save the lower 16 bit
unaligned_instr_n = in_rdata_q[31:16];
// and that it was unaligned
unaligned_n = 1'b1;
// save the address as well
unaligned_address_n = {in_addr_q[63:2], 2'b10};
// $display("Instruction: [ i0 | c ] @ %t", $time);
// this does not consume space in the FIFO
end
end else begin
// this is a full 32 bit instruction like
// _______________________
// | instruction [31:0] |
// |______________________
mem_n[write_pointer_q] = {
branch_predict_q, in_addr_q, in_rdata_q, 1'b0, 1'b0
};
status_cnt++;
write_pointer++;
// $display("Instruction: [ i ] @ %t", $time);
end
end
rdata_n[DEPTH - 1] = 32'b0;
valid_n = {valid_int[1:DEPTH-1], 1'b0};
end
// we have an outstanding unaligned instruction
if (in_valid_q && unaligned_q) begin
mem_n[write_pointer_q] = {
branch_predict_q, unaligned_address_q, {in_rdata_q[15:0], unaligned_instr_q}, 1'b0, 1'b0
};
status_cnt++;
write_pointer++;
// whats up with the other upper 16 bit of this instruction
// is the second instruction also compressed, like:
// _____________________________________________
// | compressed 2 [31:16] | unaligned[31:16] |
// |____________________________________________
// check if the lower compressed instruction was no branch otherwise we will need to squash this instruction
// but only if we predicted it to be taken, the predict was on the lower 16 bit compressed instruction
if (in_rdata_q[17:16] != 2'b11 && !(branch_predict_q.valid && branch_predict_q.predict_taken && branch_predict_q.is_lower_16)) begin
mem_n[write_pointer_q + 1'b1] = {
branch_predict_q, {in_addr_q[63:2], 2'b10}, decompressed_instruction[1], 1'b1, is_illegal[1]
};
status_cnt++;
write_pointer++;
// unaligned access served
unaligned_n = 1'b0;
// $display("Instruction: [ c | i1 ] @ %t", $time);
// or is it an unaligned 32 bit instruction like
// ____________________________________________________
// |instr [15:0] | instr [31:16] | compressed 1[15:0] |
// |____________________________________________________
end else if (!(branch_predict_q.valid && branch_predict_q.predict_taken && branch_predict_q.is_lower_16)) begin
// save the lower 16 bit
unaligned_instr_n = in_rdata_q[31:16];
// and that it was unaligned
unaligned_n = 1'b1;
// save the address as well
unaligned_address_n = {in_addr_q[63:2], 2'b10};
// $display("Instruction: [ i0 | i1 ] @ %t", $time);
// this does not consume space in the FIFO
// we've got a predicted taken branch we need to clear the unaligned flag if it was decoded as a lower 16 instruction
end else if (branch_predict_q.valid && branch_predict_q.predict_taken && branch_predict_q.is_lower_16) begin
// the next fetch will start from a 4 byte boundary again
unaligned_n = 1'b0;
end
end
end else if (in_valid_q && in_addr_q[1] == 1'b1) begin // address was a half word access
// reset the unaligned flag as this is a completely new fetch (because consecutive fetches only happen on a word basis)
unaligned_n = 1'b0;
// this is a compressed instruction
if (in_rdata_q[17:16] != 2'b11) begin
// it is compressed
mem_n[write_pointer_q] = {
branch_predict_q, in_addr_q, decompressed_instruction[1], 1'b1, is_illegal[1]
};
status_cnt++;
write_pointer++;
end else begin // this is the first part of a 32 bit unaligned instruction
// save the lower 16 bit
unaligned_instr_n = in_rdata_q[31:16];
// and that it was unaligned
unaligned_n = 1'b1;
// save the address as well
unaligned_address_n = {in_addr_q[63:2], 2'b10};
// this does not consume space in the FIFO
end
// there can never be a whole 32 bit instruction on a half word access
end
end
end
end
//----------------------------------------------------------------------------
// registers
//----------------------------------------------------------------------------
// -------------
// Output port
// -------------
// we are ready to accept a new request if we still have two places in the queue
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
addr_Q <= '{default: '0};
rdata_Q <= '{default: '0};
valid_Q <= '0;
end
else
begin
// on a clear signal from outside we invalidate the content of the FIFO
// completely and start from an empty state
if (clear_i) begin
valid_Q <= '0;
end else begin
addr_Q <= addr_n;
rdata_Q <= rdata_n;
valid_Q <= valid_n;
end
end
end
// Output assignments
fetch_entry_o = mem_q[read_pointer_q];
//----------------------------------------------------------------------------
// Assertions
//----------------------------------------------------------------------------
`ifndef SYNTHESIS
`ifndef VERILATOR
assert property (
@(posedge clk) (in_valid_i) |-> ((valid_Q[DEPTH-1] == 1'b0) || (clear_i == 1'b1)) );
`endif
`endif
if (out_ready_i) begin
read_pointer_n = read_pointer_q + 1;
status_cnt--;
end
write_pointer_n = write_pointer;
status_cnt_n = status_cnt;
if (flush_i) begin
status_cnt_n = '0;
write_pointer_n = 'b0;
read_pointer_n = 'b0;
// clear the unaligned instruction
unaligned_n = 1'b0;
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
status_cnt_q <= '{default: 0};
mem_q <= '{default: 0};
read_pointer_q <= '{default: 0};
write_pointer_q <= '{default: 0};
unaligned_q <= 1'b0;
unaligned_instr_q <= 16'b0;
unaligned_address_q <= 64'b0;
// input registers
in_addr_q <= 64'b0;
in_rdata_q <= 32'b0;
in_valid_q <= 1'b0;
branch_predict_q <= '{default: 0};
end else begin
status_cnt_q <= status_cnt_n;
mem_q <= mem_n;
read_pointer_q <= read_pointer_n;
write_pointer_q <= write_pointer_n;
unaligned_q <= unaligned_n;
unaligned_instr_q <= unaligned_instr_n;
unaligned_address_q <= unaligned_address_n;
// input registers
in_addr_q <= in_addr_n;
in_rdata_q <= in_rdata_n;
in_valid_q <= in_valid_n;
branch_predict_q <= branch_predict_n;
end
end
//-------------
// Assertions
//-------------
`ifndef SYNTHESIS
`ifndef VERILATOR
// since this is a dual port queue the status count of the queue should never change more than two
assert property (@(posedge clk_i) ((status_cnt_n - status_cnt_q) < 3 || (status_cnt_n - status_cnt_q) > 3)) else $error("FIFO underflowed or overflowed");
// assert property (
// @(posedge clk_i) (instr_gnt_i) |-> (instr_req_o) )
// else $warning("There was a grant without a request");
`endif
`endif
endmodule

View file

@ -21,19 +21,19 @@ module fifo #(
parameter type dtype = logic[63:0],
parameter int unsigned DEPTH = 4
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
// status flags
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic single_element_o, // there is just a single element in the queue
// as long as the queue is not full we can push new data
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
// as long as the queue is not empty we can pop new elements
output dtype data_o, // output data
input logic pop_i // pop head from queue
output dtype data_o, // output data
input logic pop_i // pop head from queue
);
// pointer to the read and write section of the queue
logic [$clog2(DEPTH) - 1:0] read_pointer_n, read_pointer_q, write_pointer_n, write_pointer_q;
@ -44,7 +44,7 @@ module fifo #(
assign full_o = (status_cnt_q == DEPTH);
assign empty_o = (status_cnt_q == 0);
assign single_element_o = (status_cnt_q == 1);
assign single_element_o = (status_cnt_q == 1);
// read and write queue logic
always_comb begin : read_write_comb
// default assignment

View file

@ -28,28 +28,36 @@ module id_stage #(
input logic test_en_i, // Test Enable
input logic flush_i,
input logic flush_unissued_instr_i,
input logic flush_scoreboard_i,
// from IF
input logic [31:0] instruction_i,
input logic instruction_valid_i,
input logic is_compressed_i,
input logic [63:0] pc_if_i,
input fetch_entry fetch_entry_i,
input logic fetch_entry_valid_i,
output logic decoded_instr_ack_o,
input exception ex_if_i, // we already got an exception in IF
output logic ready_o, // id is ready
output fu_op operator_o,
output logic [63:0] operand_a_o,
output logic [63:0] operand_b_o,
output logic [63:0] operand_c_o,
output logic [63:0] imm_o,
output logic [TRANS_ID_BITS-1:0] trans_id_o,
output logic [63:0] pc_o,
output logic is_compressed_instr_o,
input logic alu_ready_i,
output logic alu_valid_o,
output logic branch_valid_o, // use branch prediction unit
// ex just resolved our predicted branch, we are ready to accept new requests
input logic resolve_branch_i,
input logic lsu_ready_i,
output logic lsu_valid_o,
input logic mult_ready_i,
output logic mult_valid_o,
output logic mult_valid_o, // Branch predict Out
output branchpredict_sbe branch_predict_o,
input logic csr_ready_i,
output logic csr_valid_o,
@ -67,8 +75,9 @@ module id_stage #(
output scoreboard_entry commit_instr_o,
input logic commit_ack_i
);
// ---------------------------------------------------
// Global signals
// ---------------------------------------------------
logic full;
// ---------------------------------------------------
// Scoreboard (SB) <-> Issue and Read Operands (iro)
@ -84,21 +93,55 @@ module id_stage #(
logic issue_instr_valid_sb_iro;
logic issue_ack_iro_sb;
// ---------------------------------------------------
// Compressed Decoder <-> Decoder
// ---------------------------------------------------
// ---------------------------------------------------
// Decoder (DC) <-> Scoreboard (SB)
// ---------------------------------------------------
scoreboard_entry decoded_instr_dc_sb;
// ---------------------------------------------------
// Decoder (DC) <-> Branch Logic
// ---------------------------------------------------
logic is_control_flow_instr;
// TODO: Branching logic
assign ready_o = ~full;
// -----------------
// Branch logic
// -----------------
// This should basically prevent the scoreboard from accepting
// instructions past a branch. We need to resolve the branch beforehand.
// This limitation is in place to ease the backtracking of mis-predicted branches as they
// can simply be in the front-end of the processor.
logic unresolved_branch_n, unresolved_branch_q;
always_comb begin : unresolved_branch
unresolved_branch_n = unresolved_branch_q;
// we just resolved the branch
if (resolve_branch_i) begin
unresolved_branch_n = 1'b0;
end
// if the instruction is valid and it is a control flow instruction
if (fetch_entry_valid_i && is_control_flow_instr) begin
unresolved_branch_n = 1'b1;
end
// if we are requested to flush also flush the unresolved branch flag because either the flush
// was requested by a branch or an exception. In any case: any unresolved branch will get evicted
if (flush_unissued_instr_i || flush_i) begin
unresolved_branch_n = 1'b0;
end
end
// we are ready if we are not full and don't have any unresolved branches, but it can be
// the case that we have an unresolved branch which is cleared in that cycle (resolved_branch_i.valid == 1)
assign ready_o = ~full && (~unresolved_branch_q || resolve_branch_i);
decoder decoder_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.pc_i ( pc_if_i ),
.is_compressed_i ( is_compressed_i ),
.instruction_i ( instruction_i ),
.ex_i ( ex_if_i ),
.instruction_o ( decoded_instr_dc_sb )
.pc_i ( fetch_entry_i.address ),
.is_compressed_i ( fetch_entry_i.is_compressed ),
.instruction_i ( fetch_entry_i.instruction ),
.branch_predict_i ( fetch_entry_i.branch_predict ),
.ex_i ( ex_if_i ),
.instruction_o ( decoded_instr_dc_sb ),
.is_control_flow_instr_o ( is_control_flow_instr ),
.*
);
scoreboard #(
@ -108,7 +151,7 @@ module id_stage #(
scoreboard_i
(
.full_o ( full ),
.flush_i ( flush_i ),
.flush_i ( flush_scoreboard_i ),
.rd_clobber_o ( rd_clobber_sb_iro ),
.rs1_i ( rs1_iro_sb ),
.rs1_o ( rs1_sb_iro ),
@ -119,7 +162,7 @@ module id_stage #(
.commit_instr_o ( commit_instr_o ),
.commit_ack_i ( commit_ack_i ),
.decoded_instr_i ( decoded_instr_dc_sb ),
.decoded_instr_valid_i ( instruction_valid_i ),
.decoded_instr_valid_i ( fetch_entry_valid_i ),
.issue_instr_o ( issue_instr_sb_iro ),
.issue_instr_valid_o ( issue_instr_valid_sb_iro ),
.issue_ack_i ( issue_ack_iro_sb ),
@ -144,4 +187,12 @@ module id_stage #(
.*
);
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
unresolved_branch_q <= 1'b0;
end else begin
unresolved_branch_q <= unresolved_branch_n;
end
end
endmodule

View file

@ -1,43 +1,34 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 unpublished work. //
// Any reuse/redistribution should only be under explicit permission. //
// //
// Bug fixes and contributions will eventually be released under the //
// SolderPad open hardware license and under the copyright of ETH Zurich //
// and the University of Bologna. //
// ///
// Engineer: Renzo Andri - andrire@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// Andreas Traber - atraber@student.ethz.ch //
// Sven Stucki - svstucki@student.ethz.ch //
// //
// Design Name: Instruction Fetch Stage //
// Project Name: zero-riscy //
// Language: SystemVerilog //
// //
// Description: Instruction fetch unit: Selection of the next PC, and //
// buffering (sampling) of the read instruction //
// //
////////////////////////////////////////////////////////////////////////////////
// Author: Florian Zaruba, ETH Zurich
// Date: 14.05.2017
// Description: Instruction fetch stage
//
// Copyright (C) 2017 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.
//
import ariane_pkg::*;
module if_stage (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// control signals
input logic flush_i,
input logic req_i, // request new instructions
output logic if_busy_o, // is the IF stage busy fetching instructions?
input logic id_ready_i,
input logic halt_if_i, // pipeline stall
input logic set_pc_i, // set new PC
input logic [63:0] fetch_addr_i,
// fetch direction from PC Gen
input logic [63:0] fetch_address_i,
input logic fetch_valid_i,
input branchpredict_sbe branch_predict_i,
// instruction cache interface
output logic instr_req_o,
output logic [63:0] instr_addr_o,
@ -45,178 +36,46 @@ module if_stage (
input logic instr_rvalid_i,
input logic [31:0] instr_rdata_i,
// Output of IF Pipeline stage
output logic instr_valid_id_o, // instruction in IF/ID pipeline is valid
output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent to ID stage for decoding
output logic is_compressed_id_o, // compressed decoder thinks this is a compressed instruction
output logic illegal_c_insn_id_o, // compressed decoder thinks this is an invalid instruction
output logic [63:0] pc_if_o,
output logic [63:0] pc_id_o,
output fetch_entry fetch_entry_o,
output logic fetch_entry_valid_i, // instruction in IF/ID pipeline is valid
input logic instr_ack_i,
output exception ex_o
);
logic if_ready, if_valid;
logic branch_req;
logic valid;
logic prefetch_busy;
logic fetch_valid;
logic fetch_ready;
logic [31:0] fetch_rdata;
logic [63:0] fetch_addr;
// offset FSM
enum logic[0:0] {WAIT, IDLE} offset_fsm_cs, offset_fsm_ns;
logic [31:0] instr_decompressed;
logic illegal_c_insn;
logic instr_compressed_int;
logic clear_instr_valid_i;
assign pc_if_o = fetch_addr;
// id stage acknowledged
assign clear_instr_valid_i = id_ready_i;
// compressed instruction decoding, or more precisely compressed instruction
// expander
//
// since it does not matter where we decompress instructions, we do it here
// to ease timing closure
compressed_decoder compressed_decoder_i
(
.instr_i ( fetch_rdata ),
.instr_o ( instr_decompressed ),
.is_compressed_o ( instr_compressed_int ),
.illegal_instr_o ( illegal_c_insn )
);
// prefetch buffer, caches a fixed number of instructions
prefetch_buffer prefetch_buffer_i
(
.clk ( clk_i ),
.rst_n ( rst_ni ),
.req_i ( req_i ),
.branch_i ( branch_req ), // kill everything
.addr_i ( {fetch_addr_i[63:1], 1'b0} ),
.ready_i ( fetch_ready ),
.valid_o ( fetch_valid ),
.rdata_o ( fetch_rdata ),
.addr_o ( fetch_addr ),
// goes to instruction memory / instruction cache
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
// Pre-fetch buffer, caches a fixed number of instructions
prefetch_buffer prefetch_buffer_i (
.ready_i ( instr_ack_i ),
.valid_o ( fetch_entry_valid_i ),
// Prefetch Buffer Status
.busy_o ( prefetch_busy )
);
.busy_o ( prefetch_busy ),
.*
);
// offset FSM state
always_ff @(posedge clk_i, negedge rst_ni)
begin
if (rst_ni == 1'b0) begin
offset_fsm_cs <= IDLE;
end else begin
offset_fsm_cs <= offset_fsm_ns;
end
assign if_busy_o = prefetch_busy;
// --------------------------------------------------------------
// IF-ID pipeline registers, frozen when the ID stage is stalled
// --------------------------------------------------------------
always_ff @(posedge clk_i, negedge rst_ni) begin : IF_ID_PIPE_REGISTERS
if (~rst_ni) begin
ex_o <= '{default: 0};
end else begin
ex_o.cause <= 64'b0; // TODO: Output exception
ex_o.tval <= 64'b0; // TODO: Output exception
ex_o.valid <= 1'b0; //illegal_compressed_instr; // TODO: Output exception
end
// offset FSM state transition logic
always_comb
begin
offset_fsm_ns = offset_fsm_cs;
fetch_ready = 1'b0;
branch_req = 1'b0;
valid = 1'b0;
unique case (offset_fsm_cs)
// no valid instruction data for ID stage
// assume aligned
IDLE: begin
if (req_i) begin
branch_req = 1'b1;
offset_fsm_ns = WAIT;
end
end
// serving aligned 32 bit or 16 bit instruction, we don't know yet
WAIT: begin
if (fetch_valid) begin
valid = 1'b1; // an instruction is ready for ID stage
if (req_i && if_valid) begin
fetch_ready = 1'b1;
offset_fsm_ns = WAIT;
end
end
end
default: begin
offset_fsm_ns = IDLE;
end
endcase
// take care of control flow changes
if (set_pc_i) begin
valid = 1'b0;
// switch to new PC from ID stage
branch_req = 1'b1;
offset_fsm_ns = WAIT;
end
end
// IF-ID pipeline registers, frozen when the ID stage is stalled
always_ff @(posedge clk_i, negedge rst_ni)
begin : IF_ID_PIPE_REGISTERS
if (rst_ni == 1'b0)
begin
instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= '0;
illegal_c_insn_id_o <= 1'b0;
is_compressed_id_o <= 1'b0;
pc_id_o <= '0;
ex_o <= '{default: 0};
end
else
begin
if (if_valid)
begin
instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed;
illegal_c_insn_id_o <= illegal_c_insn;
is_compressed_id_o <= instr_compressed_int;
pc_id_o <= pc_if_o;
ex_o.cause <= 64'b0; // TODO: Output exception
ex_o.tval <= 64'b0; // TODO: Output exception
ex_o.valid <= 1'b0; // TODO: Output exception
end else if (clear_instr_valid_i) begin
instr_valid_id_o <= 1'b0;
end
end
end
assign if_ready = valid & id_ready_i;
assign if_valid = (~halt_if_i) & if_ready;
assign if_busy_o = prefetch_busy;
//-------------
// Assertions
//-------------
`ifndef SYNTHESIS
`ifndef VERILATOR
end
//-------------
// Assertions
//-------------
`ifndef SYNTHESIS
`ifndef VERILATOR
// there should never be a grant when there was no request
assert property (
@(posedge clk_i) (instr_gnt_i) |-> (instr_req_o) )
else $warning("There was a grant without a request");
`endif
`endif
`endif
`endif
endmodule

View file

@ -42,11 +42,17 @@ module issue_read_operands (
output fu_op operator_o,
output logic [63:0] operand_a_o,
output logic [63:0] operand_b_o,
output logic [63:0] operand_c_o,
output logic [63:0] imm_o, // output immediate for the LSU
output logic [TRANS_ID_BITS-1:0] trans_id_o,
output logic [63:0] pc_o,
output logic is_compressed_instr_o,
// ALU 1
input logic alu_ready_i, // FU is ready
output logic alu_valid_o, // Output is valid
// Branches and Jumps
output logic branch_valid_o, // this is a valid branch instruction
output branchpredict_sbe branch_predict_o,
// LSU
input logic lsu_ready_i, // FU is ready
output logic lsu_valid_o, // Output is valid
@ -66,34 +72,41 @@ module issue_read_operands (
logic [63:0] operand_a_regfile, operand_b_regfile; // operands coming from regfile
// output flipflop (ID <-> EX)
logic [63:0] operand_a_n, operand_a_q, operand_b_n, operand_b_q, imm_n, imm_q;
logic alu_valid_n, alu_valid_q;
logic mult_valid_n, mult_valid_q;
logic lsu_valid_n, lsu_valid_q;
logic csr_valid_n, csr_valid_q;
logic [63:0] operand_a_n, operand_a_q,
operand_b_n, operand_b_q,
operand_c_n, operand_c_q,
imm_n, imm_q;
logic alu_valid_n, alu_valid_q;
logic mult_valid_n, mult_valid_q;
logic lsu_valid_n, lsu_valid_q;
logic csr_valid_n, csr_valid_q;
logic branch_valid_n, branch_valid_q;
logic [TRANS_ID_BITS-1:0] trans_id_n, trans_id_q;
fu_op operator_n, operator_q;
// forwarding signals
logic forward_rs1, forward_rs2;
assign operand_a_o = operand_a_q;
assign operand_b_o = operand_b_q;
assign operator_o = operator_q;
assign alu_valid_o = alu_valid_q;
assign lsu_valid_o = lsu_valid_q;
assign csr_valid_o = csr_valid_q;
assign mult_valid_o = mult_valid_q;
assign trans_id_o = trans_id_q;
assign imm_o = imm_q;
// ID <-> EX registers
assign operand_a_o = operand_a_q;
assign operand_b_o = operand_b_q;
assign operand_c_o = operand_c_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 trans_id_o = trans_id_q;
assign imm_o = imm_q;
// ---------------
// Issue Stage
// ---------------
// We can issue an instruction if we do not detect that any other instruction is writing the same
// destination register.
// We also need to check if there is an unresolved branch in the scoreboard.
always_comb begin : issue
always_comb begin : issue_scoreboard
// default assignment
issue_ack_o = 1'b0;
// check that we didn't stall, that the instruction we got is valid
@ -105,6 +118,11 @@ module issue_read_operands (
if (rd_clobber_i[issue_instr_i.rd] == NONE) begin
issue_ack_o = 1'b1;
end
// or check that the target destination register will be written in this cycle by the
// commit stage
if (we_a_i && waddr_a_i == issue_instr_i.rd) begin
issue_ack_o = 1'b1;
end
end
// we can also issue the instruction under the following two circumstances:
// we can do this even if we are stalled or no functional unit is ready (as we don't need one)
@ -127,7 +145,8 @@ module issue_read_operands (
unique case (issue_instr_i.fu)
NONE:
fu_busy = 1'b0;
ALU:
ALU, CTRL_FLOW: // control flow instruction also need the ALU
// and they are always ready if the ALU is ready
fu_busy = ~alu_ready_i;
MULT:
fu_busy = ~mult_ready_i;
@ -175,10 +194,16 @@ module issue_read_operands (
end
end
// Forwarding/Output MUX
always_comb begin : forwarding
always_comb begin : forwarding_operand_select
// default is regfile
operand_a_n = operand_a_regfile;
operand_b_n = operand_b_regfile;
// set PC as default operand c
operand_c_n = issue_instr_i.pc;
// immediates are the third operands in the store case
imm_n = issue_instr_i.result;
trans_id_n = issue_instr_i.trans_id;
operator_n = issue_instr_i.op;
// or should we forward
if (forward_rs1) begin
@ -203,21 +228,42 @@ module issue_read_operands (
if (issue_instr_i.use_imm && ~(issue_instr_i.op inside {SD, SW, SH, SB})) begin
operand_b_n = issue_instr_i.result;
end
// immediates are the third operands in the store case
imm_n = issue_instr_i.result;
trans_id_n = issue_instr_i.trans_id;
operator_n = issue_instr_i.op;
// special assignments in the JAL and JALR case
case (issue_instr_i.op)
// re-write the operator since
// we need the ALU for addition
JAL: begin
operator_n = ADD;
// output 4 as operand b as we
// need to save PC + 4 or in case of a compressed instruction PC + 4
operand_b_n = (issue_instr_i.is_compressed) ? 64'h2 : 64'h4;
end
JALR: begin
operator_n = ADD;
// output 4 as operand b as we
// need to save PC + 4 or in case of a compressed instruction PC + 4
operand_b_n = (issue_instr_i.is_compressed) ? 64'h2 : 64'h4;
// get RS1 as operand C
operand_c_n = operand_a_regfile;
// forward rs1
if (forward_rs1) begin
operand_c_n = rs1_i;
end
end
endcase
end
// FU select
always_comb begin : unit_valid
alu_valid_n = 1'b0;
lsu_valid_n = 1'b0;
mult_valid_n = 1'b0;
csr_valid_n = 1'b0;
alu_valid_n = 1'b0;
lsu_valid_n = 1'b0;
mult_valid_n = 1'b0;
csr_valid_n = 1'b0;
branch_valid_n = 1'b0;
// Exception pass through
// if an exception has occurred simply pass it through
// we do not want to issue this instruction
if (~issue_instr_i.ex.valid && issue_instr_valid_i) begin
if (~issue_instr_i.ex.valid && issue_instr_valid_i && issue_ack_o) begin
case (issue_instr_i.fu)
ALU:
alu_valid_n = 1'b1;
@ -227,6 +273,10 @@ module issue_read_operands (
lsu_valid_n = 1'b1;
CSR:
csr_valid_n = 1'b1;
CTRL_FLOW: begin
alu_valid_n = 1'b1;
branch_valid_n = 1'b1;
end
default: begin
end
@ -257,23 +307,35 @@ module issue_read_operands (
// Registers
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
operand_a_q <= '{default: 0};
operand_b_q <= '{default: 0};
alu_valid_q <= 1'b0;
mult_valid_q <= 1'b0;
lsu_valid_q <= 1'b0;
csr_valid_q <= 1'b0;
operator_q <= ADD;
trans_id_q <= 5'b0;
operand_a_q <= '{default: 0};
operand_b_q <= '{default: 0};
operand_c_q <= '{default: 0};
imm_q <= 64'b0;
alu_valid_q <= 1'b0;
branch_valid_q <= 1'b0;
mult_valid_q <= 1'b0;
lsu_valid_q <= 1'b0;
csr_valid_q <= 1'b0;
operator_q <= ADD;
trans_id_q <= 5'b0;
pc_o <= 64'b0;
is_compressed_instr_o <= 1'b0;
branch_predict_o <= '{default: 0};
end else begin
operand_a_q <= operand_a_n;
operand_b_q <= operand_b_n;
alu_valid_q <= alu_valid_n;
mult_valid_q <= mult_valid_n;
lsu_valid_q <= lsu_valid_n;
csr_valid_q <= csr_valid_n;
operator_q <= operator_n;
trans_id_q <= trans_id_n;
operand_a_q <= operand_a_n;
operand_b_q <= operand_b_n;
operand_c_q <= operand_c_n;
imm_q <= imm_n;
alu_valid_q <= alu_valid_n;
branch_valid_q <= branch_valid_n;
mult_valid_q <= mult_valid_n;
lsu_valid_q <= lsu_valid_n;
csr_valid_q <= csr_valid_n;
operator_q <= operator_n;
trans_id_q <= trans_id_n;
pc_o <= issue_instr_i.pc;
is_compressed_instr_o <= issue_instr_i.is_compressed;
branch_predict_o <= issue_instr_i.bp;
end
end
endmodule

View file

@ -170,7 +170,7 @@ module lsu #(
.INSTR_TLB_ENTRIES ( 16 ),
.DATA_TLB_ENTRIES ( 16 ),
.ASID_WIDTH ( ASID_WIDTH )
) i_mmu (
) mmu_i (
.lsu_req_i ( translation_req ),
.lsu_vaddr_i ( vaddr ),
.lsu_valid_o ( translation_valid ),
@ -353,32 +353,32 @@ module lsu #(
// essentially the same part as in IDLE but we can't accept a new store
// as the store could immediately be performed and we would collide on the
// trans id part (e.g.: a structural hazard)
if (op == LD_OP & lsu_valid_i) begin
translation_req = 1'b1;
// we can never handle a load in a single cycle
// but at least on a tlb hit we can output it to the memory
if (translation_valid) begin
// check if the address is in the store buffer otherwise we need
// to wait until the store buffer has cleared its entry
if (~address_match) begin
// lets request this read
data_req_i[1] = 1'b1;
// we already got a grant here so lets wait for the rvalid
if (data_gnt_o[1]) begin
NS = LOAD_WAIT_RVALID;
end else begin // we didn't get a grant so wait for it in a separate stage
NS = LOAD_WAIT_GNT;
end
end
end else begin// otherwise we need to wait for the translation
NS = LOAD_WAIT_TRANSLATION;
end
// STORE
end else if (op == ST_OP & lsu_valid_i) begin
NS = STORE;
end else begin
// if (op == LD_OP & lsu_valid_i) begin
// translation_req = 1'b1;
// // we can never handle a load in a single cycle
// // but at least on a tlb hit we can output it to the memory
// if (translation_valid) begin
// // check if the address is in the store buffer otherwise we need
// // to wait until the store buffer has cleared its entry
// if (~address_match) begin
// // lets request this read
// data_req_i[1] = 1'b1;
// // we already got a grant here so lets wait for the rvalid
// if (data_gnt_o[1]) begin
// NS = LOAD_WAIT_RVALID;
// end else begin // we didn't get a grant so wait for it in a separate stage
// NS = LOAD_WAIT_GNT;
// end
// end
// end else begin// otherwise we need to wait for the translation
// NS = LOAD_WAIT_TRANSLATION;
// end
// // STORE
// end else if (op == ST_OP & lsu_valid_i) begin
// NS = STORE;
// end else begin
NS = IDLE;
end
// end
end else begin
// and stall

View file

@ -20,34 +20,29 @@
import ariane_pkg::*;
module pcgen (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i,
input logic [63:0] pc_if_i,
input mispredict mispredict_i, // from controller signaling a mispredict -> update BTB
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// control signals
input logic fetch_enable_i,
input logic flush_i,
input logic if_ready_i,
input branchpredict resolved_branch_i, // from controller signaling a branch_predict -> update BTB
// to IF
output logic [63:0] pc_if_o, // new PC
output logic set_pc_o, // request the PC to be set to pc_if_o
output logic is_branch_o, // to check if we mispredicted we need to save whether this was a branch or not
output logic [63:0] fetch_address_o, // new PC (address because we do not distinguish instructions)
output logic fetch_valid_o, // the PC (address) is valid
output branchpredict_sbe branch_predict_o, // pass on the information if this is speculative
// global input
input logic [63:0] boot_addr_i,
input logic [63:0] boot_addr_i,
// CSR input
input logic [63:0] epc_i, // return from exception
input logic [63:0] trap_vector_base_i, // base of trap vector
input exception ex_i // exception in - from commit
input logic [63:0] epc_i, // return from exception
input logic [63:0] trap_vector_base_i, // base of trap vector
input exception ex_i // exception in - from commit
);
logic [63:0] branch_target_address;
logic predict_taken;
logic [63:0] npc_n, npc_q;
logic is_branch;
logic is_branch_n, is_branch_q;
logic set_pc_n, set_pc_q;
logic [63:0] npc_n, npc_q;
branchpredict_sbe branch_predict_btb;
assign pc_if_o = npc_q;
assign set_pc_o = set_pc_q;
assign is_branch_o = is_branch_q;
assign fetch_address_o = npc_q;
btb #(
.NR_ENTRIES(64),
@ -55,58 +50,63 @@ module pcgen (
)
btb_i
(
.vpc_i ( pc_if_i ),
.mispredict_i ( mispredict_i ),
.is_branch_o ( is_branch ),
.predict_taken_o ( predict_taken ),
.branch_target_address_o ( branch_target_address ),
// Use the PC from last cycle to perform branch lookup for the current cycle
.vpc_i ( npc_q ),
.branch_predict_i ( resolved_branch_i ), // update port
.branch_predict_o ( branch_predict_btb ), // read port
.*
);
// TODO: on flush output exception or other things but do not take branch
// -------------------
// Next PC
// -------------------
// next PC (npc) can come from:
// next PC (NPC) can come from:
// 1. Exception
// 2. Return from exception
// 3. Predicted branch
// 4. Debug
// 5. Boot address
always_comb begin : npc_select
// default assignment
npc_n = npc_q;
set_pc_n = 1'b0;
is_branch_n = is_branch;
branch_predict_o = branch_predict_btb;
fetch_valid_o = 1'b1;
// 0. Default assignment
// default is a consecutive PC
if (if_ready_i && fetch_enable_i)
npc_n = {npc_q[62:2], 2'b0} + 64'h4;
else // or keep the PC stable if IF is not ready
npc_n = npc_q;
// 4. Predict taken
if (predict_taken) begin
npc_n = branch_target_address;
if (branch_predict_btb.valid && branch_predict_btb.predict_taken) begin
npc_n = branch_predict_btb.predict_address;
end
// 1.Debug
// 3. Control flow change request
if (resolved_branch_i.is_mispredict) begin
// we already got the correct target address
npc_n = resolved_branch_i.target_address;
end
// 2. Exception
if (ex_i.valid) begin
npc_n = trap_vector_base_i;
is_branch_n = 1'b0;
npc_n = trap_vector_base_i;
branch_predict_o.valid = 1'b0;
end
// 3. Return from exception
// fetch enable
if (!fetch_enable_i) begin
fetch_valid_o = 1'b0;
end
end
// -------------------
// Sequential Process
// -------------------
// PCGEN -> IF Register
// PCGEN -> IF Pipeline Stage
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
npc_q <= 64'b0;
set_pc_q <= 1'b0;
is_branch_q <= 1'b0;
npc_q <= boot_addr_i;
end else begin
npc_q <= npc_n;
set_pc_q <= set_pc_n;
is_branch_q <= is_branch_n;
end
end

View file

@ -21,28 +21,29 @@
// long critical paths to the instruction cache //
// //
////////////////////////////////////////////////////////////////////////////////
import ariane_pkg::*;
module prefetch_buffer
(
input logic clk,
input logic rst_n,
input logic clk_i,
input logic rst_ni,
input logic flush_i,
input logic req_i,
input logic branch_i,
input logic [63:0] addr_i,
input logic ready_i,
output logic valid_o,
output logic [63:0] addr_o,
output logic [31:0] rdata_o,
// input side
input logic [63:0] fetch_address_i,
input logic fetch_valid_i,
input branchpredict_sbe branch_predict_i,
// output side
input logic ready_i,
output logic valid_o,
output fetch_entry fetch_entry_o,
// goes to instruction memory / instruction cache
output logic instr_req_o,
input logic instr_gnt_i,
output logic [63:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_rvalid_i,
output logic instr_req_o,
input logic instr_gnt_i,
output logic [63:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_rvalid_i,
// Prefetch Buffer Status
output logic busy_o
@ -50,180 +51,148 @@ module prefetch_buffer
enum logic [1:0] {IDLE, WAIT_GNT, WAIT_RVALID, WAIT_ABORTED } CS, NS;
logic [63:0] instr_addr_q, fetch_addr;
logic addr_valid;
logic fifo_valid;
logic fifo_ready;
logic fifo_clear;
logic valid_stored;
logic [63:0] fetch_address;
logic addr_valid;
logic [63:0] instr_addr_q;
logic fifo_valid;
logic fifo_ready;
logic fifo_clear;
branchpredict_sbe branchpredict_q;
//---------------------------------
// Prefetch buffer status
//---------------------------------
assign busy_o = (CS != IDLE) || instr_req_o;
// we are busy if we are either waiting for a grant
// or if the fifo is full
assign busy_o = (CS inside {WAIT_GNT, WAIT_ABORTED} && !instr_req_o) || !fifo_ready;
assign fetch_address = {fetch_address_i[63:2], 2'b0};
//---------------------------------
// Fetch FIFO
// consumes addresses and rdata
//---------------------------------
fetch_fifo fifo_i
(
.clk ( clk ),
.rst_n ( rst_n ),
fetch_fifo fifo_i (
.branch_predict_i ( branchpredict_q ),
.in_addr_i ( instr_addr_q ),
.in_rdata_i ( instr_rdata_i ),
.in_valid_i ( fifo_valid ),
.in_ready_o ( fifo_ready ),
.clear_i ( fifo_clear ),
.out_valid_o ( valid_o ),
.out_ready_i ( ready_i ),
.*
);
.in_addr_i ( instr_addr_q ),
.in_rdata_i ( instr_rdata_i ),
.in_valid_i ( fifo_valid ),
.in_ready_o ( fifo_ready ),
.out_valid_o ( valid_o ),
.out_ready_i ( ready_i ),
.out_rdata_o ( rdata_o ),
.out_addr_o ( addr_o ),
.out_valid_stored_o ( valid_stored )
);
//---------------
// Fetch address
//---------------
assign fetch_addr = {instr_addr_q[63:2], 2'b00} + 64'd4;
always_comb
begin
fifo_clear = branch_i;
end
//-------------------------
//--------------------------------------------------
// Instruction fetch FSM
// deals with instruction memory / instruction cache
//-------------------------
always_comb
begin
//--------------------------------------------------
always_comb begin
instr_req_o = 1'b0;
instr_addr_o = fetch_addr;
instr_addr_o = fetch_address;
fifo_valid = 1'b0;
addr_valid = 1'b0;
NS = CS;
unique case(CS)
// default state, not waiting for requested data
IDLE:
begin
instr_addr_o = fetch_addr;
instr_req_o = 1'b0;
// default state, not waiting for requested data
IDLE: begin
instr_addr_o = fetch_address;
instr_req_o = 1'b0;
if (branch_i)
instr_addr_o = addr_i;
if (req_i & (fifo_ready | branch_i )) begin
instr_req_o = 1'b1;
addr_valid = 1'b1;
// make a new request
if (fifo_ready && fetch_valid_i) begin
instr_req_o = 1'b1;
addr_valid = 1'b1;
if(instr_gnt_i) //~> granted request
NS = WAIT_RVALID;
else begin //~> got a request but no grant
NS = WAIT_GNT;
end
end
end // case: IDLE
if(instr_gnt_i) //~> granted request
// we have one outstanding rvalid: wait for it
if (flush_i)
NS = WAIT_ABORTED;
else
NS = WAIT_RVALID;
else begin //~> got a request but no grant
NS = WAIT_GNT;
end
end
end // case: IDLE
// we sent a request but did not yet get a grant
WAIT_GNT:
begin
instr_addr_o = instr_addr_q;
instr_req_o = 1'b1;
// we sent a request but did not yet get a grant
WAIT_GNT: begin
instr_addr_o = {instr_addr_q[63:2], 2'b0};
instr_req_o = 1'b1;
if (branch_i) begin
instr_addr_o = addr_i;
addr_valid = 1'b1;
end
if(instr_gnt_i)
// we have one outstanding rvalid: wait for it
if (flush_i)
NS = WAIT_ABORTED;
else
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
end // case: WAIT_GNT
if(instr_gnt_i)
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
end // case: WAIT_GNT
// we wait for rvalid, after that we are ready to serve a new request
WAIT_RVALID: begin
instr_addr_o = fetch_address;
// prepare for next request
if (fifo_ready && fetch_valid_i) begin
// wait for the valid signal
if (instr_rvalid_i) begin
instr_req_o = 1'b1;
fifo_valid = 1'b1;
addr_valid = 1'b1;
// we wait for rvalid, after that we are ready to serve a new request
WAIT_RVALID: begin
instr_addr_o = fetch_addr;
if (branch_i)
instr_addr_o = addr_i;
if (req_i & (fifo_ready | branch_i)) begin
// prepare for next request
if (instr_rvalid_i) begin
instr_req_o = 1'b1;
fifo_valid = 1'b1;
addr_valid = 1'b1;
if (instr_gnt_i) begin
NS = WAIT_RVALID;
if (instr_gnt_i) begin
// we have one outstanding rvalid: wait for it
// if we are receiving a data item during a flush ignore it
if (flush_i)
NS = WAIT_ABORTED;
else
NS = WAIT_RVALID;
end else begin
NS = WAIT_GNT;
end
end
end else begin
NS = WAIT_GNT;
// we are requested to abort our current request
// we didn't get an rvalid yet, so wait for it
if (flush_i) begin
NS = WAIT_ABORTED;
end
// just wait for rvalid and go back to IDLE, no new request
if (instr_rvalid_i) begin
// if we are receiving a data item during a flush ignore it
fifo_valid = 1'b1;
NS = IDLE;
end
end
end else begin
// we are requested to abort our current request
// we didn't get an rvalid yet, so wait for it
if (branch_i) begin
addr_valid = 1'b1;
NS = WAIT_ABORTED;
end // case: WAIT_RVALID
// our last request was aborted, but we didn't yet get a rvalid and
// there was no new request sent yet we assume that req_i is set to high
WAIT_ABORTED: begin
instr_addr_o = {fetch_address_i[63:2], 2'b0};
if (instr_rvalid_i) begin
// we are aborting this instruction so don't tell the FIFO it is valid
fifo_valid = 1'b0;
instr_req_o = 1'b1;
if (instr_gnt_i) begin
// we have one outstanding rvalid
if (flush_i)
NS = WAIT_ABORTED;
else
NS = WAIT_RVALID;
end else begin
NS = WAIT_GNT;
end
end
end
end else begin
// just wait for rvalid and go back to IDLE, no new request
if (instr_rvalid_i) begin
fifo_valid = 1'b1;
NS = IDLE;
end
end
end // case: WAIT_RVALID
// our last request was aborted, but we didn't yet get a rvalid and
// there was no new request sent yet
// we assume that req_i is set to high
WAIT_ABORTED: begin
instr_addr_o = instr_addr_q;
if (branch_i) begin
instr_addr_o = addr_i;
addr_valid = 1'b1;
end
if (instr_rvalid_i) begin
instr_req_o = 1'b1;
// no need to send address, already done in WAIT_RVALID
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else begin
NS = WAIT_GNT;
end
default: begin
NS = IDLE;
instr_req_o = 1'b0;
end
end
default:
begin
NS = IDLE;
instr_req_o = 1'b0;
end
endcase
end
@ -231,19 +200,17 @@ module prefetch_buffer
// Registers
//-------------
always_ff @(posedge clk, negedge rst_n)
always_ff @(posedge clk_i, negedge rst_ni)
begin
if(rst_n == 1'b0)
begin
if (~rst_ni) begin
CS <= IDLE;
instr_addr_q <= '0;
end
else
begin
branchpredict_q <= '{default: 0};
end else begin
CS <= NS;
if (addr_valid) begin
instr_addr_q <= instr_addr_o;
instr_addr_q <= fetch_address_i;
branchpredict_q <= branch_predict_i;
end
end
end

View file

@ -29,7 +29,8 @@ module scoreboard #(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
output logic full_o, // We can't take anymore data
input logic flush_i,
input logic flush_i, // flush whole scoreboard
input logic flush_unissued_instr_i,
// list of clobbered registers to issue stage
output fu_t [31:0] rd_clobber_o,
@ -50,6 +51,7 @@ module scoreboard #(
// we can always put this instruction to the to p unless we signal with asserted full_o
input dtype decoded_instr_i,
input logic decoded_instr_valid_i,
output logic decoded_instr_ack_o,
// instruction to issue logic, if issue_instr_valid and issue_ready is asserted, advance the issue pointer
output dtype issue_instr_o,
@ -100,6 +102,8 @@ always_comb begin : clobber_output
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q && i[BITS_ENTRIES-1:0] < issue_pointer_q)
rd_clobber_o[mem_q[i].rd] = mem_q[i].fu;
end
end else if (commit_pointer_q == issue_pointer_q) begin // everything committed
rd_clobber_o = '{default: NONE};
end else begin // the issue pointer has overflowed, invert logic, depicted on the right
for (int unsigned i = 0; i < NR_ENTRIES; i++) begin
if (i[BITS_ENTRIES-1:0] >= commit_pointer_q || i[BITS_ENTRIES-1:0] < issue_pointer_q)
@ -173,14 +177,17 @@ end
// write-back instruction: update value of RD register in scoreboard
always_comb begin : push_instruction_and_wb
// default assignment
top_pointer_n = top_pointer_q;
mem_n = mem_q;
top_pointer_n = top_pointer_q;
mem_n = mem_q;
// acknowledge decoded instruction
decoded_instr_ack_o = 1'b0;
// if we are not full we can push a new instruction
if (~full_o && decoded_instr_valid_i) begin
mem_n[$unsigned(top_pointer_q)] = decoded_instr_i;
// label the transaction ID with the current top pointer
mem_n[$unsigned(top_pointer_q)].trans_id = top_pointer_q;
top_pointer_n = top_pointer_q + 1;
top_pointer_n = top_pointer_q + 1;
decoded_instr_ack_o = 1'b1;
end
// write back:
@ -197,11 +204,11 @@ always_comb begin : push_instruction_and_wb
end
end
end
// flush signal
if (flush_i)
mem_n = '{default: 0};
// flush all instructions which are not issued, e.g. set the top pointer back to the issue pointer
// -> everything we decoded so far was garbage
if (flush_unissued_instr_i) begin
top_pointer_n = issue_pointer_q;
end
end
// issue instruction: advance the issue pointer
@ -209,7 +216,7 @@ always_comb begin : issue_instruction
// provide a combinatorial path in case the scoreboard is empty
if (top_pointer_q == issue_pointer_q) begin
if (top_pointer_q == issue_pointer_q && ~full_o) begin
issue_instr_o = decoded_instr_i;
issue_instr_o.trans_id = issue_pointer_q;
issue_instr_valid_o = decoded_instr_valid_i;
@ -218,11 +225,15 @@ always_comb begin : issue_instruction
issue_instr_o = mem_q[$unsigned(issue_pointer_q)];
// we have not reached the top of the buffer
// issue pointer has overflowed
if (issue_pointer_q <= commit_pointer_q) begin
if (issue_pointer_q < commit_pointer_q) begin
if (issue_pointer_q < top_pointer_q)
issue_instr_valid_o = 1'b1;
else
issue_instr_valid_o = 1'b0;
end else if (issue_pointer_q == commit_pointer_q) begin
// commit and issue pointer are the same, so we are waiting
// for instructions to be written back
issue_instr_valid_o = 1'b0;
end else begin // issue pointer has not overflowed
if (pointer_overflow)
issue_instr_valid_o = 1'b1;
@ -240,6 +251,10 @@ always_comb begin : issue_instruction
issue_pointer_n = issue_pointer_q + 1;
end
// if we are flushing we should not issue the current instruction
if (flush_unissued_instr_i)
issue_instr_valid_o = 1'b0;
end
// commit instruction: remove from scoreboard, advance pointer
@ -260,20 +275,28 @@ always_ff @(posedge clk_i or negedge rst_ni) begin : sequential
commit_pointer_q <= '{default: 0};
top_pointer_q <= '{default: 0};
top_pointer_qq <= '{default: 0};
mem_q <= '{default: 0};
for (int i = 0; i < NR_ENTRIES; i++) begin
mem_q[i] <= {$bits(scoreboard_entry){1'b0}};
end
end else if (flush_i) begin // reset pointers on flush
// flush signal, e.g.: flush everything we need to backtrack after an exception
issue_pointer_q <= '{default: 0};
commit_pointer_q <= '{default: 0};
top_pointer_q <= '{default: 0};
top_pointer_qq <= '{default: 0};
mem_q <= '{default: 0};
for (int i = 0; i < NR_ENTRIES; i++) begin
mem_q[i] <= {$bits(scoreboard_entry){1'b0}};
end
end else begin
issue_pointer_q <= issue_pointer_n;
commit_pointer_q <= commit_pointer_n;
top_pointer_q <= top_pointer_n;
mem_q <= mem_n;
if (decoded_instr_valid_i) // only advance if we decoded instruction
top_pointer_qq <= top_pointer_q;
if (decoded_instr_valid_i && ~full_o) // only advance if we decoded instruction and we are not full
if (flush_unissued_instr_i)
top_pointer_qq <= top_pointer_n;
else
top_pointer_qq <= top_pointer_q;
end
end

View file

@ -61,16 +61,13 @@ module tlb #(
logic [8:0] vpn0, vpn1, vpn2;
logic [TLB_ENTRIES-1:0] lu_hit; // to replacement logic
logic [TLB_ENTRIES-1:0] replace_en; // replace the following entry, set by replacement strategy
// register signals
logic lu_access_q;
logic [63:0] lu_vaddr_q;
//-------------
// Translation
//-------------
always_comb begin : translation
vpn0 = lu_vaddr_q[20:12];
vpn1 = lu_vaddr_q[29:21];
vpn2 = lu_vaddr_q[38:30];
vpn0 = lu_vaddr_i[20:12];
vpn1 = lu_vaddr_i[29:21];
vpn2 = lu_vaddr_i[38:30];
// default assignment
lu_hit = '{default: 0};
@ -168,7 +165,7 @@ module tlb #(
// endcase
for (int unsigned i = 0; i < TLB_ENTRIES; i++) begin
// we got a hit so update the pointer as it was least recently used
if (lu_hit[i] & lu_access_q) begin
if (lu_hit[i] & lu_access_i) begin
// Set the nodes to the values we would expect
for (int unsigned lvl = 0; lvl < $clog2(TLB_ENTRIES); lvl++) begin
automatic int unsigned idx_base = $unsigned((2**lvl)-1);
@ -225,16 +222,6 @@ module tlb #(
plru_tree_q <= plru_tree_n;
end
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_
if(~rst_ni) begin
lu_access_q <= 1'b0;
lu_vaddr_q <= 64'b0;
end else begin
lu_access_q <= lu_access_i;
lu_vaddr_q <= lu_vaddr_i;
end
end
//--------------
// Sanity checks
//--------------

View file

@ -0,0 +1,311 @@
class instruction_trace_item;
time simtime;
integer cycles;
logic [31:0] pc;
logic [31:0] instr;
string str;
function new ();
endfunction
function string regAddrToStr(logic [5:0] addr);
return $sformatf("x%0d", addr);
endfunction
function string printInstr(logic [63:0] instr);
string s;
casex (instr)
// Aliases
32'h00_00_00_13: s = this.printMnemonic("nop");
// Regular opcodes
INSTR_LUI: s = this.printUInstr("lui");
INSTR_AUIPC: s = this.printUInstr("auipc");
INSTR_JAL: s = this.printUJInstr("jal");
INSTR_JALR: s = this.printIInstr("jalr");
// BRANCH
INSTR_BEQ: s = this.printSBInstr("beq");
INSTR_BNE: s = this.printSBInstr("bne");
INSTR_BLT: s = this.printSBInstr("blt");
INSTR_BGE: s = this.printSBInstr("bge");
INSTR_BLTU: s = this.printSBInstr("bltu");
INSTR_BGEU: s = this.printSBInstr("bgeu");
// OPIMM
INSTR_ADDI: s = this.printIInstr("addi");
INSTR_SLTI: s = this.printIInstr("slti");
INSTR_SLTIU: s = this.printIInstr("sltiu");
INSTR_XORI: s = this.printIInstr("xori");
INSTR_ORI: s = this.printIInstr("ori");
INSTR_ANDI: s = this.printIInstr("andi");
INSTR_SLLI: s = this.printIuInstr("slli");
INSTR_SRLI: s = this.printIuInstr("srli");
INSTR_SRAI: s = this.printIuInstr("srai");
// OP
INSTR_ADD: s = this.printRInstr("add");
INSTR_SUB: s = this.printRInstr("sub");
INSTR_SLL: s = this.printRInstr("sll");
INSTR_SLT: s = this.printRInstr("slt");
INSTR_SLTU: s = this.printRInstr("sltu");
INSTR_XOR: s = this.printRInstr("xor");
INSTR_SRL: s = this.printRInstr("srl");
INSTR_SRA: s = this.printRInstr("sra");
INSTR_OR: s = this.printRInstr("or");
INSTR_AND: s = this.printRInstr("and");
// FENCE
INSTR_FENCE: s = this.printMnemonic("fence");
INSTR_FENCEI: s = this.printMnemonic("fencei");
// SYSTEM (CSR man ipulation)
INSTR_CSRRW: s = this.printCSRInstr("csrrw");
INSTR_CSRRS: s = this.printCSRInstr("csrrs");
INSTR_CSRRC: s = this.printCSRInstr("csrrc");
INSTR_CSRRWI: s = this.printCSRInstr("csrrwi");
INSTR_CSRRSI: s = this.printCSRInstr("csrrsi");
INSTR_CSRRCI: s = this.printCSRInstr("csrrci");
// SYSTEM (others)
INSTR_ECALL: s = this.printMnemonic("ecall");
INSTR_EBREAK: s = this.printMnemonic("ebreak");
INSTR_ERET: s = this.printMnemonic("eret");
INSTR_WFI: s = this.printMnemonic("wfi");
// opcodes with custom decoding
{25'b?, OPCODE_LOAD}: s = this.printLoadInstr();
{25'b?, OPCODE_STORE}: s = this.printStoreInstr();
default: s = this.printMnemonic("INVALID");
endcase
return s;
// $fwrite(f, "%t %15d %h %h %-36s", simtime,
// cycles,
// pc,
// instr,
// str);
// foreach(regs_write[i]) begin
// if (regs_write[i].addr != 0)
// $fwrite(f, " %s=%08x", regAddrToStr(regs_write[i].addr), regs_write[i].value);
// end
// foreach(regs_read[i]) begin
// if (regs_read[i].addr != 0)
// $fwrite(f, " %s:%08x", regAddrToStr(regs_read[i].addr), regs_read[i].value);
// end
// if (mem_access.size() > 0) begin
// mem_acc = mem_access.pop_front();
// $fwrite(f, " PA:%08x", mem_acc.addr);
// end
// $fwrite(f, "\n");
endfunction
function string printMnemonic(input string mnemonic);
return mnemonic;
endfunction // printMnemonic
function string printRInstr(input string mnemonic);
// return $sformatf("%-16s x%0d, x%0d, x%0d", mnemonic, rd, rs1, rs2);
return mnemonic;
endfunction // printRInstr
function string printIInstr(input string mnemonic);
// begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, x%0d, %0d", mnemonic, rd, rs1, $signed(imm_i_type));
// end
return mnemonic;
endfunction // printIInstr
function string printIuInstr(input string mnemonic);
// begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, x%0d, 0x%0x", mnemonic, rd, rs1, imm_i_type);
// end
return mnemonic;
endfunction // printIuInstr
function string printSBInstr(input string mnemonic);
// begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, x%0d, 0x%0x", mnemonic, rd, rs1, imm_i_type);
// end
return mnemonic;
endfunction // printIuInstr
function string printUInstr(input string mnemonic);
// begin
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, 0x%0h", mnemonic, rd, {imm_u_type[31:12], 12'h000});
// end
return mnemonic;
endfunction // printUInstr
function string printUJInstr(input string mnemonic);
// begin
// regs_write.push_back('{rd, 'x});
// str = $sformatf("%-16s x%0d, %0d", mnemonic, rd, $signed(imm_uj_type));
// end
return mnemonic;
endfunction // printUJInstr
function string printCSRInstr(input string mnemonic);
// logic [11:0] csr;
// begin
// csr = instr[31:20];
// regs_write.push_back('{rd, 'x});
// if (instr[14] == 1'b0) begin
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, x%0d, 0x%h", mnemonic, rd, rs1, csr);
// end else begin
// str = $sformatf("%-16s x%0d, 0x%h, 0x%h", mnemonic, rd, imm_z_type, csr);
// end
// end
return mnemonic;
endfunction // printCSRInstr
function string printLoadInstr();
// string mnemonic;
// logic [2:0] size;
// begin
// // detect reg-reg load and find size
// size = instr[14:12];
// if (instr[14:12] == 3'b111)
// size = instr[30:28];
// case (size)
// 3'b000: mnemonic = "lb";
// 3'b001: mnemonic = "lh";
// 3'b010: mnemonic = "lw";
// 3'b100: mnemonic = "lbu";
// 3'b101: mnemonic = "lhu";
// 3'b110: mnemonic = "p.elw";
// 3'b011,
// 3'b111: begin
// printMnemonic("INVALID");
// return;
// end
// endcase
// regs_write.push_back('{rd, 'x});
// if (instr[14:12] != 3'b111) begin
// // regular load
// if (instr[6:0] != OPCODE_LOAD_POST) begin
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, %0d(x%0d)", mnemonic, rd, $signed(imm_i_type), rs1);
// end else begin
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, %0d(x%0d!)", mnemonic, rd, $signed(imm_i_type), rs1);
// end
// end else begin
// // reg-reg load
// if (instr[6:0] != OPCODE_LOAD_POST) begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, x%0d(x%0d)", mnemonic, rd, rs2, rs1);
// end else begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, x%0d(x%0d!)", mnemonic, rd, rs2, rs1);
// end
// end
// end
return "";
endfunction
function string printStoreInstr();
// string mnemonic;
// begin
// case (instr[13:12])
// 2'b00: mnemonic = "sb";
// 2'b01: mnemonic = "sh";
// 2'b10: mnemonic = "sw";
// 2'b11: begin
// printMnemonic("INVALID");
// return;
// end
// endcase
// if (instr[14] == 1'b0) begin
// // regular store
// if (instr[6:0] != OPCODE_STORE_POST) begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("%-16s x%0d, %0d(x%0d)", mnemonic, rs2, $signed(imm_s_type), rs1);
// end else begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, %0d(x%0d!)", mnemonic, rs2, $signed(imm_s_type), rs1);
// end
// end else begin
// // reg-reg store
// if (instr[6:0] != OPCODE_STORE_POST) begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs3, rs3_value});
// regs_read.push_back('{rs1, rs1_value});
// str = $sformatf("p.%-14s x%0d, x%0d(x%0d)", mnemonic, rs2, rs3, rs1);
// end else begin
// regs_read.push_back('{rs2, rs2_value});
// regs_read.push_back('{rs3, rs3_value});
// regs_read.push_back('{rs1, rs1_value});
// regs_write.push_back('{rs1, 'x});
// str = $sformatf("p.%-14s x%0d, x%0d(x%0d!)", mnemonic, rs2, rs3, rs1);
// end
// end
// end
return "";
endfunction // printSInstr
function string printMulInstr();
// string mnemonic;
// string str_suf;
// string str_imm;
// string str_asm;
// begin
// // always read rs1 and rs2 and write rd
// regs_read.push_back('{rs1, rs1_value});
// regs_read.push_back('{rs2, rs2_value});
// regs_write.push_back('{rd, 'x});
// if (instr[12])
// regs_read.push_back('{rd, rs3_value});
// case ({instr[31:30], instr[14]})
// 3'b000: str_suf = "u";
// 3'b001: str_suf = "uR";
// 3'b010: str_suf = "hhu";
// 3'b011: str_suf = "hhuR";
// 3'b100: str_suf = "s";
// 3'b101: str_suf = "sR";
// 3'b110: str_suf = "hhs";
// 3'b111: str_suf = "hhsR";
// endcase
// if (instr[12])
// mnemonic = "p.mac";
// else
// mnemonic = "p.mul";
// if (imm_s3_type[4:0] != 5'b00000)
// str_asm = $sformatf("%s%sN", mnemonic, str_suf);
// else
// str_asm = $sformatf("%s%s", mnemonic, str_suf);
// if (instr[29:25] != 5'b00000)
// str = $sformatf("%-16s x%0d, x%0d, x%0d, %0d", str_asm, rd, rs1, rs2, $unsigned(imm_s3_type[4:0]));
// else
// str = $sformatf("%-16s x%0d, x%0d, x%0d", str_asm, rd, rs1, rs2);
// end
return "";
endfunction
endclass

78
src/util/instruction_tracer.svh Executable file
View file

@ -0,0 +1,78 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Main Class
//
// Copyright (C) 2017 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.
//
class instruction_tracer;
// interface to the core
virtual instruction_tracer_if tracer_if;
// keep the decoded instructions in a queue
fetch_entry decode_queue [$];
// shadow copy of the register file
logic [63:0] reg_file [31];
// 64 bit clock tick count
longint unsigned clk_ticks;
function new(virtual instruction_tracer_if tracer_if);
this.tracer_if = tracer_if;
endfunction : new
task trace();
fetch_entry issue_instruction;
forever begin
// new cycle, we are only interested if reset is de-asserted
@(tracer_if.pck iff tracer_if.pck.rstn);
clk_ticks++;
// We are decoding an instruction
if (tracer_if.pck.fetch_valid && tracer_if.pck.fetch_ack) begin
decode_queue.push_back(tracer_if.pck.fetch);
issue_instruction = fetch_entry'(tracer_if.pck.fetch);
printInstr(issue_instruction.instruction);
end
// we are committing an instruction
// if (tracer_if.pck.commit_instr.valid) begin
// $display("Committing: %0h", tracer_if.pck.commit_instr);
// end
// write back
if (tracer_if.pck.we && tracer_if.pck.waddr != 5'b0) begin
reg_file[tracer_if.pck.waddr] = tracer_if.pck.wdata;
end
end
endtask
function void flushIssue ();
endfunction;
function void flush ();
endfunction;
function void printInstr(logic [63:0] instr);
instruction_trace_item iti = new;
$display(iti.printInstr(instr));
endfunction;
endclass : instruction_tracer

View file

@ -0,0 +1,73 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Defines
//
// Copyright (C) 2017 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.
//
parameter INSTR_LUI = { 25'b?, OPCODE_LUI };
parameter INSTR_AUIPC = { 25'b?, OPCODE_AUIPC };
parameter INSTR_JAL = { 25'b?, OPCODE_JAL };
parameter INSTR_JALR = { 17'b?, 3'b000, 5'b?, OPCODE_JALR };
// BRANCH
parameter INSTR_BEQ = { 17'b?, 3'b000, 5'b?, OPCODE_BRANCH };
parameter INSTR_BNE = { 17'b?, 3'b001, 5'b?, OPCODE_BRANCH };
parameter INSTR_BLT = { 17'b?, 3'b100, 5'b?, OPCODE_BRANCH };
parameter INSTR_BGE = { 17'b?, 3'b101, 5'b?, OPCODE_BRANCH };
parameter INSTR_BLTU = { 17'b?, 3'b110, 5'b?, OPCODE_BRANCH };
parameter INSTR_BGEU = { 17'b?, 3'b111, 5'b?, OPCODE_BRANCH };
// OPIMM
parameter INSTR_ADDI = { 17'b?, 3'b000, 5'b?, OPCODE_OPIMM };
parameter INSTR_SLTI = { 17'b?, 3'b010, 5'b?, OPCODE_OPIMM };
parameter INSTR_SLTIU = { 17'b?, 3'b011, 5'b?, OPCODE_OPIMM };
parameter INSTR_XORI = { 17'b?, 3'b100, 5'b?, OPCODE_OPIMM };
parameter INSTR_ORI = { 17'b?, 3'b110, 5'b?, OPCODE_OPIMM };
parameter INSTR_ANDI = { 17'b?, 3'b111, 5'b?, OPCODE_OPIMM };
parameter INSTR_SLLI = { 7'b0000000, 10'b?, 3'b001, 5'b?, OPCODE_OPIMM };
parameter INSTR_SRLI = { 7'b0000000, 10'b?, 3'b101, 5'b?, OPCODE_OPIMM };
parameter INSTR_SRAI = { 7'b0100000, 10'b?, 3'b101, 5'b?, OPCODE_OPIMM };
// OP
parameter INSTR_ADD = { 7'b0000000, 10'b?, 3'b000, 5'b?, OPCODE_OP };
parameter INSTR_SUB = { 7'b0100000, 10'b?, 3'b000, 5'b?, OPCODE_OP };
parameter INSTR_SLL = { 7'b0000000, 10'b?, 3'b001, 5'b?, OPCODE_OP };
parameter INSTR_SLT = { 7'b0000000, 10'b?, 3'b010, 5'b?, OPCODE_OP };
parameter INSTR_SLTU = { 7'b0000000, 10'b?, 3'b011, 5'b?, OPCODE_OP };
parameter INSTR_XOR = { 7'b0000000, 10'b?, 3'b100, 5'b?, OPCODE_OP };
parameter INSTR_SRL = { 7'b0000000, 10'b?, 3'b101, 5'b?, OPCODE_OP };
parameter INSTR_SRA = { 7'b0100000, 10'b?, 3'b101, 5'b?, OPCODE_OP };
parameter INSTR_OR = { 7'b0000000, 10'b?, 3'b110, 5'b?, OPCODE_OP };
parameter INSTR_AND = { 7'b0000000, 10'b?, 3'b111, 5'b?, OPCODE_OP };
// FENCE
parameter INSTR_FENCE = { 4'b0, 8'b?, 13'b0, OPCODE_FENCE };
parameter INSTR_FENCEI = { 17'b0, 3'b001, 5'b0, OPCODE_FENCE };
// SYSTEM
parameter INSTR_CSRRW = { 17'b?, 3'b001, 5'b?, OPCODE_SYSTEM };
parameter INSTR_CSRRS = { 17'b?, 3'b010, 5'b?, OPCODE_SYSTEM };
parameter INSTR_CSRRC = { 17'b?, 3'b011, 5'b?, OPCODE_SYSTEM };
parameter INSTR_CSRRWI = { 17'b?, 3'b101, 5'b?, OPCODE_SYSTEM };
parameter INSTR_CSRRSI = { 17'b?, 3'b110, 5'b?, OPCODE_SYSTEM };
parameter INSTR_CSRRCI = { 17'b?, 3'b111, 5'b?, OPCODE_SYSTEM };
parameter INSTR_ECALL = { 12'b000000000000, 13'b0, OPCODE_SYSTEM };
parameter INSTR_EBREAK = { 12'b000000000001, 13'b0, OPCODE_SYSTEM };
parameter INSTR_ERET = { 12'b000100000000, 13'b0, OPCODE_SYSTEM };
parameter INSTR_WFI = { 12'b000100000010, 13'b0, OPCODE_SYSTEM };
// RV32M
parameter INSTR_PMUL = { 7'b0000001, 10'b?, 3'b000, 5'b?, OPCODE_OP };
parameter INSTR_DIV = { 7'b0000001, 10'b?, 3'b100, 5'b?, OPCODE_OP };
parameter INSTR_DIVU = { 7'b0000001, 10'b?, 3'b101, 5'b?, OPCODE_OP };
parameter INSTR_REM = { 7'b0000001, 10'b?, 3'b110, 5'b?, OPCODE_OP };
parameter INSTR_REMU = { 7'b0000001, 10'b?, 3'b111, 5'b?, OPCODE_OP };

View file

@ -0,0 +1,48 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Interface
//
// Copyright (C) 2017 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.
//
import ariane_pkg::*;
`ifndef INSTR_TRACER_IF_SV
`define INSTR_TRACER_IF_SV
interface instruction_tracer_if (
input clk
);
logic rstn;
logic flush_issue;
logic flush;
// decode
fetch_entry fetch;
logic fetch_valid;
logic fetch_ack;
// WB stage
logic [4:0] waddr;
logic [63:0] wdata;
logic we;
// commit stage
scoreboard_entry commit_instr; // commit instruction
logic commit_ack;
// the tracer just has a passive interface we do not drive anything with it
clocking pck @(posedge clk);
input rstn, flush, fetch, fetch_valid, fetch_ack, waddr, wdata, we, commit_instr, commit_ack;
endclocking
endinterface
`endif

View file

@ -0,0 +1,25 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Package
//
// Copyright (C) 2017 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.
//
package instruction_tracer_pkg;
import ariane_pkg::*;
`include "instruction_tracer_defines.svh"
`include "instruction_trace_item.svh"
`include "instruction_tracer.svh"
endpackage

View file

@ -0,0 +1,49 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 14.5.2017
// Description: Fetch FIFO interface
//
//
// Copyright (C) 2017 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.
//
`ifndef FETCH_FIFO_IF_SV
`define FETCH_FIFO_IF_SV
import ariane_pkg::*;
interface fetch_fifo_if (
input clk
);
wire flush;
wire [$bits(branchpredict_sbe)-1:0] in_branch_predict;
wire [63:0] in_addr;
wire [31:0] in_rdata;
wire in_valid;
wire in_ready;
wire [$bits(fetch_entry)-1:0] fetch_entry;
wire out_valid;
wire out_ready;
clocking mck @(posedge clk);
input in_ready, fetch_entry, out_valid;
output flush, in_branch_predict, in_addr, in_rdata, in_valid, out_ready;
endclocking
clocking pck @(posedge clk);
input in_ready, fetch_entry, out_valid,
flush, in_branch_predict, in_addr, in_rdata, in_valid, out_ready;
endclocking
endinterface
`endif

View file

@ -26,14 +26,15 @@ module alu_tb;
alu
dut
(
.trans_id_i ( ),
.alu_valid_i ( ),
.operator_i ( fu_op'(alu_if.operator) ),
.operand_a_i ( alu_if.operand_a ),
.operand_b_i ( alu_if.operand_b ),
.result_o ( alu_if.result ),
.comparison_result_o ( alu_if.comparison_result ),
.is_equal_result_o ( ),
.adder_result_ext_o ( ),
.adder_result_o ( )
.alu_valid_o ( ),
.alu_ready_o ( ),
.alu_trans_id_o ( )
);
initial begin

96
tb/fetch_fifo_tb.sv Executable file
View file

@ -0,0 +1,96 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 14.5.2017
// Description: Fetch FIFO testbench
//
//
// Copyright (C) 2017 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.
//
import ariane_pkg::*;
import fetch_fifo_pkg::*;
module fetch_fifo_tb;
logic rst_ni, clk_i;
fetch_fifo_if fetch_fifo_if (clk_i);
fetch_fifo
dut (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( fetch_fifo_if.flush ),
.branch_predict_i ( fetch_fifo_if.in_branch_predict ),
.in_addr_i ( fetch_fifo_if.in_addr ),
.in_rdata_i ( fetch_fifo_if.in_rdata ),
.in_valid_i ( fetch_fifo_if.in_valid ),
.in_ready_o ( fetch_fifo_if.in_ready ),
.fetch_entry_o ( fetch_fifo_if.fetch_entry ),
.out_valid_o ( fetch_fifo_if.out_valid ),
.out_ready_i ( fetch_fifo_if.out_ready )
);
initial begin
clk_i = 1'b0;
rst_ni = 1'b0;
repeat(8)
#10ns clk_i = ~clk_i;
rst_ni = 1'b1;
forever
#10ns clk_i = ~clk_i;
end
// simulator stopper, this is suboptimal better go for coverage
initial begin
#10000000ns
$finish;
end
program testbench (fetch_fifo_if fetch_fifo_if);
instruction_stream is = new;
fetch_fifo_model model = new;
instruction_queue_entry_t iqe;
initial begin
fetch_fifo_if.mck.flush <= 1'b0;
fetch_fifo_if.mck.in_branch_predict <= 'b0;
fetch_fifo_if.mck.in_addr <= 'b0;
fetch_fifo_if.mck.in_rdata <= 'b0;
fetch_fifo_if.mck.in_valid <= 'b0;
fetch_fifo_if.mck.out_ready <= 'b0;
wait(rst_ni == 1'b1);
// Driver
forever begin
@(fetch_fifo_if.mck iff fetch_fifo_if.in_ready);
do begin
iqe = is.get_instruction();
fetch_fifo_if.mck.in_addr <= iqe.address;
fetch_fifo_if.mck.in_rdata <= iqe.instr;
fetch_fifo_if.mck.in_branch_predict <= iqe.bp;
fetch_fifo_if.mck.in_valid <= 1'b1;
@(fetch_fifo_if.mck);
end while (fetch_fifo_if.mck.in_ready);
fetch_fifo_if.mck.in_valid <= 1'b0;
end
end
endprogram
testbench tb(fetch_fifo_if);
endmodule

View file

@ -110,7 +110,6 @@ module scoreboard_tb;
@(scoreboard_if.mck);
// if we are not full then load another instruction
if (scoreboard_if.issue_instr_valid == 1'b1) begin
scoreboard_if.mck.issue_ack <= 1'b1;
issue_instruction <= scoreboard_if.mck.issue_instr;

View file

@ -0,0 +1,104 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 14.5.2017
// Description: Fetch FIFO Golden Model
//
//
// Copyright (C) 2017 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.
//
// Read 32 bit instruction, separate and re-align them
typedef struct {
logic [63:0] address;
logic [31:0] instr;
branchpredict_sbe bp;
} instruction_queue_entry_t;
class fetch_fifo_model;
logic [15:0] unaligned_part;
int is_unaligned = 0;
logic [63:0] unaligend_address;
instruction_queue_entry_t instruction_queue[$];
function void put(logic [63:0] address, logic [31:0] instr, branchpredict_sbe bp);
instruction_queue_entry_t param;
if (is_unaligned == 0) begin
// we've got a compressed instruction
if (instr[1:0] != 2'b11) begin
param.address = address;
param.instr = {16'b0, instr[15:0]};
param.bp = bp;
instruction_queue.push_back(param);
// the upper part is a unaligned 32 bit instruction
if (instr[17:16] == 2'b11) begin
unaligend_address = {address[63:2], 2'b10};
is_unaligned = 1;
unaligned_part = instr[31:16];
// there is another compressed instruction
// don't include if branch prediction predicted a compressed
// branch in the first instruction part
end else if (!(bp.predict_taken && bp.valid && bp.is_lower_16)) begin
param.address = {address[63:2], 2'b10};
param.instr = instr[31:16];
param.bp = bp;
instruction_queue.push_back(param);
end
// normal instruction
end else begin
param.address = address;
param.instr = instr;
param.bp = bp;
instruction_queue.push_back(param);
end
// the last generation iteration produced an outstanding instruction
end else begin
param.address = unaligend_address;
param.instr = {instr[15:0], unaligned_part};
param.bp = bp;
instruction_queue.push_back(param);
// there is another compressed instruction
// don't include if branch prediction predicted a compressed
// branch in the first instruction part
if (instr[17:16] != 2'b11) begin
if (!(bp.predict_taken && bp.valid && bp.is_lower_16)) begin
param.address = {address[63:2], 2'b10};
param.instr = instr[31:16];
param.bp = bp;
instruction_queue.push_back(param);
end
is_unaligned = 0;
end else begin
// again we have an unaligned instruction
param.address = {address[63:2], 2'b10};
is_unaligned = 1;
unaligned_part = instr[31:16];
end
end
endfunction : put
function instruction_queue_entry_t pull();
return instruction_queue.pop_front();
endfunction : pull
function flush();
for (int i = 0; i < instruction_queue.size(); i++) begin
instruction_queue.delete(i);
end
endfunction : flush
endclass : fetch_fifo_model

View file

@ -0,0 +1,25 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 14.5.2017
// Description: Fetch FIFO Pkg
//
//
// Copyright (C) 2017 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.
//
package fetch_fifo_pkg;
import ariane_pkg::*;
`include "fetch_fifo_model.svh"
`include "instruction_stream.svh"
endpackage

View file

@ -0,0 +1,107 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 14.5.2017
// Description: Random instruction class
//
//
// Copyright (C) 2017 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.
//
class instruction;
rand logic [31:0] instruction;
rand bit is_compressed;
constraint compressed_constraint {
(is_compressed) -> {
instruction[1:0] != 2'b11;
}
(!is_compressed) -> {
instruction[1:0] == 2'b11;
instruction[4:2] != 3'b111;
}
}
// Return readable representation
function string convert2string();
string s;
$sformat(s, "Instruction: %0h\nCompressed: %h", instruction, is_compressed);
return s;
endfunction : convert2string
endclass : instruction
class instruction_stream;
logic [63:0] address = 0;
instruction instr;
logic [15:0] unaligned_part;
int is_unaligned = 0;
// get an instruction stream of consecutive data
function instruction_queue_entry_t get_instruction();
branchpredict_sbe bp = '0;
instruction_queue_entry_t return_entry;
logic [31:0] return_instruction;
// generate a new instruction
if (is_unaligned == 0) begin
instr = new;
void'(randomize(instr));
// we've generated a compressed instruction so generate another one
if (instr.is_compressed) begin
return_instruction [15:0] = instr.instruction[15:0];
// get a new instruction
instr = new;
void'(randomize(instr));
return_instruction[31:16] = instr.instruction[15:0];
// $display("Instruction: [ c | c ]");
// was this a compressed instruction as well?
// if not than store that this was an unaligned access
if (!instr.is_compressed) begin
// $display("Instruction: [ i0 | c ]");
is_unaligned = 1;
unaligned_part = instr.instruction[31:16];
end
// normal instruction
end else begin
return_instruction = instr.instruction;
// $display("Instruction: [ i ]");
end
// the last generation iteration produced an outstanding instruction
end else begin
return_instruction [15:0] = unaligned_part;
// generate a new isntruction
instr = new;
void'(randomize(instr));
return_instruction [31:16] = instr.instruction[15:0];
// was it compressed?
if (instr.is_compressed) begin
is_unaligned = 0;
// $display("Instruction: [ c | i1 ]");
end else begin
// again we have an unaligned instruction
unaligned_part = instr.instruction[31:16];
// $display("Instruction: [ i0 | i1 ]");
end
end
return_entry.instr = return_instruction;
return_entry.bp = bp;
return_entry.address = address;
address = address + 4;
return return_entry;
endfunction : get_instruction
endclass : instruction_stream

View file

@ -1,483 +1,20 @@
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -group instr_if /core_tb/instr_if/clk
add wave -noupdate -group instr_if /core_tb/instr_if/address
add wave -noupdate -group instr_if /core_tb/instr_if/data_wdata
add wave -noupdate -group instr_if /core_tb/instr_if/data_req
add wave -noupdate -group instr_if /core_tb/instr_if/data_gnt
add wave -noupdate -group instr_if /core_tb/instr_if/data_rvalid
add wave -noupdate -group instr_if /core_tb/instr_if/data_rdata
add wave -noupdate -group instr_if /core_tb/instr_if/data_we
add wave -noupdate -group instr_if /core_tb/instr_if/data_be
add wave -noupdate -group Core /core_tb/dut/clk_i
add wave -noupdate -group Core /core_tb/dut/clock_en_i
add wave -noupdate -group Core /core_tb/dut/test_en_i
add wave -noupdate -group Core /core_tb/dut/fetch_enable_i
add wave -noupdate -group Core /core_tb/dut/core_busy_o
add wave -noupdate -group Core /core_tb/dut/ext_perf_counters_i
add wave -noupdate -group Core /core_tb/dut/boot_addr_i
add wave -noupdate -group Core /core_tb/dut/core_id_i
add wave -noupdate -group Core /core_tb/dut/cluster_id_i
add wave -noupdate -group Core /core_tb/dut/irq_i
add wave -noupdate -group Core /core_tb/dut/irq_id_i
add wave -noupdate -group Core /core_tb/dut/irq_ack_o
add wave -noupdate -group Core /core_tb/dut/irq_sec_i
add wave -noupdate -group Core /core_tb/dut/sec_lvl_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/clk
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/rst_n
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/clear_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/in_addr_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/in_rdata_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/in_valid_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/in_ready_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/out_addr_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/out_rdata_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/out_valid_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/out_ready_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/out_valid_stored_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/addr_n
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/addr_int
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/addr_Q
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/rdata_n
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/rdata_int
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/rdata_Q
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/valid_n
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/valid_int
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/valid_Q
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/addr_next
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/rdata
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/rdata_unaligned
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/valid
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/valid_unaligned
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/aligned_is_compressed
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/unaligned_is_compressed
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/aligned_is_compressed_st
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/unaligned_is_compressed_st
add wave -noupdate -expand -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/j
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/clk
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/rst_n
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/req_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/branch_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/addr_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/ready_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/valid_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/addr_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/rdata_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/instr_req_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/instr_gnt_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/instr_addr_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/instr_rdata_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/instr_rvalid_i
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/busy_o
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/CS
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/NS
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/instr_addr_q
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/fetch_addr
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/addr_valid
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_valid
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_ready
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_clear
add wave -noupdate -expand -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/valid_stored
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/clk_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/rst_ni
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/flush_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/req_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/if_busy_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/id_ready_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/halt_if_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_req_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_addr_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_gnt_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_rvalid_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_rdata_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_valid_id_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_rdata_id_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/is_compressed_id_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/illegal_c_insn_id_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/pc_if_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/pc_id_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/ex_o
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/boot_addr_i
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/if_ready
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/if_valid
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/branch_req
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/valid
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/prefetch_busy
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/fetch_addr_n
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/fetch_valid
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/fetch_ready
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/fetch_rdata
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/fetch_addr
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/offset_fsm_cs
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/offset_fsm_ns
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_decompressed
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/illegal_c_insn
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/instr_compressed_int
add wave -noupdate -expand -group if_stage /core_tb/dut/if_stage_i/clear_instr_valid_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/clk_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/rst_ni
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/test_en_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/flush_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/instruction_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/instruction_valid_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/pc_if_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/ready_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/operator_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/operand_a_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/operand_b_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/trans_id_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/alu_ready_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/alu_valid_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/lsu_ready_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/lsu_valid_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/mult_ready_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/mult_valid_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/trans_id_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/wdata_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/wb_valid_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/waddr_a_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/wdata_a_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/we_a_i
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/commit_instr_o
add wave -noupdate -expand -group id_stage /core_tb/dut/id_stage_i/commit_ack_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/clk_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rst_ni
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/full_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/flush_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rd_clobber_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rs1_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rs1_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rs1_valid_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rs2_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rs2_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/rs2_valid_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/commit_instr_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/commit_ack_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/decoded_instr_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/decoded_instr_valid_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/issue_instr_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/issue_instr_valid_o
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/issue_ack_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/trans_id_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/wdata_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/ex_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/wb_valid_i
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/mem_q
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/mem_n
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/issue_pointer_n
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/issue_pointer_q
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/commit_pointer_n
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/commit_pointer_q
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/top_pointer_n
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/top_pointer_q
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/top_pointer_qq
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/pointer_overflow
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/empty
add wave -noupdate -expand -group id_stage -expand -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/reset_condition
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/clk_i
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/rst_ni
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/pc_i
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/instruction_i
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/ex_i
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/instruction_o
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/instr
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_select
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_i_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_iz_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_s_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_sb_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_u_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_uj_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_z_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_s2_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_bi_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_s3_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_vs_type
add wave -noupdate -expand -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/imm_vu_type
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/clk_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rst_ni
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/test_en_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/flush_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/issue_instr_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/issue_instr_valid_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/issue_ack_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rs1_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rs1_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rs1_valid_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rs2_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rs2_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rs2_valid_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/rd_clobber_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operator_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_a_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_b_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/trans_id_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/alu_ready_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/alu_valid_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/lsu_ready_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/lsu_valid_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/mult_ready_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/mult_valid_o
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/waddr_a_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/wdata_a_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/we_a_i
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/stall
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/fu_busy
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_a_regfile
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_b_regfile
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_a_n
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_a_q
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_b_n
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operand_b_q
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/alu_valid_n
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/alu_valid_q
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/trans_id_n
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/trans_id_q
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operator_n
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/operator_q
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/forward_rs1
add wave -noupdate -expand -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/forward_rs2
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/operator_i
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/operand_a_i
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/operand_b_i
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/adder_result_o
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/adder_result_ext_o
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/result_o
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/comparison_result_o
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/is_equal_result_o
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/operand_a_rev
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/operand_a_rev32
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/operand_b_neg
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/adder_op_b_negate
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/adder_in_a
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/adder_in_b
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/adder_result
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_left
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_arithmetic
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_amt
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_op_a
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_op_a32
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_result
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_result32
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_right_result
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_right_result32
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_left_result
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_left_result32
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_op_a_64
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/shift_op_a_32
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/is_equal
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/is_greater_equal
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/cmp_signed
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/cmp_result
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/clk_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/rst_ni
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/flush_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/operator_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/operand_a_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/operand_b_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/imm_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/lsu_ready_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/lsu_valid_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/trans_id_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/lsu_trans_id_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/lsu_result_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/lsu_valid_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/commit_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/enable_translation_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/fetch_req_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/fetch_gnt_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/fetch_valid_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/fetch_err_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/fetch_vaddr_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/fetch_rdata_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/priv_lvl_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/flag_pum_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/flag_mxr_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/pd_ppn_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/asid_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/flush_tlb_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/instr_if_address_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/instr_if_data_req_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/instr_if_data_be_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/instr_if_data_gnt_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/instr_if_data_rvalid_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/instr_if_data_rdata_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_address_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_data_wdata_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_data_req_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_data_we_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_data_be_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_data_gnt_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_data_rvalid_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_if_data_rdata_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/lsu_exception_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_misaligned
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/CS
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/NS
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/vaddr_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/stall
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/get_from_register
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/vaddr
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/be
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/operator
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/trans_id
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/vaddr_q
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_q
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/operator_q
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/trans_id_q
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/st_buffer_paddr
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/st_buffer_data
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/st_buffer_be
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/st_buffer_valid
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/st_ready
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/st_valid
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/translation_req
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/translation_valid
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/paddr_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/address_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_wdata_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_req_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_we_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_be_i
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_gnt_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_rvalid_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/data_rdata_o
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/rdata
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/address_match
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/op
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/rdata_d_ext
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/rdata_w_ext
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/rdata_h_ext
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/rdata_b_ext
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/clk_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/rst_ni
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/flush_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/operator_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/operand_a_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/operand_b_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/trans_id_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_ready_o
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_valid_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_trans_id_o
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_result_o
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_valid_o
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/commit_i
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_addr_o
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_reg_n
add wave -noupdate -group ex_stage -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/csr_reg_q
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/clk_i
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/rst_ni
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/operator_i
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/operand_a_i
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/operand_b_i
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/trans_id_i
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/alu_ready_o
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/alu_valid_i
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/alu_valid_o
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/alu_result_o
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/alu_trans_id_o
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/comparison_result_o
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/lsu_ready_o
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/lsu_valid_i
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/mult_ready_o
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/mult_valid_i
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/clk_i
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/rst_ni
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/exception_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/commit_instr_i
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/commit_ack_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/waddr_a_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/wdata_a_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/we_a_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/pc_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/csr_op_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/csr_wdata_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/csr_rdata_i
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/csr_exception_i
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/commit_lsu_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/commit_csr_o
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/irq_enable_i
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/exception
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/clk_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/rst_ni
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/flush_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/core_id_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/cluster_id_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/boot_addr_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/ex_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_op_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_addr_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_wdata_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_rdata_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/pc_i
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_exception_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/irq_enable_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/epc_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/trap_vector_base_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/priv_lvl_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/enable_translation_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/flag_pum_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/flag_mxr_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/pd_ppn_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/asid_o
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_addr
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/read_access_exception
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/update_access_exception
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_we
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_wdata
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/csr_rdata
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/priv_lvl_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/priv_lvl_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/prev_priv_lvl_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/prev_priv_lvl_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mstatus_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mstatus_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mtvec_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mtvec_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/medeleg_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/medeleg_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mideleg_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mideleg_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mip_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mip_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mie_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mie_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mscratch_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mscratch_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mepc_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mepc_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mcause_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mcause_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mtval_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/mtval_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/stvec_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/stvec_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/sscratch_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/sscratch_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/sepc_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/sepc_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/scause_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/scause_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/stval_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/stval_n
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/satp_q
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/satp_n
add wave -noupdate -group core /core_tb/dut/*
add wave -noupdate -group pcgen_stage -group btb /core_tb/dut/pcgen_i/btb_i/*
add wave -noupdate -group pcgen_stage /core_tb/dut/pcgen_i/*
add wave -noupdate -group if_stage -group prefetch_buffer -group fifo /core_tb/dut/if_stage_i/prefetch_buffer_i/fifo_i/*
add wave -noupdate -group if_stage -group prefetch_buffer /core_tb/dut/if_stage_i/prefetch_buffer_i/*
add wave -noupdate -group if_stage /core_tb/dut/if_stage_i/*
add wave -noupdate -group id_stage -group scoreboard /core_tb/dut/id_stage_i/scoreboard_i/*
add wave -noupdate -group id_stage -group decoder /core_tb/dut/id_stage_i/decoder_i/*
add wave -noupdate -group id_stage -group issue_read_operands /core_tb/dut/id_stage_i/issue_read_operands_i/*
add wave -noupdate -group id_stage /core_tb/dut/id_stage_i/*
add wave -noupdate -group ex_stage -group ALU /core_tb/dut/ex_stage_i/alu_i/*
add wave -noupdate -group ex_stage -group lsu /core_tb/dut/ex_stage_i/lsu_i/*
add wave -noupdate -group ex_stage -group branch_engine /core_tb/dut/ex_stage_i/branch_engine_i/*
add wave -noupdate -group ex_stage -expand -group csr_buffer /core_tb/dut/ex_stage_i/csr_buffer_i/*
add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/*
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/*
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/*
add wave -noupdate -group controller /core_tb/dut/controller_i/*
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {207 ns} 0} {{Cursor 2} {278 ns} 1}
quietly wave cursor active 1
configure wave -namecolwidth 241
configure wave -valuecolwidth 258
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ns} {1580 ns}

View file

@ -1,10 +1,9 @@
.text
nop
nop
nop
addi x1, x0, 1
addi x2, x0, 1
add x3, x1, x2
add x3, x1, x2
add x4, x2, x3
add x5, x3, x4
add x6, x4, x5
@ -14,5 +13,12 @@
add x9, x7, x8
csrr x1, mstatus
nop
L0: jal x0, L1
nop
nop
nop
nop
nop
L1: jal x0, L0
nop
nop
addi x1, x0, 55