mirror of
https://github.com/lowRISC/ibex.git
synced 2025-06-27 17:00:41 -04:00
Currently, the dual-core lockstep FI mitigation is enabled/disabled using a single bit. For transient bit-flips, this is not problematic, as one bit-flip into this signal and one bit into the Ibex is required to threaten the security of the system. However, a permanent stuck-at-0 fault could disable the lockstep completely by targeting this signal. Then, only a single, additional fault (transient or permanent) is required. This PR enhances the FI resilience of the Ibex lockstep by encoding this single bit into a ibex_mubi_t signal, i.e., a 4-bit multi-bit signal. Signed-off-by: Pascal Nasahl <nasahlpa@lowrisc.org>
495 lines
21 KiB
Systemverilog
495 lines
21 KiB
Systemverilog
// Copyright lowRISC contributors.
|
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Ibex lockstep module
|
|
// This module instantiates a second copy of the core logic, and compares it's outputs against
|
|
// those from the main core. The second core runs synchronously with the main core, delayed by
|
|
// LockstepOffset cycles.
|
|
|
|
// SEC_CM: LOGIC.SHADOW
|
|
module ibex_lockstep import ibex_pkg::*; #(
|
|
parameter int unsigned LockstepOffset = 2,
|
|
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
|
|
) (
|
|
input logic clk_i,
|
|
input logic rst_ni,
|
|
|
|
input logic [31:0] hart_id_i,
|
|
input logic [31:0] boot_addr_i,
|
|
|
|
input logic instr_req_i,
|
|
input logic instr_gnt_i,
|
|
input logic instr_rvalid_i,
|
|
input logic [31:0] instr_addr_i,
|
|
input logic [MemDataWidth-1:0] instr_rdata_i,
|
|
input logic instr_err_i,
|
|
|
|
input logic data_req_i,
|
|
input logic data_gnt_i,
|
|
input logic data_rvalid_i,
|
|
input logic data_we_i,
|
|
input logic [3:0] data_be_i,
|
|
input logic [31:0] data_addr_i,
|
|
input logic [MemDataWidth-1:0] data_wdata_i,
|
|
input logic [MemDataWidth-1:0] data_rdata_i,
|
|
input logic data_err_i,
|
|
|
|
input logic dummy_instr_id_i,
|
|
input logic dummy_instr_wb_i,
|
|
input logic [4:0] rf_raddr_a_i,
|
|
input logic [4:0] rf_raddr_b_i,
|
|
input logic [4:0] rf_waddr_wb_i,
|
|
input logic rf_we_wb_i,
|
|
input logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc_i,
|
|
input logic [RegFileDataWidth-1:0] rf_rdata_a_ecc_i,
|
|
input logic [RegFileDataWidth-1:0] rf_rdata_b_ecc_i,
|
|
|
|
input logic [IC_NUM_WAYS-1:0] ic_tag_req_i,
|
|
input logic ic_tag_write_i,
|
|
input logic [IC_INDEX_W-1:0] ic_tag_addr_i,
|
|
input logic [TagSizeECC-1:0] ic_tag_wdata_i,
|
|
input logic [TagSizeECC-1:0] ic_tag_rdata_i [IC_NUM_WAYS],
|
|
input logic [IC_NUM_WAYS-1:0] ic_data_req_i,
|
|
input logic ic_data_write_i,
|
|
input logic [IC_INDEX_W-1:0] ic_data_addr_i,
|
|
input logic [LineSizeECC-1:0] ic_data_wdata_i,
|
|
input logic [LineSizeECC-1:0] ic_data_rdata_i [IC_NUM_WAYS],
|
|
input logic ic_scr_key_valid_i,
|
|
input logic ic_scr_key_req_i,
|
|
|
|
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,
|
|
input logic irq_pending_i,
|
|
|
|
input logic debug_req_i,
|
|
input crash_dump_t crash_dump_i,
|
|
input logic double_fault_seen_i,
|
|
|
|
input ibex_mubi_t fetch_enable_i,
|
|
output logic alert_minor_o,
|
|
output logic alert_major_internal_o,
|
|
output logic alert_major_bus_o,
|
|
input ibex_mubi_t core_busy_i,
|
|
input logic test_en_i,
|
|
input logic scan_rst_ni
|
|
);
|
|
|
|
localparam int unsigned LockstepOffsetW = $clog2(LockstepOffset);
|
|
// Core outputs are delayed for an extra cycle due to shadow output registers
|
|
localparam int unsigned OutputsOffset = LockstepOffset + 1;
|
|
|
|
//////////////////////
|
|
// Reset generation //
|
|
//////////////////////
|
|
|
|
// Upon reset, the comparison is stopped and the shadow core is reset, both immediately. A
|
|
// counter is started. After LockstepOffset clock cycles:
|
|
// - The counter is stopped.
|
|
// - The reset of the shadow core is synchronously released.
|
|
// The comparison is started in the following clock cycle.
|
|
|
|
logic [LockstepOffsetW-1:0] rst_shadow_cnt;
|
|
logic rst_shadow_cnt_err;
|
|
ibex_mubi_t rst_shadow_set_d, rst_shadow_set_q;
|
|
logic rst_shadow_n, rst_shadow_set_single_bit;
|
|
ibex_mubi_t enable_cmp_d, enable_cmp_q;
|
|
|
|
// This counter primitive starts counting to LockstepOffset after a system
|
|
// reset. The counter value saturates at LockstepOffset.
|
|
prim_count #(
|
|
.Width (LockstepOffsetW ),
|
|
.ResetValue (LockstepOffsetW'(1'b0) )
|
|
) u_rst_shadow_cnt (
|
|
.clk_i (clk_i ),
|
|
.rst_ni (rst_ni ),
|
|
.clr_i (1'b0 ),
|
|
.set_i (1'b0 ),
|
|
.set_cnt_i ('0 ),
|
|
.incr_en_i (1'b1 ),
|
|
.decr_en_i (1'b0 ),
|
|
.step_i (LockstepOffsetW'(1'b1) ),
|
|
.cnt_o (rst_shadow_cnt ),
|
|
.cnt_next_o ( ),
|
|
.err_o (rst_shadow_cnt_err )
|
|
);
|
|
|
|
// When the LockstepOffset counter value is reached, activate the lockstep
|
|
// comparison. We do not explicitly check whether rst_shadow_set_q forms a valid
|
|
// multibit signal as this value is implicitly checked by the enable_cmp
|
|
// comparison below.
|
|
assign rst_shadow_set_d =
|
|
(rst_shadow_cnt >= LockstepOffsetW'(LockstepOffset - 1)) ? IbexMuBiOn : IbexMuBiOff;
|
|
|
|
// Enable lockstep comparison.
|
|
assign enable_cmp_d = rst_shadow_set_q;
|
|
|
|
// This assignment is needed in order to avoid "Warning-IMPERFECTSCH" messages.
|
|
// TODO: Remove when updating Verilator #2134.
|
|
assign rst_shadow_set_single_bit = rst_shadow_set_q[0];
|
|
|
|
// The primitives below are used to place size-only constraints in order to prevent
|
|
// synthesis optimizations and preserve anchor points for constraining backend tools.
|
|
prim_flop #(
|
|
.Width(IbexMuBiWidth),
|
|
.ResetValue(IbexMuBiOff)
|
|
) u_prim_rst_shadow_set_flop (
|
|
.clk_i (clk_i),
|
|
.rst_ni(rst_ni),
|
|
.d_i (rst_shadow_set_d),
|
|
.q_o (rst_shadow_set_q)
|
|
);
|
|
|
|
prim_flop #(
|
|
.Width(IbexMuBiWidth),
|
|
.ResetValue(IbexMuBiOff)
|
|
) u_prim_enable_cmp_flop (
|
|
.clk_i (clk_i),
|
|
.rst_ni(rst_ni),
|
|
.d_i (enable_cmp_d),
|
|
.q_o (enable_cmp_q)
|
|
);
|
|
|
|
prim_clock_mux2 #(
|
|
.NoFpgaBufG(1'b1)
|
|
) u_prim_rst_shadow_n_mux2 (
|
|
.clk0_i(rst_shadow_set_single_bit),
|
|
.clk1_i(scan_rst_ni),
|
|
.sel_i (test_en_i),
|
|
.clk_o (rst_shadow_n)
|
|
);
|
|
|
|
//////////////////
|
|
// Input delays //
|
|
//////////////////
|
|
|
|
typedef struct packed {
|
|
logic instr_gnt;
|
|
logic instr_rvalid;
|
|
logic [MemDataWidth-1:0] instr_rdata;
|
|
logic instr_err;
|
|
logic data_gnt;
|
|
logic data_rvalid;
|
|
logic [MemDataWidth-1:0] data_rdata;
|
|
logic data_err;
|
|
logic [RegFileDataWidth-1:0] rf_rdata_a_ecc;
|
|
logic [RegFileDataWidth-1:0] rf_rdata_b_ecc;
|
|
logic irq_software;
|
|
logic irq_timer;
|
|
logic irq_external;
|
|
logic [14:0] irq_fast;
|
|
logic irq_nm;
|
|
logic debug_req;
|
|
ibex_mubi_t fetch_enable;
|
|
logic ic_scr_key_valid;
|
|
} delayed_inputs_t;
|
|
|
|
delayed_inputs_t [LockstepOffset-1:0] shadow_inputs_q;
|
|
delayed_inputs_t shadow_inputs_in;
|
|
// Packed arrays must be dealt with separately
|
|
logic [TagSizeECC-1:0] shadow_tag_rdata_q [IC_NUM_WAYS][LockstepOffset];
|
|
logic [LineSizeECC-1:0] shadow_data_rdata_q [IC_NUM_WAYS][LockstepOffset];
|
|
|
|
// Assign the inputs to the delay structure
|
|
assign shadow_inputs_in.instr_gnt = instr_gnt_i;
|
|
assign shadow_inputs_in.instr_rvalid = instr_rvalid_i;
|
|
assign shadow_inputs_in.instr_rdata = instr_rdata_i;
|
|
assign shadow_inputs_in.instr_err = instr_err_i;
|
|
assign shadow_inputs_in.data_gnt = data_gnt_i;
|
|
assign shadow_inputs_in.data_rvalid = data_rvalid_i;
|
|
assign shadow_inputs_in.data_rdata = data_rdata_i;
|
|
assign shadow_inputs_in.data_err = data_err_i;
|
|
assign shadow_inputs_in.rf_rdata_a_ecc = rf_rdata_a_ecc_i;
|
|
assign shadow_inputs_in.rf_rdata_b_ecc = rf_rdata_b_ecc_i;
|
|
assign shadow_inputs_in.irq_software = irq_software_i;
|
|
assign shadow_inputs_in.irq_timer = irq_timer_i;
|
|
assign shadow_inputs_in.irq_external = irq_external_i;
|
|
assign shadow_inputs_in.irq_fast = irq_fast_i;
|
|
assign shadow_inputs_in.irq_nm = irq_nm_i;
|
|
assign shadow_inputs_in.debug_req = debug_req_i;
|
|
assign shadow_inputs_in.fetch_enable = fetch_enable_i;
|
|
assign shadow_inputs_in.ic_scr_key_valid = ic_scr_key_valid_i;
|
|
|
|
// Delay the inputs
|
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
if (!rst_ni) begin
|
|
for (int unsigned i = 0; i < LockstepOffset; i++) begin
|
|
shadow_inputs_q[i] <= delayed_inputs_t'('0);
|
|
shadow_tag_rdata_q[i] <= '{default: 0};
|
|
shadow_data_rdata_q[i] <= '{default: 0};
|
|
end
|
|
end else begin
|
|
for (int unsigned i = 0; i < LockstepOffset - 1; i++) begin
|
|
shadow_inputs_q[i] <= shadow_inputs_q[i+1];
|
|
shadow_tag_rdata_q[i] <= shadow_tag_rdata_q[i+1];
|
|
shadow_data_rdata_q[i] <= shadow_data_rdata_q[i+1];
|
|
end
|
|
shadow_inputs_q[LockstepOffset-1] <= shadow_inputs_in;
|
|
shadow_tag_rdata_q[LockstepOffset-1] <= ic_tag_rdata_i;
|
|
shadow_data_rdata_q[LockstepOffset-1] <= ic_data_rdata_i;
|
|
end
|
|
end
|
|
|
|
///////////////////
|
|
// Output delays //
|
|
///////////////////
|
|
|
|
typedef struct packed {
|
|
logic instr_req;
|
|
logic [31:0] instr_addr;
|
|
logic data_req;
|
|
logic data_we;
|
|
logic [3:0] data_be;
|
|
logic [31:0] data_addr;
|
|
logic [MemDataWidth-1:0] data_wdata;
|
|
logic dummy_instr_id;
|
|
logic dummy_instr_wb;
|
|
logic [4:0] rf_raddr_a;
|
|
logic [4:0] rf_raddr_b;
|
|
logic [4:0] rf_waddr_wb;
|
|
logic rf_we_wb;
|
|
logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc;
|
|
logic [IC_NUM_WAYS-1:0] ic_tag_req;
|
|
logic ic_tag_write;
|
|
logic [IC_INDEX_W-1:0] ic_tag_addr;
|
|
logic [TagSizeECC-1:0] ic_tag_wdata;
|
|
logic [IC_NUM_WAYS-1:0] ic_data_req;
|
|
logic ic_data_write;
|
|
logic [IC_INDEX_W-1:0] ic_data_addr;
|
|
logic [LineSizeECC-1:0] ic_data_wdata;
|
|
logic ic_scr_key_req;
|
|
logic irq_pending;
|
|
crash_dump_t crash_dump;
|
|
logic double_fault_seen;
|
|
ibex_mubi_t core_busy;
|
|
} delayed_outputs_t;
|
|
|
|
delayed_outputs_t [OutputsOffset-1:0] core_outputs_q;
|
|
delayed_outputs_t core_outputs_in;
|
|
delayed_outputs_t shadow_outputs_d, shadow_outputs_q;
|
|
|
|
// Assign core outputs to the structure
|
|
assign core_outputs_in.instr_req = instr_req_i;
|
|
assign core_outputs_in.instr_addr = instr_addr_i;
|
|
assign core_outputs_in.data_req = data_req_i;
|
|
assign core_outputs_in.data_we = data_we_i;
|
|
assign core_outputs_in.data_be = data_be_i;
|
|
assign core_outputs_in.data_addr = data_addr_i;
|
|
assign core_outputs_in.data_wdata = data_wdata_i;
|
|
assign core_outputs_in.dummy_instr_id = dummy_instr_id_i;
|
|
assign core_outputs_in.dummy_instr_wb = dummy_instr_wb_i;
|
|
assign core_outputs_in.rf_raddr_a = rf_raddr_a_i;
|
|
assign core_outputs_in.rf_raddr_b = rf_raddr_b_i;
|
|
assign core_outputs_in.rf_waddr_wb = rf_waddr_wb_i;
|
|
assign core_outputs_in.rf_we_wb = rf_we_wb_i;
|
|
assign core_outputs_in.rf_wdata_wb_ecc = rf_wdata_wb_ecc_i;
|
|
assign core_outputs_in.ic_tag_req = ic_tag_req_i;
|
|
assign core_outputs_in.ic_tag_write = ic_tag_write_i;
|
|
assign core_outputs_in.ic_tag_addr = ic_tag_addr_i;
|
|
assign core_outputs_in.ic_tag_wdata = ic_tag_wdata_i;
|
|
assign core_outputs_in.ic_data_req = ic_data_req_i;
|
|
assign core_outputs_in.ic_data_write = ic_data_write_i;
|
|
assign core_outputs_in.ic_data_addr = ic_data_addr_i;
|
|
assign core_outputs_in.ic_data_wdata = ic_data_wdata_i;
|
|
assign core_outputs_in.ic_scr_key_req = ic_scr_key_req_i;
|
|
assign core_outputs_in.irq_pending = irq_pending_i;
|
|
assign core_outputs_in.crash_dump = crash_dump_i;
|
|
assign core_outputs_in.double_fault_seen = double_fault_seen_i;
|
|
assign core_outputs_in.core_busy = core_busy_i;
|
|
|
|
// Delay the outputs
|
|
always_ff @(posedge clk_i) begin
|
|
for (int unsigned i = 0; i < OutputsOffset - 1; i++) begin
|
|
core_outputs_q[i] <= core_outputs_q[i+1];
|
|
end
|
|
core_outputs_q[OutputsOffset-1] <= core_outputs_in;
|
|
end
|
|
|
|
///////////////////////////////
|
|
// Shadow core instantiation //
|
|
///////////////////////////////
|
|
|
|
logic shadow_alert_minor, shadow_alert_major_internal, shadow_alert_major_bus;
|
|
|
|
ibex_core #(
|
|
.PMPEnable ( PMPEnable ),
|
|
.PMPGranularity ( PMPGranularity ),
|
|
.PMPNumRegions ( PMPNumRegions ),
|
|
.MHPMCounterNum ( MHPMCounterNum ),
|
|
.MHPMCounterWidth ( MHPMCounterWidth ),
|
|
.RV32E ( RV32E ),
|
|
.RV32M ( RV32M ),
|
|
.RV32B ( RV32B ),
|
|
.BranchTargetALU ( BranchTargetALU ),
|
|
.ICache ( ICache ),
|
|
.ICacheECC ( ICacheECC ),
|
|
.BusSizeECC ( BusSizeECC ),
|
|
.TagSizeECC ( TagSizeECC ),
|
|
.LineSizeECC ( LineSizeECC ),
|
|
.BranchPredictor ( BranchPredictor ),
|
|
.DbgTriggerEn ( DbgTriggerEn ),
|
|
.DbgHwBreakNum ( DbgHwBreakNum ),
|
|
.WritebackStage ( WritebackStage ),
|
|
.ResetAll ( ResetAll ),
|
|
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
|
|
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
|
|
.SecureIbex ( SecureIbex ),
|
|
.DummyInstructions ( DummyInstructions ),
|
|
.RegFileECC ( RegFileECC ),
|
|
.RegFileDataWidth ( RegFileDataWidth ),
|
|
.MemECC ( MemECC ),
|
|
.MemDataWidth ( MemDataWidth ),
|
|
.DmHaltAddr ( DmHaltAddr ),
|
|
.DmExceptionAddr ( DmExceptionAddr )
|
|
) u_shadow_core (
|
|
.clk_i (clk_i),
|
|
.rst_ni (rst_shadow_n),
|
|
|
|
.hart_id_i (hart_id_i),
|
|
.boot_addr_i (boot_addr_i),
|
|
|
|
.instr_req_o (shadow_outputs_d.instr_req),
|
|
.instr_gnt_i (shadow_inputs_q[0].instr_gnt),
|
|
.instr_rvalid_i (shadow_inputs_q[0].instr_rvalid),
|
|
.instr_addr_o (shadow_outputs_d.instr_addr),
|
|
.instr_rdata_i (shadow_inputs_q[0].instr_rdata),
|
|
.instr_err_i (shadow_inputs_q[0].instr_err),
|
|
|
|
.data_req_o (shadow_outputs_d.data_req),
|
|
.data_gnt_i (shadow_inputs_q[0].data_gnt),
|
|
.data_rvalid_i (shadow_inputs_q[0].data_rvalid),
|
|
.data_we_o (shadow_outputs_d.data_we),
|
|
.data_be_o (shadow_outputs_d.data_be),
|
|
.data_addr_o (shadow_outputs_d.data_addr),
|
|
.data_wdata_o (shadow_outputs_d.data_wdata),
|
|
.data_rdata_i (shadow_inputs_q[0].data_rdata),
|
|
.data_err_i (shadow_inputs_q[0].data_err),
|
|
|
|
.dummy_instr_id_o (shadow_outputs_d.dummy_instr_id),
|
|
.dummy_instr_wb_o (shadow_outputs_d.dummy_instr_wb),
|
|
.rf_raddr_a_o (shadow_outputs_d.rf_raddr_a),
|
|
.rf_raddr_b_o (shadow_outputs_d.rf_raddr_b),
|
|
.rf_waddr_wb_o (shadow_outputs_d.rf_waddr_wb),
|
|
.rf_we_wb_o (shadow_outputs_d.rf_we_wb),
|
|
.rf_wdata_wb_ecc_o (shadow_outputs_d.rf_wdata_wb_ecc),
|
|
.rf_rdata_a_ecc_i (shadow_inputs_q[0].rf_rdata_a_ecc),
|
|
.rf_rdata_b_ecc_i (shadow_inputs_q[0].rf_rdata_b_ecc),
|
|
|
|
.ic_tag_req_o (shadow_outputs_d.ic_tag_req),
|
|
.ic_tag_write_o (shadow_outputs_d.ic_tag_write),
|
|
.ic_tag_addr_o (shadow_outputs_d.ic_tag_addr),
|
|
.ic_tag_wdata_o (shadow_outputs_d.ic_tag_wdata),
|
|
.ic_tag_rdata_i (shadow_tag_rdata_q[0]),
|
|
.ic_data_req_o (shadow_outputs_d.ic_data_req),
|
|
.ic_data_write_o (shadow_outputs_d.ic_data_write),
|
|
.ic_data_addr_o (shadow_outputs_d.ic_data_addr),
|
|
.ic_data_wdata_o (shadow_outputs_d.ic_data_wdata),
|
|
.ic_data_rdata_i (shadow_data_rdata_q[0]),
|
|
.ic_scr_key_valid_i (shadow_inputs_q[0].ic_scr_key_valid),
|
|
.ic_scr_key_req_o (shadow_outputs_d.ic_scr_key_req),
|
|
|
|
.irq_software_i (shadow_inputs_q[0].irq_software),
|
|
.irq_timer_i (shadow_inputs_q[0].irq_timer),
|
|
.irq_external_i (shadow_inputs_q[0].irq_external),
|
|
.irq_fast_i (shadow_inputs_q[0].irq_fast),
|
|
.irq_nm_i (shadow_inputs_q[0].irq_nm),
|
|
.irq_pending_o (shadow_outputs_d.irq_pending),
|
|
|
|
.debug_req_i (shadow_inputs_q[0].debug_req),
|
|
.crash_dump_o (shadow_outputs_d.crash_dump),
|
|
.double_fault_seen_o (shadow_outputs_d.double_fault_seen),
|
|
|
|
`ifdef RVFI
|
|
.rvfi_valid (),
|
|
.rvfi_order (),
|
|
.rvfi_insn (),
|
|
.rvfi_trap (),
|
|
.rvfi_halt (),
|
|
.rvfi_intr (),
|
|
.rvfi_mode (),
|
|
.rvfi_ixl (),
|
|
.rvfi_rs1_addr (),
|
|
.rvfi_rs2_addr (),
|
|
.rvfi_rs3_addr (),
|
|
.rvfi_rs1_rdata (),
|
|
.rvfi_rs2_rdata (),
|
|
.rvfi_rs3_rdata (),
|
|
.rvfi_rd_addr (),
|
|
.rvfi_rd_wdata (),
|
|
.rvfi_pc_rdata (),
|
|
.rvfi_pc_wdata (),
|
|
.rvfi_mem_addr (),
|
|
.rvfi_mem_rmask (),
|
|
.rvfi_mem_wmask (),
|
|
.rvfi_mem_rdata (),
|
|
.rvfi_mem_wdata (),
|
|
.rvfi_ext_mip (),
|
|
.rvfi_ext_nmi (),
|
|
.rvfi_ext_nmi_int (),
|
|
.rvfi_ext_debug_req (),
|
|
.rvfi_ext_debug_mode (),
|
|
.rvfi_ext_rf_wr_suppress (),
|
|
.rvfi_ext_mcycle (),
|
|
.rvfi_ext_mhpmcounters (),
|
|
.rvfi_ext_mhpmcountersh (),
|
|
.rvfi_ext_ic_scr_key_valid (),
|
|
.rvfi_ext_irq_valid (),
|
|
`endif
|
|
|
|
.fetch_enable_i (shadow_inputs_q[0].fetch_enable),
|
|
.alert_minor_o (shadow_alert_minor),
|
|
.alert_major_internal_o (shadow_alert_major_internal),
|
|
.alert_major_bus_o (shadow_alert_major_bus),
|
|
.core_busy_o (shadow_outputs_d.core_busy)
|
|
);
|
|
|
|
// Register the shadow core outputs
|
|
always_ff @(posedge clk_i) begin
|
|
shadow_outputs_q <= shadow_outputs_d;
|
|
end
|
|
|
|
/////////////////////////
|
|
// Compare the outputs //
|
|
/////////////////////////
|
|
|
|
logic outputs_mismatch;
|
|
|
|
assign outputs_mismatch =
|
|
(enable_cmp_q != IbexMuBiOff) & (shadow_outputs_q != core_outputs_q[0]);
|
|
assign alert_major_internal_o
|
|
= outputs_mismatch | shadow_alert_major_internal | rst_shadow_cnt_err;
|
|
assign alert_major_bus_o = shadow_alert_major_bus;
|
|
assign alert_minor_o = shadow_alert_minor;
|
|
|
|
endmodule
|