ibex/rtl/ibex_core.sv
Tom Roberts 44b033cf8b [rtl] Add support for instruction fetch errors
- Add required signals to top-level
- Propagate error through fetch stages
- Add new exception type
- Update documentation for new exception type
- Resolves issue #109
2019-08-09 10:44:37 +01:00

814 lines
30 KiB
Systemverilog

// Copyright lowRISC contributors.
// Copyright 2018 ETH Zurich and University of Bologna.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
////////////////////////////////////////////////////////////////////////////////
// Engineer: Matthias Baer - baermatt@student.ethz.ch //
// //
// Additional contributions by: //
// Igor Loi - igor.loi@unibo.it //
// Andreas Traber - atraber@student.ethz.ch //
// Sven Stucki - svstucki@student.ethz.ch //
// Markus Wegmann - markus.wegmann@technokrat.ch //
// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
// //
// Design Name: Top level module //
// Project Name: ibex //
// Language: SystemVerilog //
// //
// Description: Top level module of the RISC-V core. //
// //
////////////////////////////////////////////////////////////////////////////////
`ifdef RISCV_FORMAL
`define RVFI
`endif
/**
* Top level module of the ibex RISC-V core
*/
module ibex_core #(
parameter int unsigned MHPMCounterNum = 0,
parameter int unsigned MHPMCounterWidth = 40,
parameter bit RV32E = 0,
parameter bit RV32M = 1,
parameter int unsigned DmHaltAddr = 32'h1A110800,
parameter int unsigned DmExceptionAddr = 32'h1A110808
) (
// Clock and Reset
input logic clk_i,
input logic rst_ni,
input logic test_en_i, // enable all clock gates for testing
// Core ID, Cluster ID and boot address are considered more or less static
input logic [ 3:0] core_id_i,
input logic [ 5:0] cluster_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 [31: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 [31:0] data_wdata_o,
input logic [31:0] data_rdata_i,
input logic data_err_i,
// 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
// Debug Interface
input logic debug_req_i,
// 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 [31:0] rvfi_insn_uncompressed,
output logic rvfi_trap,
output logic rvfi_halt,
output logic rvfi_intr,
output logic [ 1:0] rvfi_mode,
output logic [ 4:0] rvfi_rs1_addr,
output logic [ 4:0] rvfi_rs2_addr,
output logic [31:0] rvfi_rs1_rdata,
output logic [31:0] rvfi_rs2_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,
`endif
// CPU Control Signals
input logic fetch_enable_i
);
import ibex_pkg::*;
// IF/ID signals
logic instr_valid_id;
logic instr_new_id;
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
logic instr_is_compressed_id;
logic instr_fetch_err; // Bus error on instr fetch
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 instr_valid_clear;
logic pc_set;
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_e exc_cause; // Exception cause
logic lsu_load_err;
logic lsu_store_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] jump_target_ex;
logic branch_decision;
logic ctrl_busy;
logic if_busy;
logic lsu_busy;
//core busy signals
logic core_busy;
logic core_ctrl_firstfetch, core_busy_int, core_busy_q;
// 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] alu_adder_result_ex; // Used to forward computed address to LSU
logic [31:0] regfile_wdata_ex;
// Multiplier Control
logic mult_en_ex;
logic div_en_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;
// CSR control
logic csr_access;
csr_op_e csr_op;
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 data_we_ex;
logic [1:0] data_type_ex;
logic data_sign_ext_ex;
logic [1:0] data_reg_offset_ex;
logic data_req_ex;
logic [31:0] data_wdata_ex;
logic [31:0] regfile_wdata_lsu;
// stall control
logic id_in_ready;
logic ex_valid;
logic lsu_data_valid;
// Signals between instruction core interface and pipe (if and id stages)
logic instr_req_int; // Id stage asserts a req to instruction core interface
// Interrupts
logic irq_pending;
logic csr_msip;
logic csr_mtip;
logic csr_meip;
logic [14:0] csr_mfip;
logic csr_mstatus_mie;
logic [31:0] csr_mepc, csr_depc;
logic csr_save_if;
logic csr_save_id;
logic csr_restore_mret_id;
logic csr_save_cause;
logic csr_mtvec_init;
logic [31:0] csr_mtvec;
logic [31:0] csr_mtval;
// debug mode and dcsr configuration
dbg_cause_e debug_cause;
logic debug_csr_save;
logic debug_single_step;
logic debug_ebreakm;
// performance counter related signals
logic instr_ret;
logic instr_ret_compressed;
logic perf_imiss;
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
// RISC-V Formal Interface signals
`ifdef RVFI
logic rvfi_intr_d;
logic rvfi_set_trap_pc_d;
logic rvfi_set_trap_pc_q;
logic [31:0] rvfi_insn_id;
logic [4:0] rvfi_rs1_addr_id;
logic [4:0] rvfi_rs2_addr_id;
logic [31:0] rvfi_rs1_data_d;
logic [31:0] rvfi_rs1_data_id;
logic [31:0] rvfi_rs1_data_q;
logic [31:0] rvfi_rs2_data_d;
logic [31:0] rvfi_rs2_data_id;
logic [31:0] rvfi_rs2_data_q;
logic [4:0] rvfi_rd_addr_id;
logic [4:0] rvfi_rd_addr_q;
logic [4:0] rvfi_rd_addr_d;
logic [31:0] rvfi_rd_wdata_id;
logic [31:0] rvfi_rd_wdata_d;
logic [31:0] rvfi_rd_wdata_q;
logic rvfi_rd_we_id;
logic rvfi_insn_new_d;
logic rvfi_insn_new_q;
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;
`endif
//////////////////////
// Clock management //
//////////////////////
logic clk;
logic clock_en;
// if we are sleeping on a barrier let's just wait on the instruction
// interface to finish loading instructions
assign core_busy_int = if_busy | ctrl_busy | lsu_busy;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
core_busy_q <= 1'b0;
end else begin
core_busy_q <= core_busy_int;
end
end
assign core_busy = core_ctrl_firstfetch ? 1'b1 : core_busy_q;
assign clock_en = core_busy | debug_req_i | irq_pending | irq_nm_i;
// main clock gate of the core
// generates all clocks except the one for the debug unit which is
// independent
prim_clock_gating core_clock_gate_i (
.clk_i ( clk_i ),
.en_i ( clock_en ),
.test_en_i ( test_en_i ),
.clk_o ( clk )
);
//////////////
// IF stage //
//////////////
ibex_if_stage #(
.DmHaltAddr ( DmHaltAddr ),
.DmExceptionAddr ( DmExceptionAddr )
) if_stage_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
.boot_addr_i ( boot_addr_i ),
.req_i ( instr_req_int ), // 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_err_i ( instr_err_i ),
// 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_c_id_o ( instr_rdata_c_id ),
.instr_is_compressed_id_o ( instr_is_compressed_id ),
.instr_fetch_err_o ( instr_fetch_err ),
.illegal_c_insn_id_o ( illegal_c_insn_id ),
.pc_if_o ( pc_if ),
.pc_id_o ( pc_id ),
// control signals
.instr_valid_clear_i ( instr_valid_clear ),
.pc_set_i ( pc_set ),
.pc_mux_i ( pc_mux_id ),
.exc_pc_mux_i ( exc_pc_mux_id ),
.exc_cause ( exc_cause ),
// jump targets
.jump_target_ex_i ( jump_target_ex ),
// 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 ),
.if_busy_o ( if_busy ),
.perf_imiss_o ( perf_imiss )
);
//////////////
// ID stage //
//////////////
ibex_id_stage #(
.RV32E ( RV32E ),
.RV32M ( RV32M )
) id_stage_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
.test_en_i ( test_en_i ),
// Processor Enable
.fetch_enable_i ( fetch_enable_i ),
.ctrl_busy_o ( ctrl_busy ),
.core_ctrl_firstfetch_o ( core_ctrl_firstfetch ),
.illegal_insn_o ( illegal_insn_id ),
// from/to IF-ID pipeline register
.instr_valid_i ( instr_valid_id ),
.instr_new_i ( instr_new_id ),
.instr_rdata_i ( instr_rdata_id ),
.instr_rdata_c_i ( instr_rdata_c_id ),
.instr_is_compressed_i ( instr_is_compressed_id ),
// Jumps and branches
.branch_decision_i ( branch_decision ),
// IF and ID control signals
.id_in_ready_o ( id_in_ready ),
.instr_valid_clear_o ( instr_valid_clear ),
.instr_req_o ( instr_req_int ),
.pc_set_o ( pc_set ),
.pc_mux_o ( pc_mux_id ),
.exc_pc_mux_o ( exc_pc_mux_id ),
.exc_cause_o ( exc_cause ),
.instr_fetch_err_i ( instr_fetch_err ),
.illegal_c_insn_i ( illegal_c_insn_id ),
.pc_id_i ( pc_id ),
// Stalls
.ex_valid_i ( ex_valid ),
.lsu_valid_i ( lsu_data_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 ),
.mult_en_ex_o ( mult_en_ex ),
.div_en_ex_o ( div_en_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 ),
// CSR ID/EX
.csr_access_o ( csr_access ),
.csr_op_o ( csr_op ),
.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_restore_mret_id_o ( csr_restore_mret_id ), // restore mstatus upon MRET
.csr_save_cause_o ( csr_save_cause ),
.csr_mtval_o ( csr_mtval ),
.illegal_csr_insn_i ( illegal_csr_insn_id ),
// LSU
.data_req_ex_o ( data_req_ex ), // to load store unit
.data_we_ex_o ( data_we_ex ), // to load store unit
.data_type_ex_o ( data_type_ex ), // to load store unit
.data_sign_ext_ex_o ( data_sign_ext_ex ), // to load store unit
.data_reg_offset_ex_o ( data_reg_offset_ex ), // to load store unit
.data_wdata_ex_o ( data_wdata_ex ), // to 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_store_err_i ( lsu_store_err ),
// Interrupt Signals
.csr_mstatus_mie_i ( csr_mstatus_mie ),
.csr_msip_i ( csr_msip ),
.csr_mtip_i ( csr_mtip ),
.csr_meip_i ( csr_meip ),
.csr_mfip_i ( csr_mfip ),
.irq_pending_i ( irq_pending ),
.irq_nm_i ( irq_nm_i ),
// Debug Signal
.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 ),
// write data to commit in the register file
.regfile_wdata_lsu_i ( regfile_wdata_lsu ),
.regfile_wdata_ex_i ( regfile_wdata_ex ),
.csr_rdata_i ( csr_rdata ),
`ifdef RVFI
.rfvi_reg_raddr_ra_o ( rvfi_rs1_addr_id ),
.rfvi_reg_rdata_ra_o ( rvfi_rs1_data_id ),
.rfvi_reg_raddr_rb_o ( rvfi_rs2_addr_id ),
.rfvi_reg_rdata_rb_o ( rvfi_rs2_data_id ),
.rfvi_reg_waddr_rd_o ( rvfi_rd_addr_id ),
.rfvi_reg_wdata_rd_o ( rvfi_rd_wdata_id ),
.rfvi_reg_we_o ( rvfi_rd_we_id ),
`endif
// Performance Counters
.perf_jump_o ( perf_jump ),
.perf_branch_o ( perf_branch ),
.perf_tbranch_o ( perf_tbranch ),
.instr_ret_o ( instr_ret ),
.instr_ret_compressed_o ( instr_ret_compressed )
);
// for RVFI only
assign unused_illegal_insn_id = illegal_insn_id;
ibex_ex_block #(
.RV32M ( RV32M )
) ex_block_i (
.clk_i ( clk ),
.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 ),
// Multipler/Divider signal from ID stage
.multdiv_operator_i ( multdiv_operator_ex ),
.mult_en_i ( mult_en_ex ),
.div_en_i ( div_en_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 ),
// Outputs
.alu_adder_result_ex_o ( alu_adder_result_ex ), // to LSU
.regfile_wdata_ex_o ( regfile_wdata_ex ), // to ID
.jump_target_o ( jump_target_ex ), // to IF
.branch_decision_o ( branch_decision ), // to ID
.ex_valid_o ( ex_valid )
);
/////////////////////
// Load/store unit //
/////////////////////
ibex_load_store_unit load_store_unit_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
// data interface
.data_req_o ( data_req_o ),
.data_gnt_i ( data_gnt_i ),
.data_rvalid_i ( data_rvalid_i ),
.data_err_i ( data_err_i ),
.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
.data_we_ex_i ( data_we_ex ),
.data_type_ex_i ( data_type_ex ),
.data_wdata_ex_i ( data_wdata_ex ),
.data_reg_offset_ex_i ( data_reg_offset_ex ),
.data_sign_ext_ex_i ( data_sign_ext_ex ),
.data_rdata_ex_o ( regfile_wdata_lsu ),
.data_req_ex_i ( data_req_ex ),
.adder_result_ex_i ( alu_adder_result_ex ),
.addr_incr_req_o ( lsu_addr_incr_req ),
.addr_last_o ( lsu_addr_last ),
.data_valid_o ( lsu_data_valid ),
// exception signals
.load_err_o ( lsu_load_err ),
.store_err_o ( lsu_store_err ),
.busy_o ( lsu_busy )
);
/////////////////////////////////////////
// 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);
assign perf_load = data_req_o & data_gnt_i & (~data_we_o);
assign perf_store = data_req_o & data_gnt_i & data_we_o;
ibex_cs_registers #(
.MHPMCounterNum ( MHPMCounterNum ),
.MHPMCounterWidth ( MHPMCounterWidth ),
.RV32E ( RV32E ),
.RV32M ( RV32M )
) cs_registers_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
// Core and Cluster ID from outside
.core_id_i ( core_id_i ),
.cluster_id_i ( cluster_id_i ),
// 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_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 ),
.irq_pending_o ( irq_pending ),
.csr_msip_o ( csr_msip ),
.csr_mtip_o ( csr_mtip ),
.csr_meip_o ( csr_meip ),
.csr_mfip_o ( csr_mfip ),
.csr_mstatus_mie_o ( csr_mstatus_mie ),
.csr_mepc_o ( csr_mepc ),
// debug
.csr_depc_o ( csr_depc ),
.debug_cause_i ( debug_cause ),
.debug_csr_save_i ( debug_csr_save ),
.debug_single_step_o ( debug_single_step ),
.debug_ebreakm_o ( debug_ebreakm ),
.pc_if_i ( pc_if ),
.pc_id_i ( pc_id ),
.csr_save_if_i ( csr_save_if ),
.csr_save_id_i ( csr_save_id ),
.csr_restore_mret_i ( csr_restore_mret_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 ),
.instr_new_id_i ( instr_new_id ),
// performance counter related signals
.instr_ret_i ( instr_ret ),
.instr_ret_compressed_i ( instr_ret_compressed ),
.imiss_i ( perf_imiss ),
.pc_set_i ( pc_set ),
.jump_i ( perf_jump ),
.branch_i ( perf_branch ),
.branch_taken_i ( perf_tbranch ),
.mem_load_i ( perf_load ),
.mem_store_i ( perf_store ),
.lsu_busy_i ( lsu_busy )
);
`ifdef RVFI
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_halt <= '0;
rvfi_trap <= '0;
rvfi_intr <= '0;
rvfi_order <= '0;
rvfi_insn <= '0;
rvfi_insn_uncompressed <= '0;
rvfi_mode <= '0;
rvfi_rs1_addr <= '0;
rvfi_rs2_addr <= '0;
rvfi_pc_rdata <= '0;
rvfi_pc_wdata <= '0;
rvfi_mem_rmask <= '0;
rvfi_mem_wmask <= '0;
rvfi_valid <= '0;
rvfi_rs1_rdata <= '0;
rvfi_rs2_rdata <= '0;
rvfi_rd_wdata <= '0;
rvfi_rd_addr <= '0;
rvfi_mem_rdata <= '0;
rvfi_mem_wdata <= '0;
rvfi_mem_addr <= '0;
end else begin
rvfi_halt <= '0;
rvfi_trap <= illegal_insn_id;
rvfi_intr <= rvfi_intr_d;
rvfi_order <= rvfi_order + rvfi_valid;
rvfi_insn <= rvfi_insn_id;
rvfi_insn_uncompressed <= instr_rdata_id;
rvfi_mode <= PRIV_LVL_M; // TODO: Update for user mode support
rvfi_rs1_addr <= rvfi_rs1_addr_id;
rvfi_rs2_addr <= rvfi_rs2_addr_id;
rvfi_pc_rdata <= pc_id;
rvfi_pc_wdata <= pc_if;
rvfi_mem_rmask <= rvfi_mem_mask_int;
rvfi_mem_wmask <= data_we_o ? rvfi_mem_mask_int : 4'b0000;
rvfi_valid <= instr_ret;
rvfi_rs1_rdata <= rvfi_rs1_data_d;
rvfi_rs2_rdata <= rvfi_rs2_data_d;
rvfi_rd_wdata <= rvfi_rd_wdata_d;
rvfi_rd_addr <= rvfi_rd_addr_d;
rvfi_mem_rdata <= rvfi_mem_rdata_d;
rvfi_mem_wdata <= rvfi_mem_wdata_d;
rvfi_mem_addr <= rvfi_mem_addr_d;
end
end
// Keep the mem data stable for each instruction cycle
always_comb begin
if (rvfi_insn_new_d && lsu_data_valid) begin
rvfi_mem_addr_d = alu_adder_result_ex;
rvfi_mem_rdata_d = regfile_wdata_lsu;
rvfi_mem_wdata_d = data_wdata_ex;
end else begin
rvfi_mem_addr_d = rvfi_mem_addr_q;
rvfi_mem_rdata_d = rvfi_mem_rdata_q;
rvfi_mem_wdata_d = rvfi_mem_wdata_q;
end
end
always_ff @(posedge clk 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 (data_type_ex)
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 register data are kept stable for each instruction cycle
always_comb begin
if (instr_new_id) begin
rvfi_rs1_data_d = rvfi_rs1_data_id;
rvfi_rs2_data_d = rvfi_rs2_data_id;
end else begin
rvfi_rs1_data_d = rvfi_rs1_data_q;
rvfi_rs2_data_d = rvfi_rs2_data_q;
end
end
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_rs1_data_q <= '0;
rvfi_rs2_data_q <= '0;
end else begin
rvfi_rs1_data_q <= rvfi_rs1_data_d;
rvfi_rs2_data_q <= rvfi_rs2_data_d;
end
end
// RD write register is refreshed only once per cycle and
// then it is kept stable for the cycle.
always_comb begin
if (rvfi_insn_new_d) begin
if (!rvfi_rd_we_id) begin
rvfi_rd_addr_d = '0;
rvfi_rd_wdata_d = '0;
end else begin
rvfi_rd_addr_d = rvfi_rd_addr_id;
if (!rvfi_rd_addr_id) begin
rvfi_rd_wdata_d = '0;
end else begin
rvfi_rd_wdata_d = rvfi_rd_wdata_id;
end
end
end else begin
rvfi_rd_addr_d = rvfi_rd_addr_q;
rvfi_rd_wdata_d = rvfi_rd_wdata_q;
end
end
always_ff @(posedge clk 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
always_comb begin
if (instr_new_id) begin
rvfi_insn_new_d = 1'b1;
end else begin
rvfi_insn_new_d = rvfi_insn_new_q;
end
end
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_insn_new_q <= 1'b0;
end else begin
if (instr_ret) begin
rvfi_insn_new_q <= 1'b0;
end else begin
rvfi_insn_new_q <= rvfi_insn_new_d;
end
end
end
// generate rvfi_intr_d
assign rvfi_intr_d = rvfi_set_trap_pc_q & rvfi_insn_new_d;
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 && instr_ret) 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 or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_set_trap_pc_q <= 1'b0;
end else begin
rvfi_set_trap_pc_q <= rvfi_set_trap_pc_d;
end
end
`endif
endmodule