Feature/remove writeback stage (#56)

* remove parameter option WritebackStage

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* remove references to the removed parameters from examples

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* remove references to the removed parameters from compliance verification

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* remove references to the removed parameters from formal verification code generated for SymbioticEDA

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* Remove reference to the deleted parameterd from the documentation
Do not refer to WriteBack as to a stage

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* Remove related code to Writeback stage

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* Removal of related and dead code after Writeback-stage removal

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* substitute ASSERT macro with one ignoring rst_ni and clk signals

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* keep clk_i and rst_ni for the sake of assert alone

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

* BUGFIX: reintroduce en_wb signal between id and wb

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>

---------

Signed-off-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>
Co-authored-by: Szymon Bieganski <szymon.bieganski@oss.nxp.com>
This commit is contained in:
christian-herber-nxp 2023-05-31 14:44:59 +02:00 committed by GitHub
parent cd76f83e12
commit 3a9f2d058f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 111 additions and 624 deletions

View file

@ -55,7 +55,7 @@ ${DESIGN_RTL_DIR}/cve2_multdiv_slow.sv
${DESIGN_RTL_DIR}/cve2_prefetch_buffer.sv
${DESIGN_RTL_DIR}/cve2_pmp.sv
${DESIGN_RTL_DIR}/cve2_register_file_ff.sv
${DESIGN_RTL_DIR}/cve2_wb_stage.sv
${DESIGN_RTL_DIR}/cve2_wb.sv
${DESIGN_RTL_DIR}/cve2_core.sv
${DESIGN_RTL_DIR}/cve2_top.sv
${DESIGN_RTL_DIR}/cve2_top_tracing.sv

View file

@ -29,7 +29,7 @@ filesets:
- rtl/cve2_multdiv_slow.sv
- rtl/cve2_prefetch_buffer.sv
- rtl/cve2_pmp.sv
- rtl/cve2_wb_stage.sv
- rtl/cve2_wb.sv
- rtl/cve2_core.sv
- rtl/cve2_pmp_reset_default.svh: {is_include_file: true}
file_type: systemVerilogSource

View file

@ -94,9 +94,6 @@ Parameters
| | | | "cve2_pkg::RV32MFast": 3-4 cycle multiplier, iterative divider |
| | | | "cve2_pkg::RV32MSingleCycle": 1-2 cycle multiplier, iterative divider |
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
| ``WritebackStage`` | bit | 0 | *EXPERIMENTAL* - Enables third pipeline stage (writeback) |
| | | | improving performance of loads and stores |
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
| ``BranchPrediction`` | bit | 0 | *EXPERIMENTAL* Enable Static branch prediction |
+------------------------------+---------------------+------------+-----------------------------------------------------------------------+
| ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode |

View file

@ -59,12 +59,6 @@ parameters:
paramtype: vlogparam
description: "Enable ECC protection in instruction cache"
WritebackStage:
datatype: int
paramtype: vlogparam
default: 0
description: "Enables third pipeline stage (EXPERIMENTAL)"
BranchPredictor:
datatype: int
paramtype: vlogparam
@ -114,7 +108,6 @@ targets:
- RegFile
- ICache
- ICacheECC
- WritebackStage
- BranchPredictor
- PMPEnable
- PMPGranularity

View file

@ -22,7 +22,6 @@ module cve2_riscv_compliance (
parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast;
parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone;
parameter cve2_pkg::regfile_e RegFile = cve2_pkg::RegFileFF;
parameter bit WritebackStage = 1'b0;
parameter bit ICache = 1'b0;
parameter bit ICacheECC = 1'b0;
parameter bit BranchPredictor = 1'b0;
@ -120,7 +119,6 @@ module cve2_riscv_compliance (
.RV32M (RV32M ),
.RV32B (RV32B ),
.RegFile (RegFile ),
.WritebackStage (WritebackStage ),
.ICache (ICache ),
.ICacheECC (ICacheECC ),
.BranchPredictor (BranchPredictor ),

View file

@ -54,12 +54,6 @@ parameters:
paramtype: vlogparam
description: "Path to a vmem file to initialize the RAM with"
WritebackStage:
datatype: int
paramtype: vlogparam
default: 0
description: "Enables third pipeline stage (EXPERIMENTAL)"
SecureIbex:
datatype: int
default: 0
@ -109,7 +103,6 @@ targets:
- ICache
- ICacheScramble
- ICacheECC
- WritebackStage
- SecureIbex
- BranchPredictor
- PMPEnable

View file

@ -44,7 +44,6 @@ module cve2_simple_system (
parameter cve2_pkg::rv32m_e RV32M = `RV32M;
parameter cve2_pkg::rv32b_e RV32B = `RV32B;
parameter cve2_pkg::regfile_e RegFile = `RegFile;
parameter bit WritebackStage = 1'b0;
parameter bit ICache = 1'b0;
parameter bit ICacheECC = 1'b0;
parameter bit BranchPredictor = 1'b0;
@ -174,7 +173,6 @@ module cve2_simple_system (
.RegFile ( RegFile ),
.ICache ( ICache ),
.ICacheECC ( ICacheECC ),
.WritebackStage ( WritebackStage ),
.BranchPredictor ( BranchPredictor ),
.DmHaltAddr ( 32'h00100000 ),
.DmExceptionAddr ( 32'h00100000 )

View file

@ -5,8 +5,6 @@
# Provide a convenient way to create a Verilog source of Ibex.
# This is used by riscv-formal. See README.md for more details.
CVE2_ENABLE_WB ?= 0
# Name of the output file
IBEX_OUT := ibex.v
# Build folder name
@ -45,7 +43,7 @@ SRCS_SV ?= \
$(SRC_DIR)/cve2_prefetch_buffer.sv \
$(SRC_DIR)/cve2_pmp.sv \
$(SRC_DIR)/cve2_register_file_ff.sv \
$(SRC_DIR)/cve2_wb_stage.sv \
$(SRC_DIR)/cve2_wb.sv \
$(SRC_DIR)/cve2_core.sv \
$(SRC_DIR)/cve2_top.sv
@ -74,7 +72,6 @@ $(GEN_V): $(OUTDIR)%.v: $(SRC_DIR)%.sv $(PKGS) | $(OUTDIR)
$(IBEX_OUT): $(GEN_V) $(PRIM_CLOCK)
yosys -p "read_verilog $(PRIM_CLOCK) $(GEN_V)" \
-p "chparam -set RV32M 0 cve2_top" \
-p "chparam -set WritebackStage $(CVE2_ENABLE_WB) cve2_top" \
-p "synth -top cve2_top" \
-p "write_verilog $(IBEX_OUT)"

View file

@ -11,7 +11,6 @@
`include "dv_fcov_macros.svh"
module cve2_controller #(
parameter bit WritebackStage = 0,
parameter bit BranchPredictor = 0
) (
input logic clk_i,
@ -58,7 +57,6 @@ module cve2_controller #(
input logic [31:0] lsu_addr_last_i, // for mtval
input logic load_err_i,
input logic store_err_i,
output logic wb_exception_o, // Instruction in WB taking an exception
output logic id_exception_o, // Instruction in ID taking an exception
// jump/branch signals
@ -87,7 +85,6 @@ module cve2_controller #(
output logic csr_save_if_o,
output logic csr_save_id_o,
output logic csr_save_wb_o,
output logic csr_restore_mret_id_o,
output logic csr_restore_dret_id_o,
output logic csr_save_cause_o,
@ -97,9 +94,7 @@ module cve2_controller #(
// stall & flush signals
input logic stall_id_i,
input logic stall_wb_i,
output logic flush_id_o,
input logic ready_wb_i,
// performance monitors
output logic perf_jump_o, // we are executing a jump
@ -150,7 +145,6 @@ module cve2_controller #(
logic enter_debug_mode;
logic ebreak_into_debug;
logic handle_irq;
logic id_wb_pending;
logic [3:0] mfip_id;
logic unused_irq_timer;
@ -236,40 +230,7 @@ module cve2_controller #(
// generic special request signal, applies to all instructions
assign special_req = special_req_pc_change | special_req_flush_only;
// Is there an instruction in ID or WB that has yet to complete?
assign id_wb_pending = instr_valid_i | ~ready_wb_i;
// Exception/fault prioritisation is taken from Table 3.7 of Priviledged Spec v1.11
if (WritebackStage) begin : g_wb_exceptions
always_comb begin
instr_fetch_err_prio = 0;
illegal_insn_prio = 0;
ecall_insn_prio = 0;
ebrk_insn_prio = 0;
store_err_prio = 0;
load_err_prio = 0;
// Note that with the writeback stage store/load errors occur on the instruction in writeback,
// all other exception/faults occur on the instruction in ID/EX. The faults from writeback
// must take priority as that instruction is architecurally ordered before the one in ID/EX.
if (store_err_q) begin
store_err_prio = 1'b1;
end else if (load_err_q) begin
load_err_prio = 1'b1;
end else if (instr_fetch_err) begin
instr_fetch_err_prio = 1'b1;
end else if (illegal_insn_q) begin
illegal_insn_prio = 1'b1;
end else if (ecall_insn) begin
ecall_insn_prio = 1'b1;
end else if (ebrk_insn) begin
ebrk_insn_prio = 1'b1;
end
end
// Instruction in writeback is generating an exception so instruction in ID must not execute
assign wb_exception_o = load_err_q | store_err_q | load_err_i | store_err_i;
end else begin : g_no_wb_exceptions
always_comb begin
instr_fetch_err_prio = 0;
illegal_insn_prio = 0;
@ -292,8 +253,6 @@ module cve2_controller #(
load_err_prio = 1'b1;
end
end
assign wb_exception_o = 1'b0;
end
`ASSERT_IF(IbexExceptionPrioOnehot,
$onehot({instr_fetch_err_prio,
@ -370,7 +329,6 @@ module cve2_controller #(
csr_save_if_o = 1'b0;
csr_save_id_o = 1'b0;
csr_save_wb_o = 1'b0;
csr_restore_mret_id_o = 1'b0;
csr_restore_dret_id_o = 1'b0;
csr_save_cause_o = 1'b0;
@ -494,15 +452,9 @@ module cve2_controller #(
// FLUSH state.
retain_id = 1'b1;
// Wait for the writeback stage to either be ready for a new instruction or raise its own
// exception before going to FLUSH. If the instruction in writeback raises an exception it
// must take priority over any exception from an instruction in ID/EX. Only once the
// writeback stage is ready can we be certain that won't happen. Without a writeback
// stage ready_wb_i == 1 so the FSM will always go directly to FLUSH.
// The FSM will always go directly to FLUSH.
if (ready_wb_i | wb_exception_o) begin
ctrl_fsm_ns = FLUSH;
end
ctrl_fsm_ns = FLUSH;
end
if (branch_set_i || jump_set_i) begin
@ -522,12 +474,12 @@ module cve2_controller #(
end
// If entering debug mode or handling an IRQ the core needs to wait until any instruction in
// ID or WB has finished executing. Stall IF during that time.
if ((enter_debug_mode || handle_irq) && (stall || id_wb_pending)) begin
// ID has finished executing. Stall IF during that time.
if ((enter_debug_mode || handle_irq) && (stall || instr_valid_i)) begin
halt_if = 1'b1;
end
if (!stall && !special_req && !id_wb_pending) begin
if (!stall && !special_req && !instr_valid_i) begin
if (enter_debug_mode) begin
// enter debug mode
ctrl_fsm_ns = DBG_TAKEN_IF;
@ -654,13 +606,7 @@ module cve2_controller #(
pc_mux_o = PC_EXC;
exc_pc_mux_o = debug_mode_q ? EXC_PC_DBG_EXC : EXC_PC_EXC;
if (WritebackStage) begin : g_writeback_mepc_save
// With the writeback stage present whether an instruction accessing memory will cause
// an exception is only known when it is in writeback. So when taking such an exception
// epc must come from writeback.
csr_save_id_o = ~(store_err_q | load_err_q);
csr_save_wb_o = store_err_q | load_err_q;
end else begin : g_no_writeback_mepc_save
begin : g_no_writeback_mepc_save
csr_save_id_o = 1'b0;
end
@ -776,9 +722,8 @@ module cve2_controller #(
///////////////////
// If high current instruction cannot complete this cycle. Either because it needs more cycles to
// finish (stall_id_i) or because the writeback stage cannot accept it yet (stall_wb_i). If there
// is no writeback stage stall_wb_i is a constant 0.
assign stall = stall_id_i | stall_wb_i;
// finish (stall_id_i)
assign stall = stall_id_i;
// signal to IF stage that ID stage is ready for next instr
assign id_in_ready_o = ~stall & ~halt_if & ~retain_id;

View file

@ -21,7 +21,6 @@ module cve2_core import cve2_pkg::*; #(
parameter bit RV32E = 1'b0,
parameter rv32m_e RV32M = RV32MFast,
parameter rv32b_e RV32B = RV32BNone,
parameter bit WritebackStage = 1'b0,
parameter bit BranchPredictor = 1'b0,
parameter bit DbgTriggerEn = 1'b0,
parameter int unsigned DbgHwBreakNum = 1,
@ -125,7 +124,6 @@ module cve2_core import cve2_pkg::*; #(
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
logic [31:0] pc_if; // Program counter in IF stage
logic [31:0] pc_id; // Program counter in ID stage
logic [31:0] pc_wb; // Program counter in WB stage
logic [33:0] imd_val_d_ex[2]; // Intermediate register for multicycle Ops
logic [33:0] imd_val_q_ex[2]; // Intermediate register for multicycle Ops
logic [1:0] imd_val_we_ex;
@ -166,7 +164,6 @@ module cve2_core import cve2_pkg::*; #(
logic [31:0] rf_wdata_wb;
// Writeback register write data that can be used on the forwarding path (doesn't factor in memory
// read data as this is too late for the forwarding path)
logic [31:0] rf_wdata_fwd_wb;
logic [31:0] rf_wdata_lsu;
logic rf_we_wb;
logic rf_we_lsu;
@ -192,7 +189,6 @@ module cve2_core import cve2_pkg::*; #(
logic [1:0] multdiv_signed_mode_ex;
logic [31:0] multdiv_operand_a_ex;
logic [31:0] multdiv_operand_b_ex;
logic multdiv_ready_id;
// CSR control
logic csr_access;
@ -211,7 +207,6 @@ module cve2_core import cve2_pkg::*; #(
logic lsu_sign_ext;
logic lsu_req;
logic [31:0] lsu_wdata;
logic lsu_req_done;
// stall control
logic id_in_ready;
@ -224,13 +219,8 @@ module cve2_core import cve2_pkg::*; #(
logic instr_req_int; // Id stage asserts a req to instruction core interface
logic instr_req_gated;
// Writeback stage
logic en_wb;
wb_instr_type_e instr_type_wb;
logic ready_wb;
logic rf_write_wb;
logic outstanding_load_wb;
logic outstanding_store_wb;
// Writeback
logic en_wb;
// Interrupts
logic nmi_mode;
@ -247,7 +237,6 @@ module cve2_core import cve2_pkg::*; #(
logic csr_save_if;
logic csr_save_id;
logic csr_save_wb;
logic csr_restore_mret_id;
logic csr_restore_dret_id;
logic csr_save_cause;
@ -270,11 +259,9 @@ module cve2_core import cve2_pkg::*; #(
// signals relating to instruction movements between pipeline stages
// used by performance counters and RVFI
logic instr_id_done;
logic instr_done_wb;
logic perf_instr_ret_wb;
logic perf_instr_ret_compressed_wb;
logic perf_instr_ret_wb_spec;
logic perf_instr_ret_compressed_wb_spec;
logic perf_iside_wait;
logic perf_dside_wait;
@ -375,7 +362,6 @@ module cve2_core import cve2_pkg::*; #(
.RV32E (RV32E),
.RV32M (RV32M),
.RV32B (RV32B),
.WritebackStage (WritebackStage),
.BranchPredictor(BranchPredictor)
) id_stage_i (
.clk_i (clk_i),
@ -434,7 +420,6 @@ module cve2_core import cve2_pkg::*; #(
.multdiv_signed_mode_ex_o(multdiv_signed_mode_ex),
.multdiv_operand_a_ex_o (multdiv_operand_a_ex),
.multdiv_operand_b_ex_o (multdiv_operand_b_ex),
.multdiv_ready_id_o (multdiv_ready_id),
// CSR ID/EX
.csr_access_o (csr_access),
@ -442,7 +427,6 @@ module cve2_core import cve2_pkg::*; #(
.csr_op_en_o (csr_op_en),
.csr_save_if_o (csr_save_if), // control signal to save PC
.csr_save_id_o (csr_save_id), // control signal to save PC
.csr_save_wb_o (csr_save_wb), // control signal to save PC
.csr_restore_mret_id_o(csr_restore_mret_id), // restore mstatus upon MRET
.csr_restore_dret_id_o(csr_restore_dret_id), // restore mstatus upon MRET
.csr_save_cause_o (csr_save_cause),
@ -457,7 +441,6 @@ module cve2_core import cve2_pkg::*; #(
.lsu_type_o (lsu_type), // to load store unit
.lsu_sign_ext_o(lsu_sign_ext), // to load store unit
.lsu_wdata_o (lsu_wdata), // to load store unit
.lsu_req_done_i(lsu_req_done), // from load store unit
.lsu_addr_incr_req_i(lsu_addr_incr_req),
.lsu_addr_last_i (lsu_addr_last),
@ -495,19 +478,9 @@ module cve2_core import cve2_pkg::*; #(
.rf_waddr_id_o (rf_waddr_id),
.rf_wdata_id_o (rf_wdata_id),
.rf_we_id_o (rf_we_id),
.rf_rd_a_wb_match_o(),
.rf_rd_b_wb_match_o(),
.rf_waddr_wb_i (rf_waddr_wb),
.rf_wdata_fwd_wb_i(rf_wdata_fwd_wb),
.rf_write_wb_i (rf_write_wb),
.en_wb_o (en_wb),
.instr_type_wb_o (instr_type_wb),
.en_wb_o (en_wb),
.instr_perf_count_id_o (instr_perf_count_id),
.ready_wb_i (ready_wb),
.outstanding_load_wb_i (outstanding_load_wb),
.outstanding_store_wb_i(outstanding_store_wb),
// Performance Counters
.perf_jump_o (perf_jump),
@ -544,7 +517,6 @@ module cve2_core import cve2_pkg::*; #(
.multdiv_signed_mode_i(multdiv_signed_mode_ex),
.multdiv_operand_a_i (multdiv_operand_a_ex),
.multdiv_operand_b_i (multdiv_operand_b_ex),
.multdiv_ready_id_i (multdiv_ready_id),
// Intermediate value register
.imd_val_we_o(imd_val_we_ex),
@ -594,7 +566,6 @@ module cve2_core import cve2_pkg::*; #(
.lsu_rdata_o (rf_wdata_lsu),
.lsu_rdata_valid_o(rf_we_lsu),
.lsu_req_i (lsu_req),
.lsu_req_done_o (lsu_req_done),
.adder_result_ex_i(alu_adder_result_ex),
@ -614,26 +585,17 @@ module cve2_core import cve2_pkg::*; #(
.perf_store_o(perf_store)
);
cve2_wb_stage #(
.WritebackStage(WritebackStage)
) wb_stage_i (
.clk_i (clk_i),
.rst_ni (rst_ni),
.en_wb_i (en_wb),
.instr_type_wb_i (instr_type_wb),
.pc_id_i (pc_id),
cve2_wb #(
) wb_i (
.clk_i (clk_i),
.rst_ni (rst_ni),
.en_wb_i (en_wb),
.instr_is_compressed_id_i(instr_is_compressed_id),
.instr_perf_count_id_i (instr_perf_count_id),
.ready_wb_o (ready_wb),
.rf_write_wb_o (rf_write_wb),
.outstanding_load_wb_o (outstanding_load_wb),
.outstanding_store_wb_o (outstanding_store_wb),
.pc_wb_o (pc_wb),
.perf_instr_ret_wb_o (perf_instr_ret_wb),
.perf_instr_ret_compressed_wb_o (perf_instr_ret_compressed_wb),
.perf_instr_ret_wb_spec_o (perf_instr_ret_wb_spec),
.perf_instr_ret_compressed_wb_spec_o(perf_instr_ret_compressed_wb_spec),
.rf_waddr_id_i(rf_waddr_id),
.rf_wdata_id_i(rf_wdata_id),
@ -642,16 +604,12 @@ module cve2_core import cve2_pkg::*; #(
.rf_wdata_lsu_i(rf_wdata_lsu),
.rf_we_lsu_i (rf_we_lsu),
.rf_wdata_fwd_wb_o(rf_wdata_fwd_wb),
.rf_waddr_wb_o(rf_waddr_wb),
.rf_wdata_wb_o(rf_wdata_wb),
.rf_we_wb_o (rf_we_wb),
.lsu_resp_valid_i(lsu_resp_valid),
.lsu_resp_err_i (lsu_resp_err),
.instr_done_wb_o(instr_done_wb)
.lsu_resp_err_i (lsu_resp_err)
);
///////////////////////
@ -678,19 +636,7 @@ module cve2_core import cve2_pkg::*; #(
assign outstanding_store_id = id_stage_i.instr_executing & id_stage_i.lsu_req_dec &
id_stage_i.lsu_we;
if (WritebackStage) begin : gen_wb_stage
// When the writeback stage is present a load/store could be in ID or WB. A Load/store in ID can
// see a response before it moves to WB when it is unaligned otherwise we should only see
// a response when load/store is in WB.
assign outstanding_load_resp = outstanding_load_wb |
(outstanding_load_id & load_store_unit_i.split_misaligned_access);
assign outstanding_store_resp = outstanding_store_wb |
(outstanding_store_id & load_store_unit_i.split_misaligned_access);
// When writing back the result of a load, the load must have made it to writeback
`ASSERT(NoMemRFWriteWithoutPendingLoad, rf_we_lsu |-> outstanding_load_wb, clk_i, !rst_ni)
end else begin : gen_no_wb_stage
begin : gen_no_wb_stage
// Without writeback stage only look into whether load or store is in ID to determine if
// a response is expected.
assign outstanding_load_resp = outstanding_load_id;
@ -795,11 +741,9 @@ module cve2_core import cve2_pkg::*; #(
.pc_if_i(pc_if),
.pc_id_i(pc_id),
.pc_wb_i(pc_wb),
.csr_save_if_i (csr_save_if),
.csr_save_id_i (csr_save_id),
.csr_save_wb_i (csr_save_wb),
.csr_restore_mret_i(csr_restore_mret_id),
.csr_restore_dret_i(csr_restore_dret_id),
.csr_save_cause_i (csr_save_cause),
@ -810,8 +754,6 @@ module cve2_core import cve2_pkg::*; #(
// performance counter related signals
.instr_ret_i (perf_instr_ret_wb),
.instr_ret_compressed_i (perf_instr_ret_compressed_wb),
.instr_ret_spec_i (perf_instr_ret_wb_spec),
.instr_ret_compressed_spec_i(perf_instr_ret_compressed_wb_spec),
.iside_wait_i (perf_iside_wait),
.jump_i (perf_jump),
.branch_i (perf_branch),
@ -888,7 +830,7 @@ module cve2_core import cve2_pkg::*; #(
// second stage. RVFI outputs are all straight from flops. So 2 stage pipeline requires a single
// set of flops (instr_info => RVFI_out), 3 stage pipeline requires two sets (instr_info => wb
// => RVFI_out)
localparam int RVFI_STAGES = WritebackStage ? 2 : 1;
localparam int RVFI_STAGES = 1;
logic rvfi_stage_valid [RVFI_STAGES];
logic [63:0] rvfi_stage_order [RVFI_STAGES];
@ -945,10 +887,8 @@ module cve2_core import cve2_pkg::*; #(
logic [31:0] rvfi_mem_addr_d;
logic [31:0] rvfi_mem_addr_q;
logic rvfi_trap_id;
logic rvfi_trap_wb;
logic [63:0] rvfi_stage_order_d;
logic rvfi_id_done;
logic rvfi_wb_done;
logic new_debug_req;
logic new_nmi;
@ -1021,41 +961,7 @@ module cve2_core import cve2_pkg::*; #(
assign rvfi_id_done = instr_id_done | (id_stage_i.controller_i.rvfi_flush_next &
id_stage_i.controller_i.id_exception_o);
if (WritebackStage) begin : gen_rvfi_wb_stage
logic unused_instr_new_id;
assign unused_instr_new_id = instr_new_id;
// With writeback stage first RVFI stage buffers instruction information captured in ID/EX
// awaiting instruction retirement and RF Write data/Mem read data whilst instruction is in WB
// So first stage becomes valid when instruction leaves ID/EX stage and remains valid until
// instruction leaves WB
assign rvfi_stage_valid_d[0] = rvfi_id_done |
(rvfi_stage_valid[0] & ~rvfi_wb_done);
// Second stage is output stage so simple valid cycle after instruction leaves WB (and so has
// retired)
assign rvfi_stage_valid_d[1] = rvfi_wb_done;
// Signal new instruction in WB cycle after instruction leaves ID/EX (to enter WB)
logic rvfi_instr_new_wb_q;
// Signal new instruction in WB either when one has just entered or when a trap is progressing
// through the tracking pipeline
assign rvfi_instr_new_wb = rvfi_instr_new_wb_q | (rvfi_stage_valid[0] & rvfi_stage_trap[0]);
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_instr_new_wb_q <= 0;
end else begin
rvfi_instr_new_wb_q <= rvfi_id_done;
end
end
assign rvfi_trap_id = id_stage_i.controller_i.id_exception_o;
assign rvfi_trap_wb = id_stage_i.controller_i.exc_req_lsu;
// WB is instantly done in the tracking pipeline when a trap is progress through the pipeline
assign rvfi_wb_done = instr_done_wb | (rvfi_stage_valid[0] & rvfi_stage_trap[0]);
end else begin : gen_rvfi_no_wb_stage
begin : gen_rvfi_no_wb_stage
// Without writeback stage first RVFI stage is output stage so simply valid the cycle after
// instruction leaves ID/EX (and so has retired)
assign rvfi_stage_valid_d[0] = rvfi_id_done;
@ -1063,8 +969,6 @@ module cve2_core import cve2_pkg::*; #(
// setup register write signals
assign rvfi_instr_new_wb = instr_new_id;
assign rvfi_trap_id = id_stage_i.controller_i.exc_req_d | id_stage_i.controller_i.exc_req_lsu;
assign rvfi_trap_wb = 1'b0;
assign rvfi_wb_done = instr_done_wb;
end
assign rvfi_stage_order_d = rvfi_stage_order[0] + 64'd1;
@ -1202,9 +1106,8 @@ module cve2_core import cve2_pkg::*; #(
rvfi_ext_stage_mcycle[i] <= cs_registers_i.mcycle_counter_i.counter_val_o;
end
end else begin
if (rvfi_wb_done) begin
rvfi_stage_halt[i] <= rvfi_stage_halt[i-1];
rvfi_stage_trap[i] <= rvfi_stage_trap[i-1] | rvfi_trap_wb;
rvfi_stage_trap[i] <= rvfi_stage_trap[i-1];
rvfi_stage_intr[i] <= rvfi_stage_intr[i-1];
rvfi_stage_order[i] <= rvfi_stage_order[i-1];
rvfi_stage_insn[i] <= rvfi_stage_insn[i-1];
@ -1235,7 +1138,6 @@ module cve2_core import cve2_pkg::*; #(
rvfi_ext_stage_nmi[i+1] <= rvfi_ext_stage_nmi[i];
rvfi_ext_stage_debug_req[i+1] <= rvfi_ext_stage_debug_req[i];
rvfi_ext_stage_mcycle[i] <= rvfi_ext_stage_mcycle[i-1];
end
end
end
end
@ -1388,10 +1290,9 @@ module cve2_core import cve2_pkg::*; #(
end
`else
logic unused_instr_new_id, unused_instr_id_done, unused_instr_done_wb;
logic unused_instr_new_id, unused_instr_id_done;
assign unused_instr_id_done = instr_id_done;
assign unused_instr_new_id = instr_new_id;
assign unused_instr_done_wb = instr_done_wb;
`endif
endmodule

View file

@ -77,12 +77,10 @@ module cve2_cs_registers #(
input logic [31:0] pc_if_i,
input logic [31:0] pc_id_i,
input logic [31:0] pc_wb_i,
// Exception save/restore
input logic csr_save_if_i,
input logic csr_save_id_i,
input logic csr_save_wb_i,
input logic csr_restore_mret_i,
input logic csr_restore_dret_i,
input logic csr_save_cause_i,
@ -94,8 +92,6 @@ module cve2_cs_registers #(
// Performance Counters
input logic instr_ret_i, // instr retired in ID/EX stage
input logic instr_ret_compressed_i, // compressed instr retired
input logic instr_ret_spec_i, // speculative instr_ret_i
input logic instr_ret_compressed_spec_i, // speculative instr_ret_compressed_i
input logic iside_wait_i, // core waiting for the iside
input logic jump_i, // jump instr seen (j, jr, jal, jalr)
input logic branch_i, // branch instr seen (bf, bnf)
@ -623,9 +619,6 @@ module cve2_cs_registers #(
csr_save_id_i: begin
exception_pc = pc_id_i;
end
csr_save_wb_i: begin
exception_pc = pc_wb_i;
end
default:;
endcase
@ -1237,7 +1230,7 @@ module cve2_cs_registers #(
// so the incorrect value doesn't matter. A similar behaviour is required for the compressed
// instruction retired counter below. When the writeback stage isn't present the speculative
// signals are always 0.
assign mhpmcounter[2] = instr_ret_spec_i & ~mcountinhibit[2] ? minstret_next : minstret_raw;
assign mhpmcounter[2] = minstret_raw;
// reserved:
assign mhpmcounter[1] = '0;
@ -1270,7 +1263,6 @@ module cve2_cs_registers #(
// Special behaviour for reading compressed instruction retired counter, see comment on
// `mhpmcounter[2]` above for further information.
assign mhpmcounter[Cnt] =
instr_ret_compressed_spec_i & ~mcountinhibit[Cnt] ? mhpmcounter_next:
mhpmcounter_raw;
end else begin : gen_other_cnts
logic [63:0] unused_mhpmcounter_next;
@ -1280,11 +1272,6 @@ module cve2_cs_registers #(
end
end else begin : gen_unimp
assign mhpmcounter[Cnt] = '0;
if (Cnt == 10) begin : gen_no_compressed_instr_cnt
logic unused_instr_ret_compressed_spec_i;
assign unused_instr_ret_compressed_spec_i = instr_ret_compressed_spec_i;
end
end
end

View file

@ -30,7 +30,6 @@ module cve2_ex_block #(
input logic [1:0] multdiv_signed_mode_i,
input logic [31:0] multdiv_operand_a_i,
input logic [31:0] multdiv_operand_b_i,
input logic multdiv_ready_id_i,
// intermediate val reg
output logic [1:0] imd_val_we_o,
@ -138,7 +137,6 @@ module cve2_ex_block #(
.imd_val_q_i (imd_val_q_i),
.imd_val_d_o (multdiv_imd_val_d),
.imd_val_we_o (multdiv_imd_val_we),
.multdiv_ready_id_i(multdiv_ready_id_i),
.multdiv_result_o (multdiv_result)
);
end else if (RV32M == RV32MFast || RV32M == RV32MSingleCycle) begin : gen_multdiv_fast
@ -163,7 +161,6 @@ module cve2_ex_block #(
.imd_val_q_i (imd_val_q_i),
.imd_val_d_o (multdiv_imd_val_d),
.imd_val_we_o (multdiv_imd_val_we),
.multdiv_ready_id_i(multdiv_ready_id_i),
.valid_o (multdiv_valid),
.multdiv_result_o (multdiv_result)
);

View file

@ -21,7 +21,6 @@ module cve2_id_stage #(
parameter bit RV32E = 0,
parameter cve2_pkg::rv32m_e RV32M = cve2_pkg::RV32MFast,
parameter cve2_pkg::rv32b_e RV32B = cve2_pkg::RV32BNone,
parameter bit WritebackStage = 0,
parameter bit BranchPredictor = 0
) (
input logic clk_i,
@ -81,7 +80,6 @@ module cve2_id_stage #(
output logic [1:0] multdiv_signed_mode_ex_o,
output logic [31:0] multdiv_operand_a_ex_o,
output logic [31:0] multdiv_operand_b_ex_o,
output logic multdiv_ready_id_o,
// CSR
output logic csr_access_o,
@ -89,7 +87,6 @@ module cve2_id_stage #(
output logic csr_op_en_o,
output logic csr_save_if_o,
output logic csr_save_id_o,
output logic csr_save_wb_o,
output logic csr_restore_mret_id_o,
output logic csr_restore_dret_id_o,
output logic csr_save_cause_o,
@ -105,11 +102,6 @@ module cve2_id_stage #(
output logic lsu_sign_ext_o,
output logic [31:0] lsu_wdata_o,
input logic lsu_req_done_i, // Data req to LSU is complete and
// instruction can move to writeback
// (only relevant where writeback stage is
// present)
input logic lsu_addr_incr_req_i,
input logic [31:0] lsu_addr_last_i,
@ -149,20 +141,9 @@ module cve2_id_stage #(
output logic [4:0] rf_waddr_id_o,
output logic [31:0] rf_wdata_id_o,
output logic rf_we_id_o,
output logic rf_rd_a_wb_match_o,
output logic rf_rd_b_wb_match_o,
// Register write information from writeback (for resolving data hazards)
input logic [4:0] rf_waddr_wb_i,
input logic [31:0] rf_wdata_fwd_wb_i,
input logic rf_write_wb_i,
output logic en_wb_o,
output cve2_pkg::wb_instr_type_e instr_type_wb_o,
output logic instr_perf_count_id_o,
input logic ready_wb_i,
input logic outstanding_load_wb_i,
input logic outstanding_store_wb_i,
// Performance Counters
output logic perf_jump_o, // executing a jump instr
@ -185,9 +166,6 @@ module cve2_id_stage #(
logic ecall_insn_dec;
logic wfi_insn_dec;
logic wb_exception;
logic id_exception;
logic branch_in_dec;
logic branch_set, branch_set_raw, branch_set_raw_d;
logic branch_jump_set_done_q, branch_jump_set_done_d;
@ -201,13 +179,11 @@ module cve2_id_stage #(
logic instr_executing;
logic instr_done;
logic controller_run;
logic stall_ld_hz;
logic stall_mem;
logic stall_multdiv;
logic stall_branch;
logic stall_jump;
logic stall_id;
logic stall_wb;
logic flush_id;
logic multicycle_done;
@ -473,7 +449,6 @@ module cve2_id_stage #(
assign illegal_insn_o = instr_valid_i & (illegal_insn_dec | illegal_csr_insn_i);
cve2_controller #(
.WritebackStage (WritebackStage),
.BranchPredictor(BranchPredictor)
) controller_i (
.clk_i (clk_i),
@ -517,8 +492,6 @@ module cve2_id_stage #(
.lsu_addr_last_i(lsu_addr_last_i),
.load_err_i (lsu_load_err_i),
.store_err_i (lsu_store_err_i),
.wb_exception_o (wb_exception),
.id_exception_o (id_exception),
// jump/branch control
.branch_set_i (branch_set),
@ -535,7 +508,6 @@ module cve2_id_stage #(
// CSR Controller Signals
.csr_save_if_o (csr_save_if_o),
.csr_save_id_o (csr_save_id_o),
.csr_save_wb_o (csr_save_wb_o),
.csr_restore_mret_id_o(csr_restore_mret_id_o),
.csr_restore_dret_id_o(csr_restore_dret_id_o),
.csr_save_cause_o (csr_save_cause_o),
@ -554,9 +526,7 @@ module cve2_id_stage #(
.trigger_match_i (trigger_match_i),
.stall_id_i(stall_id),
.stall_wb_i(stall_wb),
.flush_id_o(flush_id),
.ready_wb_i(ready_wb_i),
// Performance Counters
.perf_jump_o (perf_jump_o),
@ -690,13 +660,9 @@ module cve2_id_stage #(
FIRST_CYCLE: begin
unique case (1'b1)
lsu_req_dec: begin
if (!WritebackStage) begin
begin
// LSU operation
id_fsm_d = MULTI_CYCLE;
end else begin
if(~lsu_req_done_i) begin
id_fsm_d = MULTI_CYCLE;
end
end
end
multdiv_en_dec: begin
@ -747,7 +713,7 @@ module cve2_id_stage #(
rf_we_raw = rf_we_dec & ex_valid_i;
end
if (multicycle_done & ready_wb_i) begin
if (multicycle_done) begin
id_fsm_d = FIRST_CYCLE;
end else begin
stall_multdiv = multdiv_en_dec;
@ -763,22 +729,19 @@ module cve2_id_stage #(
end
end
// Note for the two-stage configuration ready_wb_i is always set
assign multdiv_ready_id_o = ready_wb_i;
`ASSERT(StallIDIfMulticycle, (id_fsm_q == FIRST_CYCLE) & (id_fsm_d == MULTI_CYCLE) |-> stall_id)
// Stall ID/EX stage for reason that relates to instruction in ID/EX, update assertion below if
// modifying this.
assign stall_id = stall_ld_hz | stall_mem | stall_multdiv | stall_jump | stall_branch |
assign stall_id = stall_mem | stall_multdiv | stall_jump | stall_branch |
stall_alu;
// Generally illegal instructions have no reason to stall, however they must still stall waiting
// for outstanding memory requests so exceptions related to them take priority over the illegal
// instruction exception.
`ASSERT(IllegalInsnStallMustBeMemStall, illegal_insn_o & stall_id |-> stall_mem &
~(stall_ld_hz | stall_multdiv | stall_jump | stall_branch | stall_alu))
~(stall_multdiv | stall_jump | stall_branch | stall_alu))
assign instr_done = ~stall_id & ~flush_id & instr_executing;
@ -789,119 +752,6 @@ module cve2_id_stage #(
// Used by ALU to access RS3 if ternary instruction.
assign instr_first_cycle_id_o = instr_first_cycle;
if (WritebackStage) begin : gen_stall_mem
// Register read address matches write address in WB
logic rf_rd_a_wb_match;
logic rf_rd_b_wb_match;
// Hazard between registers being read and written
logic rf_rd_a_hz;
logic rf_rd_b_hz;
logic outstanding_memory_access;
logic instr_kill;
assign multicycle_done = lsu_req_dec ? ~stall_mem : ex_valid_i;
// Is a memory access ongoing that isn't finishing this cycle
assign outstanding_memory_access = (outstanding_load_wb_i | outstanding_store_wb_i) &
~lsu_resp_valid_i;
// Can start a new memory access if any previous one has finished or is finishing
assign data_req_allowed = ~outstanding_memory_access;
// Instruction won't execute because:
// - There is a pending exception in writeback
// The instruction in ID/EX will be flushed and the core will jump to an exception handler
// - The controller isn't running instructions
// This either happens in preparation for a flush and jump to an exception handler e.g. in
// response to an IRQ or debug request or whilst the core is sleeping or resetting/fetching
// first instruction in which case any valid instruction in ID/EX should be ignored.
// - There was an error on instruction fetch
assign instr_kill = instr_fetch_err_i |
wb_exception |
id_exception |
~controller_run;
// With writeback stage instructions must be prevented from executing if there is:
// - A load hazard
// - A pending memory access
// If it receives an error response this results in a precise exception from WB so ID/EX
// instruction must not execute until error response is known).
// - A load/store error
// This will cause a precise exception for the instruction in WB so ID/EX instruction must not
// execute
//
// instr_executing_spec is a speculative signal. It indicates an instruction can execute
// assuming there are no exceptions from writeback and any outstanding memory access won't
// receive an error. It is required so branch and jump requests don't factor in an incoming dmem
// error (that in turn would factor directly into imem requests leading to a feedthrough path).
//
// instr_executing is the full signal, it will only allow execution once any potential
// exceptions from writeback have been resolved.
assign instr_executing_spec = instr_valid_i &
~instr_fetch_err_i &
controller_run &
~stall_ld_hz;
assign instr_executing = instr_valid_i &
~instr_kill &
~stall_ld_hz &
~outstanding_memory_access;
`ASSERT(IbexExecutingSpecIfExecuting, instr_executing |-> instr_executing_spec)
`ASSERT(IbexStallIfValidInstrNotExecuting,
instr_valid_i & ~instr_kill & ~instr_executing |-> stall_id)
`ASSERT(IbexCannotRetireWithPendingExceptions,
instr_done |-> ~(wb_exception | outstanding_memory_access))
// Stall for reasons related to memory:
// * There is an outstanding memory access that won't resolve this cycle (need to wait to allow
// precise exceptions)
// * There is a load/store request not being granted or which is unaligned and waiting to issue
// a second request (needs to stay in ID for the address calculation)
assign stall_mem = instr_valid_i &
(outstanding_memory_access | (lsu_req_dec & ~lsu_req_done_i));
// If we stall a load in ID for any reason, it must not make an LSU request
// (otherwide we might issue two requests for the same instruction)
`ASSERT(IbexStallMemNoRequest,
instr_valid_i & lsu_req_dec & ~instr_done |-> ~lsu_req_done_i)
assign rf_rd_a_wb_match = (rf_waddr_wb_i == rf_raddr_a_o) & |rf_raddr_a_o;
assign rf_rd_b_wb_match = (rf_waddr_wb_i == rf_raddr_b_o) & |rf_raddr_b_o;
assign rf_rd_a_wb_match_o = rf_rd_a_wb_match;
assign rf_rd_b_wb_match_o = rf_rd_b_wb_match;
// If instruction is reading register that load will be writing stall in
// ID until load is complete. No need to stall when reading zero register.
assign rf_rd_a_hz = rf_rd_a_wb_match & rf_ren_a;
assign rf_rd_b_hz = rf_rd_b_wb_match & rf_ren_b;
// If instruction is read register that writeback is writing forward writeback data to read
// data. Note this doesn't factor in load data as it arrives too late, such hazards are
// resolved via a stall (see above).
assign rf_rdata_a_fwd = rf_rd_a_wb_match & rf_write_wb_i ? rf_wdata_fwd_wb_i : rf_rdata_a_i;
assign rf_rdata_b_fwd = rf_rd_b_wb_match & rf_write_wb_i ? rf_wdata_fwd_wb_i : rf_rdata_b_i;
assign stall_ld_hz = outstanding_load_wb_i & (rf_rd_a_hz | rf_rd_b_hz);
assign instr_type_wb_o = ~lsu_req_dec ? WB_INSTR_OTHER :
lsu_we ? WB_INSTR_STORE :
WB_INSTR_LOAD;
assign instr_id_done_o = en_wb_o & ready_wb_i;
// Stall ID/EX as instruction in ID/EX cannot proceed to writeback yet
assign stall_wb = en_wb_o & ~ready_wb_i;
assign perf_dside_wait_o = instr_valid_i & ~instr_kill &
(outstanding_memory_access | stall_ld_hz);
end else begin : gen_no_stall_mem
assign multicycle_done = lsu_req_dec ? lsu_resp_valid_i : ex_valid_i;
assign data_req_allowed = instr_first_cycle;
@ -910,9 +760,6 @@ module cve2_id_stage #(
// Then stall until it is complete
assign stall_mem = instr_valid_i & (lsu_req_dec & (~lsu_resp_valid_i | instr_first_cycle));
// No load hazards without Writeback Stage
assign stall_ld_hz = 1'b0;
// Without writeback stage any valid instruction that hasn't seen an error will execute
assign instr_executing_spec = instr_valid_i & ~instr_fetch_err_i & controller_run;
assign instr_executing = instr_executing_spec;
@ -925,45 +772,21 @@ module cve2_id_stage #(
assign rf_rdata_a_fwd = rf_rdata_a_i;
assign rf_rdata_b_fwd = rf_rdata_b_i;
assign rf_rd_a_wb_match_o = 1'b0;
assign rf_rd_b_wb_match_o = 1'b0;
// Unused Writeback stage only IO & wiring
// Assign inputs and internal wiring to unused signals to satisfy lint checks
// Tie-off outputs to constant values
logic unused_data_req_done_ex;
logic [4:0] unused_rf_waddr_wb;
logic unused_rf_write_wb;
logic unused_outstanding_load_wb;
logic unused_outstanding_store_wb;
logic unused_wb_exception;
logic [31:0] unused_rf_wdata_fwd_wb;
logic unused_id_exception;
assign unused_data_req_done_ex = lsu_req_done_i;
assign unused_rf_waddr_wb = rf_waddr_wb_i;
assign unused_rf_write_wb = rf_write_wb_i;
assign unused_outstanding_load_wb = outstanding_load_wb_i;
assign unused_outstanding_store_wb = outstanding_store_wb_i;
assign unused_wb_exception = wb_exception;
assign unused_rf_wdata_fwd_wb = rf_wdata_fwd_wb_i;
assign unused_id_exception = id_exception;
assign instr_type_wb_o = WB_INSTR_OTHER;
assign stall_wb = 1'b0;
assign perf_dside_wait_o = instr_executing & lsu_req_dec & ~lsu_resp_valid_i;
assign instr_id_done_o = instr_done;
end
// Signal which instructions to count as retired in minstret, all traps along with ebrk and
// ecall instructions are not counted.
assign instr_perf_count_id_o = ~ebrk_insn & ~ecall_insn_dec & ~illegal_insn_dec &
~illegal_csr_insn_i & ~instr_fetch_err_i;
// An instruction is ready to move to the writeback stage (or retire if there is no writeback
// stage)
// An instruction is ready to move to the writeback
assign en_wb_o = instr_done;
assign perf_wfi_wait_o = wfi_insn_dec;
@ -973,8 +796,8 @@ module cve2_id_stage #(
// FCOV //
//////////
`DV_FCOV_SIGNAL_GEN_IF(logic, rf_rd_wb_hz,
(gen_stall_mem.rf_rd_a_hz | gen_stall_mem.rf_rd_b_hz) & instr_valid_i, WritebackStage)
`DV_FCOV_SIGNAL(logic, branch_taken,
instr_executing & (id_fsm_q == FIRST_CYCLE) & branch_decision_i)
`DV_FCOV_SIGNAL(logic, branch_not_taken,
instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i)

View file

@ -50,10 +50,6 @@ module cve2_load_store_unit
// -> mtval
// -> AGU for misaligned accesses
output logic lsu_req_done_o, // Signals that data request is complete
// (only need to await final data
// response) -> to ID/EX
output logic lsu_resp_valid_o, // LSU has response from transaction -> to ID/EX
// exception signals
@ -453,8 +449,6 @@ module cve2_load_store_unit
endcase
end
assign lsu_req_done_o = (lsu_req_i | (ls_fsm_cs != IDLE)) & (ls_fsm_ns == IDLE);
// registers for FSM
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin

View file

@ -38,8 +38,6 @@ module cve2_multdiv_fast #(
output logic [33:0] imd_val_d_o[2],
output logic [1:0] imd_val_we_o,
input logic multdiv_ready_id_i,
output logic [31:0] multdiv_result_o,
output logic valid_o
);
@ -209,7 +207,7 @@ module cve2_multdiv_fast #(
mult_valid = 1'b0;
mult_state_d = MULH;
end else begin
mult_hold = ~multdiv_ready_id_i;
mult_hold = 1'b0;
end
end
@ -228,7 +226,7 @@ module cve2_multdiv_fast #(
mult_state_d = MULL;
mult_valid = 1'b1;
mult_hold = ~multdiv_ready_id_i;
mult_hold = 1'b0;
end
default: begin
@ -327,7 +325,7 @@ module cve2_multdiv_fast #(
// Note no state transition will occur if mult_hold is set
mult_state_d = ALBL;
mult_hold = ~multdiv_ready_id_i;
mult_hold = 1'b0;
end else begin
accum = imd_val_q_i[0];
mac_res_d = mac_res;
@ -350,7 +348,7 @@ module cve2_multdiv_fast #(
// Note no state transition will occur if mult_hold is set
mult_state_d = ALBL;
mult_hold = ~multdiv_ready_id_i;
mult_hold = 1'b0;
end
default: begin
mult_state_d = ALBL;
@ -507,7 +505,7 @@ module cve2_multdiv_fast #(
// Hold result until ID stage is ready to accept it
// Note no state transition will occur if div_hold is set
md_state_d = MD_IDLE;
div_hold = ~multdiv_ready_id_i;
div_hold = 1'b0;
div_valid = 1'b1;
end

View file

@ -17,7 +17,6 @@ module cve2_top import cve2_pkg::*; #(
parameter int unsigned MHPMCounterWidth = 40,
parameter bit RV32E = 1'b0,
parameter rv32m_e RV32M = RV32MFast,
parameter bit WritebackStage = 1'b0,
parameter bit BranchPredictor = 1'b0,
parameter int unsigned DmHaltAddr = 32'h1A110800,
parameter int unsigned DmExceptionAddr = 32'h1A110808
@ -158,7 +157,6 @@ module cve2_top import cve2_pkg::*; #(
.BranchPredictor (BranchPredictor),
.DbgTriggerEn (DbgTriggerEn),
.DbgHwBreakNum (DbgHwBreakNum),
.WritebackStage (WritebackStage),
.DmHaltAddr (DmHaltAddr),
.DmExceptionAddr (DmExceptionAddr)
) u_cve2_core (

View file

@ -12,7 +12,6 @@ module cve2_top_tracing import cve2_pkg::*; #(
parameter bit RV32E = 1'b0,
parameter rv32m_e RV32M = RV32MFast,
parameter rv32b_e RV32B = RV32BNone,
parameter bit WritebackStage = 1'b0,
parameter bit BranchPredictor = 1'b0,
parameter bit DbgTriggerEn = 1'b0,
parameter int unsigned DbgHwBreakNum = 1,
@ -126,7 +125,6 @@ module cve2_top_tracing import cve2_pkg::*; #(
.BranchPredictor ( BranchPredictor ),
.DbgTriggerEn ( DbgTriggerEn ),
.DbgHwBreakNum ( DbgHwBreakNum ),
.WritebackStage ( WritebackStage ),
.DmHaltAddr ( DmHaltAddr ),
.DmExceptionAddr ( DmExceptionAddr )
) u_cve2_top (

71
rtl/cve2_wb.sv Normal file
View file

@ -0,0 +1,71 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* Writeback passthrough
*
* The writeback stage is not present therefore this module acts as
* a simple passthrough to write data direct to the register file.
*/
`include "prim_assert.sv"
`include "dv_fcov_macros.svh"
module cve2_wb #(
) (
input logic clk_i,
input logic rst_ni,
input logic en_wb_i,
input logic instr_is_compressed_id_i,
input logic instr_perf_count_id_i,
output logic perf_instr_ret_wb_o,
output logic perf_instr_ret_compressed_wb_o,
input logic [4:0] rf_waddr_id_i,
input logic [31:0] rf_wdata_id_i,
input logic rf_we_id_i,
input logic [31:0] rf_wdata_lsu_i,
input logic rf_we_lsu_i,
output logic [4:0] rf_waddr_wb_o,
output logic [31:0] rf_wdata_wb_o,
output logic rf_we_wb_o,
input logic lsu_resp_valid_i,
input logic lsu_resp_err_i
);
import cve2_pkg::*;
// 0 == RF write from ID
// 1 == RF write from LSU
logic [31:0] rf_wdata_wb_mux [2];
logic [1:0] rf_wdata_wb_mux_we;
// without writeback stage just pass through register write signals
assign rf_waddr_wb_o = rf_waddr_id_i;
assign rf_wdata_wb_mux[0] = rf_wdata_id_i;
assign rf_wdata_wb_mux_we[0] = rf_we_id_i;
// Increment instruction retire counters for valid instructions which are not lsu errors.
assign perf_instr_ret_wb_o = instr_perf_count_id_i & en_wb_i &
~(lsu_resp_valid_i & lsu_resp_err_i);
assign perf_instr_ret_compressed_wb_o = perf_instr_ret_wb_o & instr_is_compressed_id_i;
assign rf_wdata_wb_mux[1] = rf_wdata_lsu_i;
assign rf_wdata_wb_mux_we[1] = rf_we_lsu_i;
// RF write data can come from ID results (all RF writes that aren't because of loads will come
// from here) or the LSU (RF writes for load data)
assign rf_wdata_wb_o = ({32{rf_wdata_wb_mux_we[0]}} & rf_wdata_wb_mux[0]) |
({32{rf_wdata_wb_mux_we[1]}} & rf_wdata_wb_mux[1]);
assign rf_we_wb_o = |rf_wdata_wb_mux_we;
`DV_FCOV_SIGNAL_GEN_IF(logic, wb_valid, g_writeback_stage.wb_valid_q, 1'b0)
`ASSERT(RFWriteFromOneSourceOnly, $onehot0(rf_wdata_wb_mux_we))
endmodule

View file

@ -1,201 +0,0 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* Writeback Stage
*
* Writeback is an optional third pipeline stage. It writes data back to the register file that was
* produced in the ID/EX stage or awaits a response to a load/store (LSU writes direct to register
* file for load data). If the writeback stage is not present (WritebackStage == 0) this acts as
* a simple passthrough to write data direct to the register file.
*/
`include "prim_assert.sv"
`include "dv_fcov_macros.svh"
module cve2_wb_stage #(
parameter bit WritebackStage = 1'b0
) (
input logic clk_i,
input logic rst_ni,
input logic en_wb_i,
input cve2_pkg::wb_instr_type_e instr_type_wb_i,
input logic [31:0] pc_id_i,
input logic instr_is_compressed_id_i,
input logic instr_perf_count_id_i,
output logic ready_wb_o,
output logic rf_write_wb_o,
output logic outstanding_load_wb_o,
output logic outstanding_store_wb_o,
output logic [31:0] pc_wb_o,
output logic perf_instr_ret_wb_o,
output logic perf_instr_ret_compressed_wb_o,
output logic perf_instr_ret_wb_spec_o,
output logic perf_instr_ret_compressed_wb_spec_o,
input logic [4:0] rf_waddr_id_i,
input logic [31:0] rf_wdata_id_i,
input logic rf_we_id_i,
input logic [31:0] rf_wdata_lsu_i,
input logic rf_we_lsu_i,
output logic [31:0] rf_wdata_fwd_wb_o,
output logic [4:0] rf_waddr_wb_o,
output logic [31:0] rf_wdata_wb_o,
output logic rf_we_wb_o,
input logic lsu_resp_valid_i,
input logic lsu_resp_err_i,
output logic instr_done_wb_o
);
import cve2_pkg::*;
// 0 == RF write from ID
// 1 == RF write from LSU
logic [31:0] rf_wdata_wb_mux [2];
logic [1:0] rf_wdata_wb_mux_we;
if (WritebackStage) begin : g_writeback_stage
logic [31:0] rf_wdata_wb_q;
logic rf_we_wb_q;
logic [4:0] rf_waddr_wb_q;
logic wb_done;
logic wb_valid_q;
logic [31:0] wb_pc_q;
logic wb_compressed_q;
logic wb_count_q;
wb_instr_type_e wb_instr_type_q;
logic wb_valid_d;
// Stage becomes valid if an instruction enters for ID/EX and valid is cleared when instruction
// is done
assign wb_valid_d = (en_wb_i & ready_wb_o) | (wb_valid_q & ~wb_done);
// Writeback for non load/store instructions always completes in a cycle (so instantly done)
// Writeback for load/store must wait for response to be received by the LSU
// Signal only relevant if wb_valid_q set
assign wb_done = (wb_instr_type_q == WB_INSTR_OTHER) | lsu_resp_valid_i;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
wb_valid_q <= 1'b0;
end else begin
wb_valid_q <= wb_valid_d;
end
end
begin : g_wb_regs
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
rf_we_wb_q <= '0;
rf_waddr_wb_q <= '0;
rf_wdata_wb_q <= '0;
wb_instr_type_q <= wb_instr_type_e'(0);
wb_pc_q <= '0;
wb_compressed_q <= '0;
wb_count_q <= '0;
end else if (en_wb_i) begin
rf_we_wb_q <= rf_we_id_i;
rf_waddr_wb_q <= rf_waddr_id_i;
rf_wdata_wb_q <= rf_wdata_id_i;
wb_instr_type_q <= instr_type_wb_i;
wb_pc_q <= pc_id_i;
wb_compressed_q <= instr_is_compressed_id_i;
wb_count_q <= instr_perf_count_id_i;
end
end
end
assign rf_waddr_wb_o = rf_waddr_wb_q;
assign rf_wdata_wb_mux[0] = rf_wdata_wb_q;
assign rf_wdata_wb_mux_we[0] = rf_we_wb_q & wb_valid_q;
assign ready_wb_o = ~wb_valid_q | wb_done;
// Instruction in writeback will be writing to register file if either rf_we is set or writeback
// is awaiting load data. This is used for determining RF read hazards in ID/EX
assign rf_write_wb_o = wb_valid_q & (rf_we_wb_q | (wb_instr_type_q == WB_INSTR_LOAD));
assign outstanding_load_wb_o = wb_valid_q & (wb_instr_type_q == WB_INSTR_LOAD);
assign outstanding_store_wb_o = wb_valid_q & (wb_instr_type_q == WB_INSTR_STORE);
assign pc_wb_o = wb_pc_q;
assign instr_done_wb_o = wb_valid_q & wb_done;
// Increment instruction retire counters for valid instructions which are not lsu errors.
// Speculative versions of the signals do not factor in exceptions and whether the instruction
// is done yet. These are used to get correct values for instructions reading the relevant
// performance counters in the ID stage.
assign perf_instr_ret_wb_spec_o = wb_count_q;
assign perf_instr_ret_compressed_wb_spec_o = perf_instr_ret_wb_spec_o & wb_compressed_q;
assign perf_instr_ret_wb_o = instr_done_wb_o & wb_count_q &
~(lsu_resp_valid_i & lsu_resp_err_i);
assign perf_instr_ret_compressed_wb_o = perf_instr_ret_wb_o & wb_compressed_q;
// Forward data that will be written to the RF back to ID to resolve data hazards. The flopped
// rf_wdata_wb_q is used rather than rf_wdata_wb_o as the latter includes read data from memory
// that returns too late to be used on the forwarding path.
assign rf_wdata_fwd_wb_o = rf_wdata_wb_q;
end else begin : g_bypass_wb
// without writeback stage just pass through register write signals
assign rf_waddr_wb_o = rf_waddr_id_i;
assign rf_wdata_wb_mux[0] = rf_wdata_id_i;
assign rf_wdata_wb_mux_we[0] = rf_we_id_i;
// Increment instruction retire counters for valid instructions which are not lsu errors.
// The speculative signals are always 0 when no writeback stage is present as the raw counter
// values will be correct.
assign perf_instr_ret_wb_spec_o = 1'b0;
assign perf_instr_ret_compressed_wb_spec_o = 1'b0;
assign perf_instr_ret_wb_o = instr_perf_count_id_i & en_wb_i &
~(lsu_resp_valid_i & lsu_resp_err_i);
assign perf_instr_ret_compressed_wb_o = perf_instr_ret_wb_o & instr_is_compressed_id_i;
// ready needs to be constant 1 without writeback stage (otherwise ID/EX stage will stall)
assign ready_wb_o = 1'b1;
// Unused Writeback stage only IO & wiring
// Assign inputs and internal wiring to unused signals to satisfy lint checks
// Tie-off outputs to constant values
logic unused_clk;
logic unused_rst;
wb_instr_type_e unused_instr_type_wb;
logic [31:0] unused_pc_id;
assign unused_clk = clk_i;
assign unused_rst = rst_ni;
assign unused_instr_type_wb = instr_type_wb_i;
assign unused_pc_id = pc_id_i;
assign outstanding_load_wb_o = 1'b0;
assign outstanding_store_wb_o = 1'b0;
assign pc_wb_o = '0;
assign rf_write_wb_o = 1'b0;
assign rf_wdata_fwd_wb_o = 32'b0;
assign instr_done_wb_o = 1'b0;
end
assign rf_wdata_wb_mux[1] = rf_wdata_lsu_i;
assign rf_wdata_wb_mux_we[1] = rf_we_lsu_i;
// RF write data can come from ID results (all RF writes that aren't because of loads will come
// from here) or the LSU (RF writes for load data)
assign rf_wdata_wb_o = ({32{rf_wdata_wb_mux_we[0]}} & rf_wdata_wb_mux[0]) |
({32{rf_wdata_wb_mux_we[1]}} & rf_wdata_wb_mux[1]);
assign rf_we_wb_o = |rf_wdata_wb_mux_we;
`DV_FCOV_SIGNAL_GEN_IF(logic, wb_valid, g_writeback_stage.wb_valid_q, WritebackStage)
`ASSERT(RFWriteFromOneSourceOnly, $onehot0(rf_wdata_wb_mux_we))
endmodule

View file

@ -14,7 +14,7 @@ cve2:
rtl/cve2_ex_block.sv,
rtl/cve2_id_stage.sv,
rtl/cve2_if_stage.sv,
rtl/cve2_wb_stage.sv,
rtl/cve2_wb.sv,
rtl/cve2_load_store_unit.sv,
rtl/cve2_multdiv_slow.sv,
rtl/cve2_multdiv_fast.sv,