mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 13:47:13 -04:00
Merge branch 'initial-dev' of iis-git.ee.ethz.ch:floce/ariane into initial-dev
This commit is contained in:
commit
a0f5d02c7d
35 changed files with 2382 additions and 1670 deletions
18
Makefile
18
Makefile
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
309
src/alu.sv
309
src/alu.sv
|
@ -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
|
||||
|
|
304
src/ariane.sv
304
src/ariane.sv
|
@ -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
128
src/branch_engine.sv
Normal 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
|
61
src/btb.sv
61
src/btb.sv
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
20
src/fifo.sv
20
src/fifo.sv
|
@ -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
|
||||
|
|
|
@ -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
|
247
src/if_stage.sv
247
src/if_stage.sv
|
@ -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
|
|
@ -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
|
||||
|
|
52
src/lsu.sv
52
src/lsu.sv
|
@ -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
|
||||
|
|
92
src/pcgen.sv
92
src/pcgen.sv
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
21
src/tlb.sv
21
src/tlb.sv
|
@ -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
|
||||
//--------------
|
||||
|
|
311
src/util/instruction_trace_item.svh
Executable file
311
src/util/instruction_trace_item.svh
Executable 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
78
src/util/instruction_tracer.svh
Executable 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
|
73
src/util/instruction_tracer_defines.svh
Executable file
73
src/util/instruction_tracer_defines.svh
Executable 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 };
|
48
src/util/instruction_tracer_if.sv
Executable file
48
src/util/instruction_tracer_if.sv
Executable 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
|
25
src/util/instruction_tracer_pkg.sv
Executable file
25
src/util/instruction_tracer_pkg.sv
Executable 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
|
49
tb/agents/fetch_fifo_if/fetch_fifo_if.sv
Executable file
49
tb/agents/fetch_fifo_if/fetch_fifo_if.sv
Executable 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
|
|
@ -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
96
tb/fetch_fifo_tb.sv
Executable 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
|
|
@ -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;
|
||||
|
|
104
tb/test/fetch_fifo/fetch_fifo_model.svh
Executable file
104
tb/test/fetch_fifo/fetch_fifo_model.svh
Executable 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
|
25
tb/test/fetch_fifo/fetch_fifo_pkg.sv
Executable file
25
tb/test/fetch_fifo/fetch_fifo_pkg.sv
Executable 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
|
107
tb/test/fetch_fifo/instruction_stream.svh
Executable file
107
tb/test/fetch_fifo/instruction_stream.svh
Executable 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
|
|
@ -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}
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue