// Copyright lowRISC contributors. // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 `ifdef RISCV_FORMAL `define RVFI `endif `include "prim_assert.sv" `include "dv_fcov_macros.svh" /** * Top level module of the ibex RISC-V core */ module ibex_core import ibex_pkg::*; #( parameter bit PMPEnable = 1'b0, parameter int unsigned PMPGranularity = 0, parameter int unsigned PMPNumRegions = 4, parameter int unsigned MHPMCounterNum = 0, parameter int unsigned MHPMCounterWidth = 40, parameter bit RV32E = 1'b0, parameter rv32m_e RV32M = RV32MFast, parameter rv32b_e RV32B = RV32BNone, parameter bit BranchTargetALU = 1'b0, parameter bit WritebackStage = 1'b0, parameter bit ICache = 1'b0, parameter bit ICacheECC = 1'b0, parameter int unsigned BusSizeECC = BUS_SIZE, parameter int unsigned TagSizeECC = IC_TAG_SIZE, parameter int unsigned LineSizeECC = IC_LINE_SIZE, parameter bit BranchPredictor = 1'b0, parameter bit DbgTriggerEn = 1'b0, parameter int unsigned DbgHwBreakNum = 1, parameter bit ResetAll = 1'b0, parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, parameter bit SecureIbex = 1'b0, parameter bit DummyInstructions = 1'b0, parameter bit RegFileECC = 1'b0, parameter int unsigned RegFileDataWidth = 32, parameter bit MemECC = 1'b0, parameter int unsigned MemDataWidth = MemECC ? 32 + 7 : 32, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( // Clock and Reset input logic clk_i, // Internally generated resets in ibex_lockstep cause IMPERFECTSCH warnings. // TODO: Remove when upgrading Verilator #2134. /* verilator lint_off IMPERFECTSCH */ input logic rst_ni, /* verilator lint_on IMPERFECTSCH */ input logic [31:0] hart_id_i, input logic [31:0] boot_addr_i, // Instruction memory interface output logic instr_req_o, input logic instr_gnt_i, input logic instr_rvalid_i, output logic [31:0] instr_addr_o, input logic [MemDataWidth-1:0] instr_rdata_i, input logic instr_err_i, // Data memory interface output logic data_req_o, input logic data_gnt_i, input logic data_rvalid_i, output logic data_we_o, output logic [3:0] data_be_o, output logic [31:0] data_addr_o, output logic [MemDataWidth-1:0] data_wdata_o, input logic [MemDataWidth-1:0] data_rdata_i, input logic data_err_i, // Register file interface output logic dummy_instr_id_o, output logic dummy_instr_wb_o, output logic [4:0] rf_raddr_a_o, output logic [4:0] rf_raddr_b_o, output logic [4:0] rf_waddr_wb_o, output logic rf_we_wb_o, output logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc_o, input logic [RegFileDataWidth-1:0] rf_rdata_a_ecc_i, input logic [RegFileDataWidth-1:0] rf_rdata_b_ecc_i, // RAMs interface output logic [IC_NUM_WAYS-1:0] ic_tag_req_o, output logic ic_tag_write_o, output logic [IC_INDEX_W-1:0] ic_tag_addr_o, output logic [TagSizeECC-1:0] ic_tag_wdata_o, input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS], output logic [IC_NUM_WAYS-1:0] ic_data_req_o, output logic ic_data_write_o, output logic [IC_INDEX_W-1:0] ic_data_addr_o, output logic [LineSizeECC-1:0] ic_data_wdata_o, input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS], input logic ic_scr_key_valid_i, output logic ic_scr_key_req_o, // Interrupt inputs input logic irq_software_i, input logic irq_timer_i, input logic irq_external_i, input logic [14:0] irq_fast_i, input logic irq_nm_i, // non-maskeable interrupt output logic irq_pending_o, // Debug Interface input logic debug_req_i, output crash_dump_t crash_dump_o, // SEC_CM: EXCEPTION.CTRL_FLOW.LOCAL_ESC // SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC output logic double_fault_seen_o, // RISC-V Formal Interface // Does not comply with the coding standards of _i/_o suffixes, but follows // the convention of RISC-V Formal Interface Specification. `ifdef RVFI output logic rvfi_valid, output logic [63:0] rvfi_order, output logic [31:0] rvfi_insn, output logic rvfi_trap, output logic rvfi_halt, output logic rvfi_intr, output logic [ 1:0] rvfi_mode, output logic [ 1:0] rvfi_ixl, output logic [ 4:0] rvfi_rs1_addr, output logic [ 4:0] rvfi_rs2_addr, output logic [ 4:0] rvfi_rs3_addr, output logic [31:0] rvfi_rs1_rdata, output logic [31:0] rvfi_rs2_rdata, output logic [31:0] rvfi_rs3_rdata, output logic [ 4:0] rvfi_rd_addr, output logic [31:0] rvfi_rd_wdata, output logic [31:0] rvfi_pc_rdata, output logic [31:0] rvfi_pc_wdata, output logic [31:0] rvfi_mem_addr, output logic [ 3:0] rvfi_mem_rmask, output logic [ 3:0] rvfi_mem_wmask, output logic [31:0] rvfi_mem_rdata, output logic [31:0] rvfi_mem_wdata, output logic [31:0] rvfi_ext_mip, output logic rvfi_ext_nmi, output logic rvfi_ext_nmi_int, output logic rvfi_ext_debug_req, output logic rvfi_ext_debug_mode, output logic rvfi_ext_rf_wr_suppress, output logic [63:0] rvfi_ext_mcycle, output logic [31:0] rvfi_ext_mhpmcounters [10], output logic [31:0] rvfi_ext_mhpmcountersh [10], output logic rvfi_ext_ic_scr_key_valid, output logic rvfi_ext_irq_valid, `endif // CPU Control Signals // SEC_CM: FETCH.CTRL.LC_GATED input ibex_mubi_t fetch_enable_i, output logic alert_minor_o, output logic alert_major_internal_o, output logic alert_major_bus_o, output ibex_mubi_t core_busy_o ); localparam int unsigned PMPNumChan = 3; // SEC_CM: CORE.DATA_REG_SW.SCA localparam bit DataIndTiming = SecureIbex; localparam bit PCIncrCheck = SecureIbex; localparam bit ShadowCSR = 1'b0; // IF/ID signals logic dummy_instr_id; logic instr_valid_id; logic instr_new_id; logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage logic [31:0] instr_rdata_alu_id; // Instruction sampled inside IF stage (replicated to // ease fan-out) logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage logic instr_is_compressed_id; logic instr_perf_count_id; logic instr_bp_taken_id; logic instr_fetch_err; // Bus error on instr fetch logic instr_fetch_err_plus2; // Instruction error is misaligned 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; logic data_ind_timing; logic dummy_instr_en; logic [2:0] dummy_instr_mask; logic dummy_instr_seed_en; logic [31:0] dummy_instr_seed; logic icache_enable; logic icache_inval; logic icache_ecc_error; logic pc_mismatch_alert; logic csr_shadow_err; logic instr_first_cycle_id; logic instr_valid_clear; logic pc_set; logic nt_branch_mispredict; logic [31:0] nt_branch_addr; pc_sel_e pc_mux_id; // Mux selector for next PC exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC exc_cause_t exc_cause; // Exception cause logic instr_intg_err; logic lsu_load_err; logic lsu_store_err; logic lsu_load_resp_intg_err; logic lsu_store_resp_intg_err; // LSU signals logic lsu_addr_incr_req; logic [31:0] lsu_addr_last; // Jump and branch target and decision (EX->IF) logic [31:0] branch_target_ex; logic branch_decision; // Core busy signals logic ctrl_busy; logic if_busy; logic lsu_busy; // Register File logic [4:0] rf_raddr_a; logic [31:0] rf_rdata_a; logic [4:0] rf_raddr_b; logic [31:0] rf_rdata_b; logic rf_ren_a; logic rf_ren_b; logic [4:0] rf_waddr_wb; 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; logic rf_ecc_err_comb; logic [4:0] rf_waddr_id; logic [31:0] rf_wdata_id; logic rf_we_id; logic rf_rd_a_wb_match; logic rf_rd_b_wb_match; // ALU Control alu_op_e alu_operator_ex; logic [31:0] alu_operand_a_ex; logic [31:0] alu_operand_b_ex; logic [31:0] bt_a_operand; logic [31:0] bt_b_operand; logic [31:0] alu_adder_result_ex; // Used to forward computed address to LSU logic [31:0] result_ex; // Multiplier Control logic mult_en_ex; logic div_en_ex; logic mult_sel_ex; logic div_sel_ex; md_op_e multdiv_operator_ex; 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; csr_op_e csr_op; logic csr_op_en; csr_num_e csr_addr; logic [31:0] csr_rdata; logic [31:0] csr_wdata; logic illegal_csr_insn_id; // CSR access to non-existent register, // with wrong priviledge level, // or missing write permissions // Data Memory Control logic lsu_we; logic [1:0] lsu_type; logic lsu_sign_ext; logic lsu_req; logic [31:0] lsu_wdata; logic lsu_req_done; // stall control logic id_in_ready; logic ex_valid; logic lsu_resp_valid; logic lsu_resp_err; // Signals between instruction core interface and pipe (if and id stages) logic instr_req_int; // Id stage asserts a req to instruction core interface logic instr_req_gated; logic instr_exec; // 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; logic dummy_instr_wb; // Interrupts logic nmi_mode; irqs_t irqs; logic csr_mstatus_mie; logic [31:0] csr_mepc, csr_depc; // PMP signals logic [33:0] csr_pmp_addr [PMPNumRegions]; pmp_cfg_t csr_pmp_cfg [PMPNumRegions]; pmp_mseccfg_t csr_pmp_mseccfg; logic pmp_req_err [PMPNumChan]; logic data_req_out; 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; logic csr_mtvec_init; logic [31:0] csr_mtvec; logic [31:0] csr_mtval; logic csr_mstatus_tw; priv_lvl_e priv_mode_id; priv_lvl_e priv_mode_lsu; // debug mode and dcsr configuration logic debug_mode; logic debug_mode_entering; dbg_cause_e debug_cause; logic debug_csr_save; logic debug_single_step; logic debug_ebreakm; logic debug_ebreaku; logic trigger_match; // 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; logic perf_mul_wait; logic perf_div_wait; logic perf_jump; logic perf_branch; logic perf_tbranch; logic perf_load; logic perf_store; // for RVFI logic illegal_insn_id, unused_illegal_insn_id; // ID stage sees an illegal instruction ////////////////////// // Clock management // ////////////////////// // Before going to sleep, wait for I- and D-side // interfaces to finish ongoing operations. if (SecureIbex) begin : g_core_busy_secure // For secure Ibex, the individual bits of core_busy_o are generated from different copies of // the various busy signal. localparam int unsigned NumBusySignals = 3; localparam int unsigned NumBusyBits = $bits(ibex_mubi_t) * NumBusySignals; logic [NumBusyBits-1:0] busy_bits_buf; prim_buf #( .Width(NumBusyBits) ) u_fetch_enable_buf ( .in_i ({$bits(ibex_mubi_t){ctrl_busy, if_busy, lsu_busy}}), .out_o(busy_bits_buf) ); // Set core_busy_o to IbexMuBiOn if even a single input is high. for (genvar i = 0; i < $bits(ibex_mubi_t); i++) begin : g_core_busy_bits if (IbexMuBiOn[i] == 1'b1) begin : g_pos assign core_busy_o[i] = |busy_bits_buf[i*NumBusySignals +: NumBusySignals]; end else begin : g_neg assign core_busy_o[i] = ~|busy_bits_buf[i*NumBusySignals +: NumBusySignals]; end end end else begin : g_core_busy_non_secure // For non secure Ibex, synthesis is allowed to optimize core_busy_o. assign core_busy_o = (ctrl_busy || if_busy || lsu_busy) ? IbexMuBiOn : IbexMuBiOff; end ////////////// // IF stage // ////////////// ibex_if_stage #( .DmHaltAddr (DmHaltAddr), .DmExceptionAddr (DmExceptionAddr), .DummyInstructions(DummyInstructions), .ICache (ICache), .ICacheECC (ICacheECC), .BusSizeECC (BusSizeECC), .TagSizeECC (TagSizeECC), .LineSizeECC (LineSizeECC), .PCIncrCheck (PCIncrCheck), .ResetAll (ResetAll), .RndCnstLfsrSeed (RndCnstLfsrSeed), .RndCnstLfsrPerm (RndCnstLfsrPerm), .BranchPredictor (BranchPredictor), .MemECC (MemECC), .MemDataWidth (MemDataWidth) ) if_stage_i ( .clk_i (clk_i), .rst_ni(rst_ni), .boot_addr_i(boot_addr_i), .req_i (instr_req_gated), // instruction request control // instruction cache interface .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), .instr_bus_err_i (instr_err_i), .instr_intg_err_o (instr_intg_err), .ic_tag_req_o (ic_tag_req_o), .ic_tag_write_o (ic_tag_write_o), .ic_tag_addr_o (ic_tag_addr_o), .ic_tag_wdata_o (ic_tag_wdata_o), .ic_tag_rdata_i (ic_tag_rdata_i), .ic_data_req_o (ic_data_req_o), .ic_data_write_o (ic_data_write_o), .ic_data_addr_o (ic_data_addr_o), .ic_data_wdata_o (ic_data_wdata_o), .ic_data_rdata_i (ic_data_rdata_i), .ic_scr_key_valid_i(ic_scr_key_valid_i), .ic_scr_key_req_o (ic_scr_key_req_o), // outputs to ID stage .instr_valid_id_o (instr_valid_id), .instr_new_id_o (instr_new_id), .instr_rdata_id_o (instr_rdata_id), .instr_rdata_alu_id_o (instr_rdata_alu_id), .instr_rdata_c_id_o (instr_rdata_c_id), .instr_is_compressed_id_o(instr_is_compressed_id), .instr_bp_taken_o (instr_bp_taken_id), .instr_fetch_err_o (instr_fetch_err), .instr_fetch_err_plus2_o (instr_fetch_err_plus2), .illegal_c_insn_id_o (illegal_c_insn_id), .dummy_instr_id_o (dummy_instr_id), .pc_if_o (pc_if), .pc_id_o (pc_id), .pmp_err_if_i (pmp_req_err[PMP_I]), .pmp_err_if_plus2_i (pmp_req_err[PMP_I2]), // control signals .instr_valid_clear_i (instr_valid_clear), .pc_set_i (pc_set), .pc_mux_i (pc_mux_id), .nt_branch_mispredict_i(nt_branch_mispredict), .exc_pc_mux_i (exc_pc_mux_id), .exc_cause (exc_cause), .dummy_instr_en_i (dummy_instr_en), .dummy_instr_mask_i (dummy_instr_mask), .dummy_instr_seed_en_i (dummy_instr_seed_en), .dummy_instr_seed_i (dummy_instr_seed), .icache_enable_i (icache_enable), .icache_inval_i (icache_inval), .icache_ecc_error_o (icache_ecc_error), // branch targets .branch_target_ex_i(branch_target_ex), .nt_branch_addr_i (nt_branch_addr), // CSRs .csr_mepc_i (csr_mepc), // exception return address .csr_depc_i (csr_depc), // debug return address .csr_mtvec_i (csr_mtvec), // trap-vector base address .csr_mtvec_init_o(csr_mtvec_init), // pipeline stalls .id_in_ready_i(id_in_ready), .pc_mismatch_alert_o(pc_mismatch_alert), .if_busy_o (if_busy) ); // Core is waiting for the ISide when ID/EX stage is ready for a new instruction but none are // available assign perf_iside_wait = id_in_ready & ~instr_valid_id; // Multi-bit fetch enable used when SecureIbex == 1. When SecureIbex == 0 only use the bottom-bit // of fetch_enable_i. Ensure the multi-bit encoding has the bottom bit set for on and unset for // off so IbexMuBiOn/IbexMuBiOff can be used without needing to know the value of SecureIbex. `ASSERT_INIT(IbexMuBiSecureOnBottomBitSet, IbexMuBiOn[0] == 1'b1) `ASSERT_INIT(IbexMuBiSecureOffBottomBitClear, IbexMuBiOff[0] == 1'b0) // fetch_enable_i can be used to stop the core fetching new instructions if (SecureIbex) begin : g_instr_req_gated_secure // For secure Ibex fetch_enable_i must be a specific multi-bit pattern to enable instruction // fetch // SEC_CM: FETCH.CTRL.LC_GATED assign instr_req_gated = instr_req_int & (fetch_enable_i == IbexMuBiOn); assign instr_exec = fetch_enable_i == IbexMuBiOn; end else begin : g_instr_req_gated_non_secure // For non secure Ibex only the bottom bit of fetch enable is considered logic unused_fetch_enable; assign unused_fetch_enable = ^fetch_enable_i[$bits(ibex_mubi_t)-1:1]; assign instr_req_gated = instr_req_int & fetch_enable_i[0]; assign instr_exec = fetch_enable_i[0]; end ////////////// // ID stage // ////////////// ibex_id_stage #( .RV32E (RV32E), .RV32M (RV32M), .RV32B (RV32B), .BranchTargetALU(BranchTargetALU), .DataIndTiming (DataIndTiming), .WritebackStage (WritebackStage), .BranchPredictor(BranchPredictor), .MemECC (MemECC) ) id_stage_i ( .clk_i (clk_i), .rst_ni(rst_ni), // Processor Enable .ctrl_busy_o (ctrl_busy), .illegal_insn_o(illegal_insn_id), // from/to IF-ID pipeline register .instr_valid_i (instr_valid_id), .instr_rdata_i (instr_rdata_id), .instr_rdata_alu_i (instr_rdata_alu_id), .instr_rdata_c_i (instr_rdata_c_id), .instr_is_compressed_i(instr_is_compressed_id), .instr_bp_taken_i (instr_bp_taken_id), // Jumps and branches .branch_decision_i(branch_decision), // IF and ID control signals .instr_first_cycle_id_o(instr_first_cycle_id), .instr_valid_clear_o (instr_valid_clear), .id_in_ready_o (id_in_ready), .instr_exec_i (instr_exec), .instr_req_o (instr_req_int), .pc_set_o (pc_set), .pc_mux_o (pc_mux_id), .nt_branch_mispredict_o(nt_branch_mispredict), .nt_branch_addr_o (nt_branch_addr), .exc_pc_mux_o (exc_pc_mux_id), .exc_cause_o (exc_cause), .icache_inval_o (icache_inval), .instr_fetch_err_i (instr_fetch_err), .instr_fetch_err_plus2_i(instr_fetch_err_plus2), .illegal_c_insn_i (illegal_c_insn_id), .pc_id_i(pc_id), // Stalls .ex_valid_i (ex_valid), .lsu_resp_valid_i(lsu_resp_valid), .alu_operator_ex_o (alu_operator_ex), .alu_operand_a_ex_o(alu_operand_a_ex), .alu_operand_b_ex_o(alu_operand_b_ex), .imd_val_q_ex_o (imd_val_q_ex), .imd_val_d_ex_i (imd_val_d_ex), .imd_val_we_ex_i(imd_val_we_ex), .bt_a_operand_o(bt_a_operand), .bt_b_operand_o(bt_b_operand), .mult_en_ex_o (mult_en_ex), .div_en_ex_o (div_en_ex), .mult_sel_ex_o (mult_sel_ex), .div_sel_ex_o (div_sel_ex), .multdiv_operator_ex_o (multdiv_operator_ex), .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), .csr_op_o (csr_op), .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), .csr_mtval_o (csr_mtval), .priv_mode_i (priv_mode_id), .csr_mstatus_tw_i (csr_mstatus_tw), .illegal_csr_insn_i (illegal_csr_insn_id), .data_ind_timing_i (data_ind_timing), // LSU .lsu_req_o (lsu_req), // to load store unit .lsu_we_o (lsu_we), // to load store unit .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), .lsu_load_err_i (lsu_load_err), .lsu_load_resp_intg_err_i (lsu_load_resp_intg_err), .lsu_store_err_i (lsu_store_err), .lsu_store_resp_intg_err_i(lsu_store_resp_intg_err), // Interrupt Signals .csr_mstatus_mie_i(csr_mstatus_mie), .irq_pending_i (irq_pending_o), .irqs_i (irqs), .irq_nm_i (irq_nm_i), .nmi_mode_o (nmi_mode), // Debug Signal .debug_mode_o (debug_mode), .debug_mode_entering_o(debug_mode_entering), .debug_cause_o (debug_cause), .debug_csr_save_o (debug_csr_save), .debug_req_i (debug_req_i), .debug_single_step_i (debug_single_step), .debug_ebreakm_i (debug_ebreakm), .debug_ebreaku_i (debug_ebreaku), .trigger_match_i (trigger_match), // write data to commit in the register file .result_ex_i(result_ex), .csr_rdata_i(csr_rdata), .rf_raddr_a_o (rf_raddr_a), .rf_rdata_a_i (rf_rdata_a), .rf_raddr_b_o (rf_raddr_b), .rf_rdata_b_i (rf_rdata_b), .rf_ren_a_o (rf_ren_a), .rf_ren_b_o (rf_ren_b), .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_a_wb_match), .rf_rd_b_wb_match_o(rf_rd_b_wb_match), .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), .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), .perf_branch_o (perf_branch), .perf_tbranch_o (perf_tbranch), .perf_dside_wait_o(perf_dside_wait), .perf_mul_wait_o (perf_mul_wait), .perf_div_wait_o (perf_div_wait), .instr_id_done_o (instr_id_done) ); // for RVFI only assign unused_illegal_insn_id = illegal_insn_id; ibex_ex_block #( .RV32M (RV32M), .RV32B (RV32B), .BranchTargetALU(BranchTargetALU) ) ex_block_i ( .clk_i (clk_i), .rst_ni(rst_ni), // ALU signal from ID stage .alu_operator_i (alu_operator_ex), .alu_operand_a_i (alu_operand_a_ex), .alu_operand_b_i (alu_operand_b_ex), .alu_instr_first_cycle_i(instr_first_cycle_id), // Branch target ALU signal from ID stage .bt_a_operand_i(bt_a_operand), .bt_b_operand_i(bt_b_operand), // Multipler/Divider signal from ID stage .multdiv_operator_i (multdiv_operator_ex), .mult_en_i (mult_en_ex), .div_en_i (div_en_ex), .mult_sel_i (mult_sel_ex), .div_sel_i (div_sel_ex), .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), .data_ind_timing_i (data_ind_timing), // Intermediate value register .imd_val_we_o(imd_val_we_ex), .imd_val_d_o (imd_val_d_ex), .imd_val_q_i (imd_val_q_ex), // Outputs .alu_adder_result_ex_o(alu_adder_result_ex), // to LSU .result_ex_o (result_ex), // to ID .branch_target_o (branch_target_ex), // to IF .branch_decision_o(branch_decision), // to ID .ex_valid_o(ex_valid) ); ///////////////////// // Load/store unit // ///////////////////// assign data_req_o = data_req_out & ~pmp_req_err[PMP_D]; assign lsu_resp_err = lsu_load_err | lsu_store_err; ibex_load_store_unit #( .MemECC(MemECC), .MemDataWidth(MemDataWidth) ) load_store_unit_i ( .clk_i (clk_i), .rst_ni(rst_ni), // data interface .data_req_o (data_req_out), .data_gnt_i (data_gnt_i), .data_rvalid_i (data_rvalid_i), .data_bus_err_i(data_err_i), .data_pmp_err_i(pmp_req_err[PMP_D]), .data_addr_o (data_addr_o), .data_we_o (data_we_o), .data_be_o (data_be_o), .data_wdata_o (data_wdata_o), .data_rdata_i (data_rdata_i), // signals to/from ID/EX stage .lsu_we_i (lsu_we), .lsu_type_i (lsu_type), .lsu_wdata_i (lsu_wdata), .lsu_sign_ext_i(lsu_sign_ext), .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), .addr_incr_req_o(lsu_addr_incr_req), .addr_last_o (lsu_addr_last), .lsu_resp_valid_o(lsu_resp_valid), // exception signals .load_err_o (lsu_load_err), .load_resp_intg_err_o (lsu_load_resp_intg_err), .store_err_o (lsu_store_err), .store_resp_intg_err_o(lsu_store_resp_intg_err), .busy_o(lsu_busy), .perf_load_o (perf_load), .perf_store_o(perf_store) ); ibex_wb_stage #( .ResetAll (ResetAll), .WritebackStage (WritebackStage), .DummyInstructions(DummyInstructions) ) 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), .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), .rf_we_id_i (rf_we_id), .dummy_instr_id_i(dummy_instr_id), .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), .dummy_instr_wb_o(dummy_instr_wb), .lsu_resp_valid_i(lsu_resp_valid), .lsu_resp_err_i (lsu_resp_err), .instr_done_wb_o(instr_done_wb) ); ///////////////////////////// // Register file interface // ///////////////////////////// assign dummy_instr_id_o = dummy_instr_id; assign dummy_instr_wb_o = dummy_instr_wb; assign rf_raddr_a_o = rf_raddr_a; assign rf_waddr_wb_o = rf_waddr_wb; assign rf_we_wb_o = rf_we_wb; assign rf_raddr_b_o = rf_raddr_b; if (RegFileECC) begin : gen_regfile_ecc // SEC_CM: DATA_REG_SW.INTEGRITY logic [1:0] rf_ecc_err_a, rf_ecc_err_b; logic rf_ecc_err_a_id, rf_ecc_err_b_id; // ECC checkbit generation for regiter file wdata prim_secded_inv_39_32_enc regfile_ecc_enc ( .data_i(rf_wdata_wb), .data_o(rf_wdata_wb_ecc_o) ); // ECC checking on register file rdata prim_secded_inv_39_32_dec regfile_ecc_dec_a ( .data_i (rf_rdata_a_ecc_i), .data_o (), .syndrome_o(), .err_o (rf_ecc_err_a) ); prim_secded_inv_39_32_dec regfile_ecc_dec_b ( .data_i (rf_rdata_b_ecc_i), .data_o (), .syndrome_o(), .err_o (rf_ecc_err_b) ); // Assign read outputs - no error correction, just trigger an alert assign rf_rdata_a = rf_rdata_a_ecc_i[31:0]; assign rf_rdata_b = rf_rdata_b_ecc_i[31:0]; // Calculate errors - qualify with WB forwarding to avoid xprop into the alert signal assign rf_ecc_err_a_id = |rf_ecc_err_a & rf_ren_a & ~rf_rd_a_wb_match; assign rf_ecc_err_b_id = |rf_ecc_err_b & rf_ren_b & ~rf_rd_b_wb_match; // Combined error assign rf_ecc_err_comb = instr_valid_id & (rf_ecc_err_a_id | rf_ecc_err_b_id); end else begin : gen_no_regfile_ecc logic unused_rf_ren_a, unused_rf_ren_b; logic unused_rf_rd_a_wb_match, unused_rf_rd_b_wb_match; assign unused_rf_ren_a = rf_ren_a; assign unused_rf_ren_b = rf_ren_b; assign unused_rf_rd_a_wb_match = rf_rd_a_wb_match; assign unused_rf_rd_b_wb_match = rf_rd_b_wb_match; assign rf_wdata_wb_ecc_o = rf_wdata_wb; assign rf_rdata_a = rf_rdata_a_ecc_i; assign rf_rdata_b = rf_rdata_b_ecc_i; assign rf_ecc_err_comb = 1'b0; end /////////////////////// // Crash dump output // /////////////////////// logic [31:0] crash_dump_mtval; assign crash_dump_o.current_pc = pc_id; assign crash_dump_o.next_pc = pc_if; assign crash_dump_o.last_data_addr = lsu_addr_last; assign crash_dump_o.exception_pc = csr_mepc; assign crash_dump_o.exception_addr = crash_dump_mtval; /////////////////// // Alert outputs // /////////////////// // Minor alert - core is in a recoverable state assign alert_minor_o = icache_ecc_error; // Major internal alert - core is unrecoverable assign alert_major_internal_o = rf_ecc_err_comb | pc_mismatch_alert | csr_shadow_err; // Major bus alert assign alert_major_bus_o = lsu_load_resp_intg_err | lsu_store_resp_intg_err | instr_intg_err; // Explict INC_ASSERT block to avoid unused signal lint warnings were asserts are not included `ifdef INC_ASSERT // Signals used for assertions only logic outstanding_load_resp; logic outstanding_store_resp; logic outstanding_load_id; logic outstanding_store_id; assign outstanding_load_id = id_stage_i.instr_executing & id_stage_i.lsu_req_dec & ~id_stage_i.lsu_we; 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 // 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; assign outstanding_store_resp = outstanding_store_id; `ASSERT(NoMemRFWriteWithoutPendingLoad, rf_we_lsu |-> outstanding_load_id, clk_i, !rst_ni) end `ASSERT(NoMemResponseWithoutPendingAccess, data_rvalid_i |-> outstanding_load_resp | outstanding_store_resp, clk_i, !rst_ni) // Keep track of the PC last seen in the ID stage when fetch is disabled logic [31:0] pc_at_fetch_disable; ibex_mubi_t last_fetch_enable; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin pc_at_fetch_disable <= '0; last_fetch_enable <= '0; end else begin last_fetch_enable <= fetch_enable_i; if ((fetch_enable_i != IbexMuBiOn) && (last_fetch_enable == IbexMuBiOn)) begin pc_at_fetch_disable <= pc_id; end end end // When fetch is disabled no instructions should be executed. Once fetch is disabled either the // ID/EX stage is not valid or the PC of the ID/EX stage must remain as it was at disable. The // ID/EX valid should not ressert once it has been cleared. `ASSERT(NoExecWhenFetchEnableNotOn, fetch_enable_i != IbexMuBiOn |=> (~instr_valid_id || (pc_id == pc_at_fetch_disable)) && ~$rose(instr_valid_id)) `endif //////////////////////// // RF (Register File) // //////////////////////// `ifdef RVFI `endif ///////////////////////////////////////// // CSRs (Control and Status Registers) // ///////////////////////////////////////// assign csr_wdata = alu_operand_a_ex; assign csr_addr = csr_num_e'(csr_access ? alu_operand_b_ex[11:0] : 12'b0); ibex_cs_registers #( .DbgTriggerEn (DbgTriggerEn), .DbgHwBreakNum (DbgHwBreakNum), .DataIndTiming (DataIndTiming), .DummyInstructions(DummyInstructions), .ShadowCSR (ShadowCSR), .ICache (ICache), .MHPMCounterNum (MHPMCounterNum), .MHPMCounterWidth (MHPMCounterWidth), .PMPEnable (PMPEnable), .PMPGranularity (PMPGranularity), .PMPNumRegions (PMPNumRegions), .RV32E (RV32E), .RV32M (RV32M), .RV32B (RV32B) ) cs_registers_i ( .clk_i (clk_i), .rst_ni(rst_ni), // Hart ID from outside .hart_id_i (hart_id_i), .priv_mode_id_o (priv_mode_id), .priv_mode_lsu_o(priv_mode_lsu), // mtvec .csr_mtvec_o (csr_mtvec), .csr_mtvec_init_i(csr_mtvec_init), .boot_addr_i (boot_addr_i), // Interface to CSRs ( SRAM like ) .csr_access_i(csr_access), .csr_addr_i (csr_addr), .csr_wdata_i (csr_wdata), .csr_op_i (csr_op), .csr_op_en_i (csr_op_en), .csr_rdata_o (csr_rdata), // Interrupt related control signals .irq_software_i (irq_software_i), .irq_timer_i (irq_timer_i), .irq_external_i (irq_external_i), .irq_fast_i (irq_fast_i), .nmi_mode_i (nmi_mode), .irq_pending_o (irq_pending_o), .irqs_o (irqs), .csr_mstatus_mie_o(csr_mstatus_mie), .csr_mstatus_tw_o (csr_mstatus_tw), .csr_mepc_o (csr_mepc), .csr_mtval_o (crash_dump_mtval), // PMP .csr_pmp_cfg_o (csr_pmp_cfg), .csr_pmp_addr_o (csr_pmp_addr), .csr_pmp_mseccfg_o(csr_pmp_mseccfg), // debug .csr_depc_o (csr_depc), .debug_mode_i (debug_mode), .debug_mode_entering_i(debug_mode_entering), .debug_cause_i (debug_cause), .debug_csr_save_i (debug_csr_save), .debug_single_step_o (debug_single_step), .debug_ebreakm_o (debug_ebreakm), .debug_ebreaku_o (debug_ebreaku), .trigger_match_o (trigger_match), .pc_if_i(pc_if), .pc_id_i(pc_id), .pc_wb_i(pc_wb), .data_ind_timing_o (data_ind_timing), .dummy_instr_en_o (dummy_instr_en), .dummy_instr_mask_o (dummy_instr_mask), .dummy_instr_seed_en_o(dummy_instr_seed_en), .dummy_instr_seed_o (dummy_instr_seed), .icache_enable_o (icache_enable), .csr_shadow_err_o (csr_shadow_err), .ic_scr_key_valid_i (ic_scr_key_valid_i), .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), .csr_mcause_i (exc_cause), .csr_mtval_i (csr_mtval), .illegal_csr_insn_o(illegal_csr_insn_id), .double_fault_seen_o, // 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), .branch_taken_i (perf_tbranch), .mem_load_i (perf_load), .mem_store_i (perf_store), .dside_wait_i (perf_dside_wait), .mul_wait_i (perf_mul_wait), .div_wait_i (perf_div_wait) ); // These assertions are in top-level as instr_valid_id required as the enable term `ASSERT(IbexCsrOpValid, instr_valid_id |-> csr_op inside { CSR_OP_READ, CSR_OP_WRITE, CSR_OP_SET, CSR_OP_CLEAR }) `ASSERT_KNOWN_IF(IbexCsrWdataIntKnown, cs_registers_i.csr_wdata_int, csr_op_en) if (PMPEnable) begin : g_pmp logic [31:0] pc_if_inc; logic [33:0] pmp_req_addr [PMPNumChan]; pmp_req_e pmp_req_type [PMPNumChan]; priv_lvl_e pmp_priv_lvl [PMPNumChan]; assign pc_if_inc = pc_if + 32'd2; assign pmp_req_addr[PMP_I] = {2'b00, pc_if}; assign pmp_req_type[PMP_I] = PMP_ACC_EXEC; assign pmp_priv_lvl[PMP_I] = priv_mode_id; assign pmp_req_addr[PMP_I2] = {2'b00, pc_if_inc}; assign pmp_req_type[PMP_I2] = PMP_ACC_EXEC; assign pmp_priv_lvl[PMP_I2] = priv_mode_id; assign pmp_req_addr[PMP_D] = {2'b00, data_addr_o[31:0]}; assign pmp_req_type[PMP_D] = data_we_o ? PMP_ACC_WRITE : PMP_ACC_READ; assign pmp_priv_lvl[PMP_D] = priv_mode_lsu; ibex_pmp #( .PMPGranularity(PMPGranularity), .PMPNumChan (PMPNumChan), .PMPNumRegions (PMPNumRegions) ) pmp_i ( // Interface to CSRs .csr_pmp_cfg_i (csr_pmp_cfg), .csr_pmp_addr_i (csr_pmp_addr), .csr_pmp_mseccfg_i(csr_pmp_mseccfg), .priv_mode_i (pmp_priv_lvl), // Access checking channels .pmp_req_addr_i (pmp_req_addr), .pmp_req_type_i (pmp_req_type), .pmp_req_err_o (pmp_req_err) ); end else begin : g_no_pmp // Unused signal tieoff priv_lvl_e unused_priv_lvl_ls; logic [33:0] unused_csr_pmp_addr [PMPNumRegions]; pmp_cfg_t unused_csr_pmp_cfg [PMPNumRegions]; pmp_mseccfg_t unused_csr_pmp_mseccfg; assign unused_priv_lvl_ls = priv_mode_lsu; assign unused_csr_pmp_addr = csr_pmp_addr; assign unused_csr_pmp_cfg = csr_pmp_cfg; assign unused_csr_pmp_mseccfg = csr_pmp_mseccfg; // Output tieoff assign pmp_req_err[PMP_I] = 1'b0; assign pmp_req_err[PMP_I2] = 1'b0; assign pmp_req_err[PMP_D] = 1'b0; end `ifdef RVFI // When writeback stage is present RVFI information is emitted when instruction is finished in // third stage but some information must be captured whilst the instruction is in the second // stage. Without writeback stage RVFI information is all emitted when instruction retires in // 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; logic rvfi_stage_valid [RVFI_STAGES]; logic [63:0] rvfi_stage_order [RVFI_STAGES]; logic [31:0] rvfi_stage_insn [RVFI_STAGES]; logic rvfi_stage_trap [RVFI_STAGES]; logic rvfi_stage_halt [RVFI_STAGES]; logic rvfi_stage_intr [RVFI_STAGES]; logic [ 1:0] rvfi_stage_mode [RVFI_STAGES]; logic [ 1:0] rvfi_stage_ixl [RVFI_STAGES]; logic [ 4:0] rvfi_stage_rs1_addr [RVFI_STAGES]; logic [ 4:0] rvfi_stage_rs2_addr [RVFI_STAGES]; logic [ 4:0] rvfi_stage_rs3_addr [RVFI_STAGES]; logic [31:0] rvfi_stage_rs1_rdata [RVFI_STAGES]; logic [31:0] rvfi_stage_rs2_rdata [RVFI_STAGES]; logic [31:0] rvfi_stage_rs3_rdata [RVFI_STAGES]; logic [ 4:0] rvfi_stage_rd_addr [RVFI_STAGES]; logic [31:0] rvfi_stage_rd_wdata [RVFI_STAGES]; logic [31:0] rvfi_stage_pc_rdata [RVFI_STAGES]; logic [31:0] rvfi_stage_pc_wdata [RVFI_STAGES]; logic [31:0] rvfi_stage_mem_addr [RVFI_STAGES]; logic [ 3:0] rvfi_stage_mem_rmask [RVFI_STAGES]; logic [ 3:0] rvfi_stage_mem_wmask [RVFI_STAGES]; logic [31:0] rvfi_stage_mem_rdata [RVFI_STAGES]; logic [31:0] rvfi_stage_mem_wdata [RVFI_STAGES]; logic rvfi_instr_new_wb; logic rvfi_intr_d; logic rvfi_intr_q; logic rvfi_set_trap_pc_d; logic rvfi_set_trap_pc_q; logic [31:0] rvfi_insn_id; logic [4:0] rvfi_rs1_addr_d; logic [4:0] rvfi_rs1_addr_q; logic [4:0] rvfi_rs2_addr_d; logic [4:0] rvfi_rs2_addr_q; logic [4:0] rvfi_rs3_addr_d; logic [31:0] rvfi_rs1_data_d; logic [31:0] rvfi_rs1_data_q; logic [31:0] rvfi_rs2_data_d; logic [31:0] rvfi_rs2_data_q; logic [31:0] rvfi_rs3_data_d; logic [4:0] rvfi_rd_addr_wb; logic [4:0] rvfi_rd_addr_q; logic [4:0] rvfi_rd_addr_d; logic [31:0] rvfi_rd_wdata_wb; logic [31:0] rvfi_rd_wdata_d; logic [31:0] rvfi_rd_wdata_q; logic rvfi_rd_we_wb; logic [3:0] rvfi_mem_mask_int; logic [31:0] rvfi_mem_rdata_d; logic [31:0] rvfi_mem_rdata_q; logic [31:0] rvfi_mem_wdata_d; logic [31:0] rvfi_mem_wdata_q; logic [31:0] rvfi_mem_addr_d; logic [31:0] rvfi_mem_addr_q; logic rvfi_trap_id; logic rvfi_trap_wb; logic rvfi_irq_valid; logic [63:0] rvfi_stage_order_d; logic rvfi_id_done; logic rvfi_wb_done; logic new_debug_req; logic new_nmi; logic new_nmi_int; logic new_irq; ibex_pkg::irqs_t captured_mip; logic captured_nmi; logic captured_nmi_int; logic captured_debug_req; logic captured_valid; // RVFI extension for co-simulation support // debug_req and MIP captured at IF -> ID transition so one extra stage ibex_pkg::irqs_t rvfi_ext_stage_mip [RVFI_STAGES+1]; logic rvfi_ext_stage_nmi [RVFI_STAGES+1]; logic rvfi_ext_stage_nmi_int [RVFI_STAGES+1]; logic rvfi_ext_stage_debug_req [RVFI_STAGES+1]; logic rvfi_ext_stage_debug_mode [RVFI_STAGES]; logic [63:0] rvfi_ext_stage_mcycle [RVFI_STAGES]; logic [31:0] rvfi_ext_stage_mhpmcounters [RVFI_STAGES][10]; logic [31:0] rvfi_ext_stage_mhpmcountersh [RVFI_STAGES][10]; logic rvfi_ext_stage_ic_scr_key_valid [RVFI_STAGES]; logic rvfi_ext_stage_irq_valid [RVFI_STAGES+1]; logic rvfi_stage_valid_d [RVFI_STAGES]; assign rvfi_valid = rvfi_stage_valid [RVFI_STAGES-1]; assign rvfi_order = rvfi_stage_order [RVFI_STAGES-1]; assign rvfi_insn = rvfi_stage_insn [RVFI_STAGES-1]; assign rvfi_trap = rvfi_stage_trap [RVFI_STAGES-1]; assign rvfi_halt = rvfi_stage_halt [RVFI_STAGES-1]; assign rvfi_intr = rvfi_stage_intr [RVFI_STAGES-1]; assign rvfi_mode = rvfi_stage_mode [RVFI_STAGES-1]; assign rvfi_ixl = rvfi_stage_ixl [RVFI_STAGES-1]; assign rvfi_rs1_addr = rvfi_stage_rs1_addr [RVFI_STAGES-1]; assign rvfi_rs2_addr = rvfi_stage_rs2_addr [RVFI_STAGES-1]; assign rvfi_rs3_addr = rvfi_stage_rs3_addr [RVFI_STAGES-1]; assign rvfi_rs1_rdata = rvfi_stage_rs1_rdata[RVFI_STAGES-1]; assign rvfi_rs2_rdata = rvfi_stage_rs2_rdata[RVFI_STAGES-1]; assign rvfi_rs3_rdata = rvfi_stage_rs3_rdata[RVFI_STAGES-1]; assign rvfi_rd_addr = rvfi_stage_rd_addr [RVFI_STAGES-1]; assign rvfi_rd_wdata = rvfi_stage_rd_wdata [RVFI_STAGES-1]; assign rvfi_pc_rdata = rvfi_stage_pc_rdata [RVFI_STAGES-1]; assign rvfi_pc_wdata = rvfi_stage_pc_wdata [RVFI_STAGES-1]; assign rvfi_mem_addr = rvfi_stage_mem_addr [RVFI_STAGES-1]; assign rvfi_mem_rmask = rvfi_stage_mem_rmask[RVFI_STAGES-1]; assign rvfi_mem_wmask = rvfi_stage_mem_wmask[RVFI_STAGES-1]; assign rvfi_mem_rdata = rvfi_stage_mem_rdata[RVFI_STAGES-1]; assign rvfi_mem_wdata = rvfi_stage_mem_wdata[RVFI_STAGES-1]; assign rvfi_rd_addr_wb = rf_waddr_wb; assign rvfi_rd_wdata_wb = rf_we_wb ? rf_wdata_wb : rf_wdata_lsu; assign rvfi_rd_we_wb = rf_we_wb | rf_we_lsu; always_comb begin // Use always_comb instead of continuous assign so first assign can set 0 as default everywhere // that is overridden by more specific settings. rvfi_ext_mip = '0; rvfi_ext_mip[CSR_MSIX_BIT] = rvfi_ext_stage_mip[RVFI_STAGES].irq_software; rvfi_ext_mip[CSR_MTIX_BIT] = rvfi_ext_stage_mip[RVFI_STAGES].irq_timer; rvfi_ext_mip[CSR_MEIX_BIT] = rvfi_ext_stage_mip[RVFI_STAGES].irq_external; rvfi_ext_mip[CSR_MFIX_BIT_HIGH:CSR_MFIX_BIT_LOW] = rvfi_ext_stage_mip[RVFI_STAGES].irq_fast; end assign rvfi_ext_nmi = rvfi_ext_stage_nmi [RVFI_STAGES]; assign rvfi_ext_nmi_int = rvfi_ext_stage_nmi_int [RVFI_STAGES]; assign rvfi_ext_debug_req = rvfi_ext_stage_debug_req [RVFI_STAGES]; assign rvfi_ext_debug_mode = rvfi_ext_stage_debug_mode [RVFI_STAGES-1]; assign rvfi_ext_mcycle = rvfi_ext_stage_mcycle [RVFI_STAGES-1]; assign rvfi_ext_mhpmcounters = rvfi_ext_stage_mhpmcounters [RVFI_STAGES-1]; assign rvfi_ext_mhpmcountersh = rvfi_ext_stage_mhpmcountersh [RVFI_STAGES-1]; assign rvfi_ext_ic_scr_key_valid = rvfi_ext_stage_ic_scr_key_valid [RVFI_STAGES-1]; assign rvfi_ext_irq_valid = rvfi_ext_stage_irq_valid [RVFI_STAGES]; // When an instruction takes a trap the `rvfi_trap` signal will be set. Instructions that take // traps flush the pipeline so ordinarily wouldn't be seen to be retire. The RVFI tracking // pipeline is kept going for flushed instructions that trapped so they are still visible on the // RVFI interface. // Factor in exceptions taken in ID so RVFI tracking picks up flushed instructions that took // a trap 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 & ~dummy_instr_id) | (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 & ~(id_stage_i.ebrk_insn & id_stage_i.controller_i.ebreak_into_debug); 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 = rvfi_stage_valid[0] & (instr_done_wb | rvfi_stage_trap[0]); end else 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 & ~dummy_instr_id; // Without writeback stage signal new instr_new_wb when instruction enters ID/EX to correctly // 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) & ~(id_stage_i.ebrk_insn & id_stage_i.controller_i.ebreak_into_debug); assign rvfi_trap_wb = 1'b0; assign rvfi_wb_done = instr_done_wb; end assign rvfi_stage_order_d = dummy_instr_id ? rvfi_stage_order[0] : rvfi_stage_order[0] + 64'd1; // For interrupts and debug Ibex will take the relevant trap as soon as whatever instruction in ID // finishes or immediately if the ID stage is empty. The rvfi_ext interface provides the DV // environment with information about the irq/debug_req/nmi state that applies to a particular // instruction. // // When a irq/debug_req/nmi appears the ID stage will finish whatever instruction it is currently // executing (if any) then take the trap the cycle after that instruction leaves the ID stage. The // trap taken depends upon the state of irq/debug_req/nmi on that cycle. In the cycles following // that before the first instruction of the trap handler enters the ID stage the state of // irq/debug_req/nmi could change but this has no effect on the trap handler (e.g. a higher // priority interrupt might appear but this wouldn't stop the lower priority interrupt trap // handler executing first as it's already being fetched). To provide the DV environment with the // correct information for it to verify execution we need to capture the irq/debug_req/nmi state // the cycle the trap decision is made. Which the captured_X signals below do. // // The new_X signals take the raw irq/debug_req/nmi inputs and factor in the enable terms required // to determine if a trap will actually happen. // // These signals and the comment above are referred to in the documentation (cosim.rst). If // altering the names or meanings of these signals or this comment please adjust the documentation // appropriately. assign new_debug_req = (debug_req_i & ~debug_mode); assign new_nmi = irq_nm_i & ~nmi_mode & ~debug_mode; assign new_nmi_int = id_stage_i.controller_i.irq_nm_int & ~nmi_mode & ~debug_mode; assign new_irq = irq_pending_o & (csr_mstatus_mie || (priv_mode_id == PRIV_LVL_U)) & ~nmi_mode & ~debug_mode; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin captured_valid <= 1'b0; captured_mip <= '0; captured_nmi <= 1'b0; captured_nmi_int <= 1'b0; captured_debug_req <= 1'b0; rvfi_irq_valid <= 1'b0; end else begin // Capture when ID stage has emptied out and something occurs that will cause a trap and we // haven't yet captured // // When we already captured a trap, and there is upcoming nmi interrupt or // a debug request then recapture as nmi or debug request are supposed to // be serviced. if (~instr_valid_id & (new_debug_req | new_irq | new_nmi | new_nmi_int) & ((~captured_valid) | (new_debug_req & ~captured_debug_req) | (new_nmi & ~captured_nmi & ~captured_debug_req))) begin captured_valid <= 1'b1; captured_nmi <= irq_nm_i; captured_nmi_int <= id_stage_i.controller_i.irq_nm_int; captured_mip <= cs_registers_i.mip; captured_debug_req <= debug_req_i; end // When the pipeline has emptied in preparation for handling a new interrupt send // a notification up the RVFI pipeline. This is used by the cosim to deal with cases where an // interrupt occurs before another interrupt or debug request but both occur before the first // instruction of the handler is executed and retired (where the cosim will see all the // interrupts and debug requests at once with no way to determine which occurred first). if (~instr_valid_id & ~new_debug_req & (new_irq | new_nmi | new_nmi_int) & ready_wb & ~captured_valid) begin rvfi_irq_valid <= 1'b1; end else begin rvfi_irq_valid <= 1'b0; end // Capture cleared out as soon as a new instruction appears in ID if (if_stage_i.instr_valid_id_d) begin captured_valid <= 1'b0; end end end // Pass the captured irq/debug_req/nmi state to the rvfi_ext interface tracking pipeline. // // To correctly capture we need to factor in various enable terms, should there be a fault in this // logic we won't tell the DV environment about a trap that should have been taken. So if there's // no valid capture we grab the raw values of the irq/debug_req/nmi inputs whatever they are and // the DV environment will see if a trap should have been taken but wasn't. always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_ext_stage_mip[0] <= '0; rvfi_ext_stage_nmi[0] <= '0; rvfi_ext_stage_nmi_int[0] <= '0; rvfi_ext_stage_debug_req[0] <= '0; end else if ((if_stage_i.instr_valid_id_d & if_stage_i.instr_new_id_d) | rvfi_irq_valid) begin rvfi_ext_stage_mip[0] <= instr_valid_id | ~captured_valid ? cs_registers_i.mip : captured_mip; rvfi_ext_stage_nmi[0] <= instr_valid_id | ~captured_valid ? irq_nm_i : captured_nmi; rvfi_ext_stage_nmi_int[0] <= instr_valid_id | ~captured_valid ? id_stage_i.controller_i.irq_nm_int : captured_nmi_int; rvfi_ext_stage_debug_req[0] <= instr_valid_id | ~captured_valid ? debug_req_i : captured_debug_req; end end // rvfi_irq_valid signals an interrupt event to the cosim. These should only occur when the RVFI // pipe is empty so just send it straigh through. for (genvar i = 0; i < RVFI_STAGES + 1; i = i + 1) begin : g_rvfi_irq_valid if (i == 0) begin : g_rvfi_irq_valid_first_stage always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_ext_stage_irq_valid[i] <= 1'b0; end else begin rvfi_ext_stage_irq_valid[i] <= rvfi_irq_valid; end end end else begin : g_rvfi_irq_valid_other_stages always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_ext_stage_irq_valid[i] <= 1'b0; end else begin rvfi_ext_stage_irq_valid[i] <= rvfi_ext_stage_irq_valid[i-1]; end end end end for (genvar i = 0; i < RVFI_STAGES; i = i + 1) begin : g_rvfi_stages always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_stage_halt[i] <= '0; rvfi_stage_trap[i] <= '0; rvfi_stage_intr[i] <= '0; rvfi_stage_order[i] <= '0; rvfi_stage_insn[i] <= '0; rvfi_stage_mode[i] <= {PRIV_LVL_M}; rvfi_stage_ixl[i] <= CSR_MISA_MXL; rvfi_stage_rs1_addr[i] <= '0; rvfi_stage_rs2_addr[i] <= '0; rvfi_stage_rs3_addr[i] <= '0; rvfi_stage_pc_rdata[i] <= '0; rvfi_stage_pc_wdata[i] <= '0; rvfi_stage_mem_rmask[i] <= '0; rvfi_stage_mem_wmask[i] <= '0; rvfi_stage_valid[i] <= '0; rvfi_stage_rs1_rdata[i] <= '0; rvfi_stage_rs2_rdata[i] <= '0; rvfi_stage_rs3_rdata[i] <= '0; rvfi_stage_rd_wdata[i] <= '0; rvfi_stage_rd_addr[i] <= '0; rvfi_stage_mem_rdata[i] <= '0; rvfi_stage_mem_wdata[i] <= '0; rvfi_stage_mem_addr[i] <= '0; rvfi_ext_stage_mip[i+1] <= '0; rvfi_ext_stage_nmi[i+1] <= '0; rvfi_ext_stage_nmi_int[i+1] <= '0; rvfi_ext_stage_debug_req[i+1] <= '0; rvfi_ext_stage_debug_mode[i] <= '0; rvfi_ext_stage_mcycle[i] <= '0; rvfi_ext_stage_mhpmcounters[i] <= '{10{'0}}; rvfi_ext_stage_mhpmcountersh[i] <= '{10{'0}}; rvfi_ext_stage_ic_scr_key_valid[i] <= '0; end else begin rvfi_stage_valid[i] <= rvfi_stage_valid_d[i]; if (i == 0) begin if (rvfi_id_done) begin rvfi_stage_halt[i] <= '0; rvfi_stage_trap[i] <= rvfi_trap_id; rvfi_stage_intr[i] <= rvfi_intr_d; rvfi_stage_order[i] <= rvfi_stage_order_d; rvfi_stage_insn[i] <= rvfi_insn_id; rvfi_stage_mode[i] <= {priv_mode_id}; rvfi_stage_ixl[i] <= CSR_MISA_MXL; rvfi_stage_rs1_addr[i] <= rvfi_rs1_addr_d; rvfi_stage_rs2_addr[i] <= rvfi_rs2_addr_d; rvfi_stage_rs3_addr[i] <= rvfi_rs3_addr_d; rvfi_stage_pc_rdata[i] <= pc_id; rvfi_stage_pc_wdata[i] <= pc_set ? branch_target_ex : pc_if; rvfi_stage_mem_rmask[i] <= rvfi_mem_mask_int; rvfi_stage_mem_wmask[i] <= data_we_o ? rvfi_mem_mask_int : 4'b0000; rvfi_stage_rs1_rdata[i] <= rvfi_rs1_data_d; rvfi_stage_rs2_rdata[i] <= rvfi_rs2_data_d; rvfi_stage_rs3_rdata[i] <= rvfi_rs3_data_d; rvfi_stage_rd_addr[i] <= rvfi_rd_addr_d; rvfi_stage_rd_wdata[i] <= rvfi_rd_wdata_d; rvfi_stage_mem_rdata[i] <= rvfi_mem_rdata_d; rvfi_stage_mem_wdata[i] <= rvfi_mem_wdata_d; rvfi_stage_mem_addr[i] <= rvfi_mem_addr_d; rvfi_ext_stage_debug_mode[i] <= debug_mode; rvfi_ext_stage_mcycle[i] <= cs_registers_i.mcycle_counter_i.counter_val_o; rvfi_ext_stage_ic_scr_key_valid[i] <= cs_registers_i.cpuctrlsts_ic_scr_key_valid_q; // This is done this way because SystemVerilog does not support looping through // gen_cntrs[k] within a for loop. for (int k=0; k < 10; k++) begin rvfi_ext_stage_mhpmcounters[i][k] <= cs_registers_i.mhpmcounter[k+3][31:0]; rvfi_ext_stage_mhpmcountersh[i][k] <= cs_registers_i.mhpmcounter[k+3][63:32]; end end // Some of the rvfi_ext_* signals are used to provide an interrupt notification (signalled // via rvfi_ext_irq_valid) when there isn't a valid retired instruction as well as // providing information along with a retired instruction. Move these up the rvfi pipeline // for both cases. if (rvfi_id_done | rvfi_ext_stage_irq_valid[i]) begin rvfi_ext_stage_mip[i+1] <= rvfi_ext_stage_mip[i]; rvfi_ext_stage_nmi[i+1] <= rvfi_ext_stage_nmi[i]; rvfi_ext_stage_nmi_int[i+1] <= rvfi_ext_stage_nmi_int[i]; rvfi_ext_stage_debug_req[i+1] <= rvfi_ext_stage_debug_req[i]; 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_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]; rvfi_stage_mode[i] <= rvfi_stage_mode[i-1]; rvfi_stage_ixl[i] <= rvfi_stage_ixl[i-1]; rvfi_stage_rs1_addr[i] <= rvfi_stage_rs1_addr[i-1]; rvfi_stage_rs2_addr[i] <= rvfi_stage_rs2_addr[i-1]; rvfi_stage_rs3_addr[i] <= rvfi_stage_rs3_addr[i-1]; rvfi_stage_pc_rdata[i] <= rvfi_stage_pc_rdata[i-1]; rvfi_stage_pc_wdata[i] <= rvfi_stage_pc_wdata[i-1]; rvfi_stage_mem_rmask[i] <= rvfi_stage_mem_rmask[i-1]; rvfi_stage_mem_wmask[i] <= rvfi_stage_mem_wmask[i-1]; rvfi_stage_rs1_rdata[i] <= rvfi_stage_rs1_rdata[i-1]; rvfi_stage_rs2_rdata[i] <= rvfi_stage_rs2_rdata[i-1]; rvfi_stage_rs3_rdata[i] <= rvfi_stage_rs3_rdata[i-1]; rvfi_stage_mem_wdata[i] <= rvfi_stage_mem_wdata[i-1]; rvfi_stage_mem_addr[i] <= rvfi_stage_mem_addr[i-1]; // For 2 RVFI_STAGES/Writeback Stage ignore first stage flops for rd_addr, rd_wdata and // mem_rdata. For RF write addr/data actual write happens in writeback so capture // address/data there. For mem_rdata that is only available from the writeback stage. // Previous stage flops still exist in RTL as they are used by the non writeback config rvfi_stage_rd_addr[i] <= rvfi_rd_addr_d; rvfi_stage_rd_wdata[i] <= rvfi_rd_wdata_d; rvfi_stage_mem_rdata[i] <= rvfi_mem_rdata_d; rvfi_ext_stage_debug_mode[i] <= rvfi_ext_stage_debug_mode[i-1]; rvfi_ext_stage_mcycle[i] <= rvfi_ext_stage_mcycle[i-1]; rvfi_ext_stage_ic_scr_key_valid[i] <= rvfi_ext_stage_ic_scr_key_valid[i-1]; rvfi_ext_stage_mhpmcounters[i] <= rvfi_ext_stage_mhpmcounters[i-1]; rvfi_ext_stage_mhpmcountersh[i] <= rvfi_ext_stage_mhpmcountersh[i-1]; end // Some of the rvfi_ext_* signals are used to provide an interrupt notification (signalled // via rvfi_ext_irq_valid) when there isn't a valid retired instruction as well as // providing information along with a retired instruction. Move these up the rvfi pipeline // for both cases. if (rvfi_wb_done | rvfi_ext_stage_irq_valid[i]) begin rvfi_ext_stage_mip[i+1] <= rvfi_ext_stage_mip[i]; rvfi_ext_stage_nmi[i+1] <= rvfi_ext_stage_nmi[i]; rvfi_ext_stage_nmi_int[i+1] <= rvfi_ext_stage_nmi_int[i]; rvfi_ext_stage_debug_req[i+1] <= rvfi_ext_stage_debug_req[i]; end end end end end // Memory adddress/write data available first cycle of ld/st instruction from register read always_comb begin if (instr_first_cycle_id) begin rvfi_mem_addr_d = alu_adder_result_ex; rvfi_mem_wdata_d = lsu_wdata; end else begin rvfi_mem_addr_d = rvfi_mem_addr_q; rvfi_mem_wdata_d = rvfi_mem_wdata_q; end end // Capture read data from LSU when it becomes valid always_comb begin if (lsu_resp_valid) begin rvfi_mem_rdata_d = rf_wdata_lsu; end else begin rvfi_mem_rdata_d = rvfi_mem_rdata_q; end end always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_mem_addr_q <= '0; rvfi_mem_rdata_q <= '0; rvfi_mem_wdata_q <= '0; end else begin rvfi_mem_addr_q <= rvfi_mem_addr_d; rvfi_mem_rdata_q <= rvfi_mem_rdata_d; rvfi_mem_wdata_q <= rvfi_mem_wdata_d; end end // Byte enable based on data type always_comb begin unique case (lsu_type) 2'b00: rvfi_mem_mask_int = 4'b1111; 2'b01: rvfi_mem_mask_int = 4'b0011; 2'b10: rvfi_mem_mask_int = 4'b0001; default: rvfi_mem_mask_int = 4'b0000; endcase end always_comb begin if (instr_is_compressed_id) begin rvfi_insn_id = {16'b0, instr_rdata_c_id}; end else begin rvfi_insn_id = instr_rdata_id; end end // Source registers 1 and 2 are read in the first instruction cycle // Source register 3 is read in the second instruction cycle. always_comb begin if (instr_first_cycle_id) begin rvfi_rs1_data_d = rf_ren_a ? multdiv_operand_a_ex : '0; rvfi_rs1_addr_d = rf_ren_a ? rf_raddr_a : '0; rvfi_rs2_data_d = rf_ren_b ? multdiv_operand_b_ex : '0; rvfi_rs2_addr_d = rf_ren_b ? rf_raddr_b : '0; rvfi_rs3_data_d = '0; rvfi_rs3_addr_d = '0; end else begin rvfi_rs1_data_d = rvfi_rs1_data_q; rvfi_rs1_addr_d = rvfi_rs1_addr_q; rvfi_rs2_data_d = rvfi_rs2_data_q; rvfi_rs2_addr_d = rvfi_rs2_addr_q; rvfi_rs3_data_d = multdiv_operand_a_ex; rvfi_rs3_addr_d = rf_raddr_a; end end always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_rs1_data_q <= '0; rvfi_rs1_addr_q <= '0; rvfi_rs2_data_q <= '0; rvfi_rs2_addr_q <= '0; end else begin rvfi_rs1_data_q <= rvfi_rs1_data_d; rvfi_rs1_addr_q <= rvfi_rs1_addr_d; rvfi_rs2_data_q <= rvfi_rs2_data_d; rvfi_rs2_addr_q <= rvfi_rs2_addr_d; end end always_comb begin if (rvfi_rd_we_wb) begin // Capture address/data of write to register file rvfi_rd_addr_d = rvfi_rd_addr_wb; // If writing to x0 zero write data as required by RVFI specification if (rvfi_rd_addr_wb == 5'b0) begin rvfi_rd_wdata_d = '0; end else begin rvfi_rd_wdata_d = rvfi_rd_wdata_wb; end end else if (rvfi_instr_new_wb) begin // If no RF write but new instruction in Writeback (when present) or ID/EX (when no writeback // stage present) then zero RF write address/data as required by RVFI specification rvfi_rd_addr_d = '0; rvfi_rd_wdata_d = '0; end else begin // Otherwise maintain previous value rvfi_rd_addr_d = rvfi_rd_addr_q; rvfi_rd_wdata_d = rvfi_rd_wdata_q; end end // RD write register is refreshed only once per cycle and // then it is kept stable for the cycle. always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_rd_addr_q <= '0; rvfi_rd_wdata_q <= '0; end else begin rvfi_rd_addr_q <= rvfi_rd_addr_d; rvfi_rd_wdata_q <= rvfi_rd_wdata_d; end end if (WritebackStage) begin : g_rvfi_rf_wr_suppress_wb logic rvfi_stage_rf_wr_suppress_wb; logic rvfi_rf_wr_suppress_wb; // Set when RF write from load data is suppressed due to an integrity error assign rvfi_rf_wr_suppress_wb = instr_done_wb & ~rf_we_wb_o & outstanding_load_wb & lsu_load_resp_intg_err; always@(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_stage_rf_wr_suppress_wb <= 1'b0; end else if (rvfi_wb_done) begin rvfi_stage_rf_wr_suppress_wb <= rvfi_rf_wr_suppress_wb; end end assign rvfi_ext_rf_wr_suppress = rvfi_stage_rf_wr_suppress_wb; end else begin : g_rvfi_no_rf_wr_suppress_wb assign rvfi_ext_rf_wr_suppress = 1'b0; end // rvfi_intr must be set for first instruction that is part of a trap handler. // On the first cycle of a new instruction see if a trap PC was set by the previous instruction, // otherwise maintain value. assign rvfi_intr_d = instr_first_cycle_id ? rvfi_set_trap_pc_q : rvfi_intr_q; always_comb begin rvfi_set_trap_pc_d = rvfi_set_trap_pc_q; if (pc_set && pc_mux_id == PC_EXC && (exc_pc_mux_id == EXC_PC_EXC || exc_pc_mux_id == EXC_PC_IRQ)) begin // PC is set to enter a trap handler rvfi_set_trap_pc_d = 1'b1; end else if (rvfi_set_trap_pc_q && rvfi_id_done) begin // first instruction has been executed after PC is set to trap handler rvfi_set_trap_pc_d = 1'b0; end end always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin rvfi_set_trap_pc_q <= 1'b0; rvfi_intr_q <= 1'b0; end else begin rvfi_set_trap_pc_q <= rvfi_set_trap_pc_d; rvfi_intr_q <= rvfi_intr_d; end end `else logic unused_instr_new_id, unused_instr_id_done, unused_instr_done_wb; 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 // Certain parameter combinations are not supported `ASSERT_INIT(IllegalParamSecure, !(SecureIbex && (RV32M == RV32MNone))) ////////// // FCOV // ////////// `ifndef SYNTHESIS // fcov signals for V2S `DV_FCOV_SIGNAL_GEN_IF(logic, rf_ecc_err_a_id, gen_regfile_ecc.rf_ecc_err_a_id, RegFileECC) `DV_FCOV_SIGNAL_GEN_IF(logic, rf_ecc_err_b_id, gen_regfile_ecc.rf_ecc_err_b_id, RegFileECC) // fcov signals for CSR access. These are complicated by illegal accesses. Where an access is // legal `csr_op_en` signals the operation occurring, but this is deasserted where an access is // illegal. Instead `illegal_insn_id` confirms the instruction is taking an illegal instruction // exception. // All CSR operations perform a read, `CSR_OP_READ` is the only one that only performs a read `DV_FCOV_SIGNAL(logic, csr_read_only, (csr_op == CSR_OP_READ) && csr_access && (csr_op_en || illegal_insn_id)) `DV_FCOV_SIGNAL(logic, csr_write, cs_registers_i.csr_wr && csr_access && (csr_op_en || illegal_insn_id)) if (PMPEnable) begin : g_pmp_fcov_signals logic [PMPNumRegions-1:0] fcov_pmp_region_ichan_priority; logic [PMPNumRegions-1:0] fcov_pmp_region_ichan2_priority; logic [PMPNumRegions-1:0] fcov_pmp_region_dchan_priority; logic unused_fcov_pmp_region_priority; assign unused_fcov_pmp_region_priority = ^{fcov_pmp_region_ichan_priority, fcov_pmp_region_ichan2_priority, fcov_pmp_region_dchan_priority}; for (genvar i_region = 0; i_region < PMPNumRegions; i_region += 1) begin : g_pmp_region_fcov `DV_FCOV_SIGNAL(logic, pmp_region_ichan_access, g_pmp.pmp_i.region_match_all[PMP_I][i_region] & if_stage_i.if_id_pipe_reg_we) `DV_FCOV_SIGNAL(logic, pmp_region_ichan2_access, g_pmp.pmp_i.region_match_all[PMP_I2][i_region] & if_stage_i.if_id_pipe_reg_we) `DV_FCOV_SIGNAL(logic, pmp_region_dchan_access, g_pmp.pmp_i.region_match_all[PMP_D][i_region] & data_req_out) // pmp_cfg[5:6] is reserved and because of that the width of it inside cs_registers module // is 6-bit. `DV_FCOV_SIGNAL(logic, warl_check_pmpcfg, fcov_csr_write && (cs_registers_i.g_pmp_registers.g_pmp_csrs[i_region].u_pmp_cfg_csr.wr_data_i != {cs_registers_i.csr_wdata_int[(i_region%4)*PMP_CFG_W+:5], cs_registers_i.csr_wdata_int[(i_region%4)*PMP_CFG_W+7]})) if (i_region > 0) begin : g_region_priority assign fcov_pmp_region_ichan_priority[i_region] = g_pmp.pmp_i.region_match_all[PMP_I][i_region] & ~|g_pmp.pmp_i.region_match_all[PMP_I][i_region-1:0]; assign fcov_pmp_region_ichan2_priority[i_region] = g_pmp.pmp_i.region_match_all[PMP_I2][i_region] & ~|g_pmp.pmp_i.region_match_all[PMP_I2][i_region-1:0]; assign fcov_pmp_region_dchan_priority[i_region] = g_pmp.pmp_i.region_match_all[PMP_D][i_region] & ~|g_pmp.pmp_i.region_match_all[PMP_D][i_region-1:0]; end else begin : g_region_highest_priority assign fcov_pmp_region_ichan_priority[i_region] = g_pmp.pmp_i.region_match_all[PMP_I][i_region]; assign fcov_pmp_region_ichan2_priority[i_region] = g_pmp.pmp_i.region_match_all[PMP_I2][i_region]; assign fcov_pmp_region_dchan_priority[i_region] = g_pmp.pmp_i.region_match_all[PMP_D][i_region]; end end end `endif endmodule