Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dv/riscv_compliance/rtl/ibex_riscv_compliance.sv
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module ibex_riscv_compliance (
parameter bit ICacheECC = 1'b0;
parameter bit BranchPredictor = 1'b0;
parameter bit SecureIbex = 1'b0;
parameter int unsigned LockstepOffset = 1;
parameter bit ICacheScramble = 1'b0;
parameter bit DbgTriggerEn = 1'b0;

Expand Down Expand Up @@ -156,6 +157,7 @@ module ibex_riscv_compliance (
.BranchPredictor (BranchPredictor ),
.DbgTriggerEn (DbgTriggerEn ),
.SecureIbex (SecureIbex ),
.LockstepOffset (LockstepOffset ),
.ICacheScramble (ICacheScramble ),
.DmBaseAddr (32'h00000000 ),
.DmAddrMask (32'h00000003 ),
Expand Down
9 changes: 6 additions & 3 deletions dv/uvm/core_ibex/tb/core_ibex_tb_top.sv
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ module core_ibex_tb_top;
parameter bit ICacheECC = 1'b0;
parameter bit BranchPredictor = 1'b0;
parameter bit SecureIbex = 1'b0;
parameter int unsigned LockstepOffset = 1;
parameter bit ICacheScramble = 1'b0;
parameter bit DbgTriggerEn = 1'b0;
parameter int unsigned DmBaseAddr = 32'h`DM_ADDR;
Expand Down Expand Up @@ -107,6 +108,7 @@ module core_ibex_tb_top;
.ICache (ICache ),
.ICacheECC (ICacheECC ),
.SecureIbex (SecureIbex ),
.LockstepOffset (LockstepOffset ),
.ICacheScramble (ICacheScramble ),
.BranchPredictor (BranchPredictor ),
.DbgTriggerEn (DbgTriggerEn ),
Expand Down Expand Up @@ -377,9 +379,10 @@ module core_ibex_tb_top;
end

// Manually set unused_assert_connected = 1 to disable the AssertConnected_A assertion for
// prim_count in case lockstep (set by SecureIbex) is enabled. If not disabled, DV fails.
if (SecureIbex) begin : gen_disable_count_check
assign dut.u_ibex_top.gen_lockstep.u_ibex_lockstep.u_rst_shadow_cnt.
// prim_count in case lockstep (set by SecureIbex) is enabled and the lockstep offset is
// larger than 1. If not disabled, DV fails.
if (SecureIbex && LockstepOffset > 1) begin : gen_disable_count_check
assign dut.u_ibex_top.gen_lockstep.u_ibex_lockstep.gen_reset_counter.u_rst_shadow_cnt.
unused_assert_connected = 1;
end

Expand Down
2 changes: 2 additions & 0 deletions examples/simple_system/rtl/ibex_simple_system.sv
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ module ibex_simple_system (
);

parameter bit SecureIbex = 1'b0;
parameter int unsigned LockstepOffset = 1;
parameter bit ICacheScramble = 1'b0;
parameter bit PMPEnable = 1'b0;
parameter int unsigned PMPGranularity = 0;
Expand Down Expand Up @@ -197,6 +198,7 @@ module ibex_simple_system (

ibex_top_tracing #(
.SecureIbex ( SecureIbex ),
.LockstepOffset ( LockstepOffset ),
.ICacheScramble ( ICacheScramble ),
.PMPEnable ( PMPEnable ),
.PMPGranularity ( PMPGranularity ),
Expand Down
1 change: 1 addition & 0 deletions ibex_top.core
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ filesets:
- lowrisc:prim:ram_1p_scr
- lowrisc:prim:onehot_check
- lowrisc:prim:onehot
- lowrisc:prim:util
files:
- rtl/ibex_register_file_ff.sv # generic FF-based
- rtl/ibex_register_file_fpga.sv # FPGA
Expand Down
181 changes: 118 additions & 63 deletions rtl/ibex_lockstep.sv
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

// SEC_CM: LOGIC.SHADOW
module ibex_lockstep import ibex_pkg::*; #(
parameter int unsigned LockstepOffset = 2,
parameter int unsigned LockstepOffset = 1,
parameter bit PMPEnable = 1'b0,
parameter int unsigned PMPGranularity = 0,
parameter int unsigned PMPNumRegions = 4,
Expand Down Expand Up @@ -116,55 +116,75 @@ module ibex_lockstep import ibex_pkg::*; #(
input logic scan_rst_ni
);

localparam int unsigned LockstepOffsetW = $clog2(LockstepOffset);
localparam int unsigned LockstepOffsetW = prim_util_pkg::vbits(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;
ibex_mubi_t enable_cmp_d, enable_cmp_q;
if (LockstepOffset > 1) begin : gen_reset_counter
// 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;
// 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) ),
.commit_i (1'b1 ),
.cnt_o (rst_shadow_cnt ),
.cnt_after_commit_o ( ),
.err_o (rst_shadow_cnt_err )
);

// When the LockstepOffset counter value is reached, activate the lockstep
// comparison.
assign rst_shadow_set_d =
(rst_shadow_cnt >= LockstepOffsetW'(LockstepOffset - 1)) ? IbexMuBiOn : IbexMuBiOff;

// Enable lockstep comparison.
assign enable_cmp_d = rst_shadow_set_q;

end else begin : gen_no_reset_counter
// Assert rst_shadow_set_d as soon as we have the first clk_i and rst_ni posedge.
// The reset of the shadow core will then be enabled with a delay of 1 cycle with
// rst_shadow_set_q.
assign rst_shadow_set_d = IbexMuBiOn;

// Tie off this error as it is not used in the `LockstepOffset = 1` case.
assign rst_shadow_cnt_err = 1'b0;

// Delay the comparison enable signal by 1 cycle.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
enable_cmp_d <= IbexMuBiOff;
end else begin
enable_cmp_d <= IbexMuBiOn;
end
end

// 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) ),
.commit_i (1'b1 ),
.cnt_o (rst_shadow_cnt ),
.cnt_after_commit_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;
// Tie off the upper unused bits of rst_shadow_set_q.
logic [2:0] unused_bits;
assign unused_bits = rst_shadow_set_q[3:1];
end

// The primitives below are used to place size-only constraints in order to prevent
// synthesis optimizations and preserve anchor points for constraining backend tools.
Expand Down Expand Up @@ -224,9 +244,62 @@ module ibex_lockstep import ibex_pkg::*; #(

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];
logic [TagSizeECC-1:0] shadow_tag_rdata_delayed [IC_NUM_WAYS];
logic [LineSizeECC-1:0] shadow_data_rdata_delayed [IC_NUM_WAYS];
if (LockstepOffset > 1) begin : gen_multi_cycle_delay
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 shadow_tag_rdata_delayed = shadow_tag_rdata_q[0];
assign shadow_data_rdata_delayed = shadow_data_rdata_q[0];

// Delay the ic_tag_rdata_i and ic_data_rdata_i inputs by LockstepOffset cycles.
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
end else begin : gen_single_cycle_delay
// If LockstepOffset = 1, using:
// logic [TagSizeECC-1:0] shadow_tag_rdata_q [IC_NUM_WAYS][LockstepOffset];
// logic [TagSizeECC-1:0] shadow_tag_rdata_q [IC_NUM_WAYS][LockstepOffset];
// aborts the compilation with an error message:
// `port or terminal connection type check failed on instance`
// Hence, in this case, remove the unpacked array dimension.
logic [TagSizeECC-1:0] shadow_tag_rdata_q [IC_NUM_WAYS];
logic [LineSizeECC-1:0] shadow_data_rdata_q [IC_NUM_WAYS];

assign shadow_tag_rdata_delayed = shadow_tag_rdata_q;
assign shadow_data_rdata_delayed = shadow_data_rdata_q;

// Delay the ic_tag_rdata_i and ic_data_rdata_i inputs by 1 cycle.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
shadow_inputs_q <= delayed_inputs_t'('0);
shadow_tag_rdata_q <= '{default: 0};
shadow_data_rdata_q <= '{default: 0};
end else begin
shadow_inputs_q <= shadow_inputs_in;
shadow_tag_rdata_q <= ic_tag_rdata_i;
shadow_data_rdata_q <= ic_data_rdata_i;
end
end
end

// Assign the inputs to the delay structure
assign shadow_inputs_in.instr_gnt = instr_gnt_i;
Expand All @@ -248,26 +321,6 @@ module ibex_lockstep import ibex_pkg::*; #(
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 //
///////////////////
Expand Down Expand Up @@ -425,12 +478,12 @@ module ibex_lockstep import ibex_pkg::*; #(
.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_tag_rdata_i (shadow_tag_rdata_delayed),
.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_data_rdata_i (shadow_data_rdata_delayed),
.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),

Expand Down Expand Up @@ -504,8 +557,10 @@ module ibex_lockstep import ibex_pkg::*; #(

logic outputs_mismatch;

// Any value except IbexMuBiOff will turn on the lockstep output comparison.
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;
Expand Down
2 changes: 2 additions & 0 deletions rtl/ibex_top.sv
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module ibex_top import ibex_pkg::*; #(
parameter bit DbgTriggerEn = 1'b0,
parameter int unsigned DbgHwBreakNum = 1,
parameter bit SecureIbex = 1'b0,
parameter int unsigned LockstepOffset = 1,
parameter bit ICacheScramble = 1'b0,
parameter int unsigned ICacheScrNumPrinceRoundsHalf = 2,
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
Expand Down Expand Up @@ -1049,6 +1050,7 @@ module ibex_top import ibex_pkg::*; #(
.RndCnstLfsrSeed (RndCnstLfsrSeed),
.RndCnstLfsrPerm (RndCnstLfsrPerm),
.SecureIbex (SecureIbex),
.LockstepOffset (LockstepOffset),
.DummyInstructions(DummyInstructions),
.RegFileECC (RegFileECC),
.RegFileDataWidth (RegFileDataWidth),
Expand Down
2 changes: 2 additions & 0 deletions rtl/ibex_top_tracing.sv
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module ibex_top_tracing import ibex_pkg::*; #(
parameter bit DbgTriggerEn = 1'b0,
parameter int unsigned DbgHwBreakNum = 1,
parameter bit SecureIbex = 1'b0,
parameter int unsigned LockstepOffset = 1,
parameter bit ICacheScramble = 1'b0,
parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault,
parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault,
Expand Down Expand Up @@ -195,6 +196,7 @@ module ibex_top_tracing import ibex_pkg::*; #(
.DbgHwBreakNum ( DbgHwBreakNum ),
.WritebackStage ( WritebackStage ),
.SecureIbex ( SecureIbex ),
.LockstepOffset ( LockstepOffset ),
.ICacheScramble ( ICacheScramble ),
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
Expand Down
Loading