Skip to content

Commit e138d32

Browse files
committed
[rtl] Split data and ECC of the register file
Until now, a single instance of the register file containing 32-bit data words and 7-bit ECC tags was used. While the input of the register file was driven by the main core, the output of the register file was distributed to the main and the shadow core. In this commit, we are splitting up the data and ECC parts into two different register file instances: - (1) This instance is driven by the main core and only operates on the 32-bit data words. The outputs (32-bit data words) are forwarded to the main and the shadow core. - (2) This instance is driven by the shadow core and only operates on the 7-bit ECC words. The 7-bit ECC output is combined with the delayed 32-bit data output of the (1) RF instance. The shadow core uses ECC checkers to check if data and ECC (a) match and (b) are not manipulated using FI. This helps us to save around 6 kGE of area. Signed-off-by: Pascal Nasahl <[email protected]>
1 parent 89ff318 commit e138d32

File tree

2 files changed

+235
-202
lines changed

2 files changed

+235
-202
lines changed

rtl/ibex_lockstep.sv

Lines changed: 168 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ module ibex_lockstep import ibex_pkg::*; #(
3939
parameter bit DummyInstructions = 1'b0,
4040
parameter bit RegFileECC = 1'b0,
4141
parameter int unsigned RegFileDataWidth = 32,
42+
parameter int unsigned RegFileDataEccWidth = 39,
43+
parameter regfile_e RegFile = RegFileFF,
4244
parameter bit MemECC = 1'b0,
4345
parameter int unsigned MemDataWidth = MemECC ? 32 + 7 : 32,
4446
parameter int unsigned DmBaseAddr = 32'h1A110000,
@@ -73,15 +75,8 @@ module ibex_lockstep import ibex_pkg::*; #(
7375
input logic [MemDataWidth-1:0] data_rdata_i,
7476
input logic data_err_i,
7577

76-
input logic dummy_instr_id_i,
77-
input logic dummy_instr_wb_i,
78-
input logic [4:0] rf_raddr_a_i,
79-
input logic [4:0] rf_raddr_b_i,
80-
input logic [4:0] rf_waddr_wb_i,
81-
input logic rf_we_wb_i,
82-
input logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc_i,
83-
input logic [RegFileDataWidth-1:0] rf_rdata_a_ecc_i,
84-
input logic [RegFileDataWidth-1:0] rf_rdata_b_ecc_i,
78+
input logic [RegFileDataWidth-1:0] rf_rdata_a_i,
79+
input logic [RegFileDataWidth-1:0] rf_rdata_b_i,
8580

8681
input logic [IC_NUM_WAYS-1:0] ic_tag_req_i,
8782
input logic ic_tag_write_i,
@@ -116,6 +111,8 @@ module ibex_lockstep import ibex_pkg::*; #(
116111
input logic scan_rst_ni
117112
);
118113

114+
import prim_secded_pkg::SecdedInv3932ZeroWord;
115+
119116
localparam int unsigned LockstepOffsetW = $clog2(LockstepOffset);
120117
// Core outputs are delayed for an extra cycle due to shadow output registers
121118
localparam int unsigned OutputsOffset = LockstepOffset + 1;
@@ -210,8 +207,8 @@ module ibex_lockstep import ibex_pkg::*; #(
210207
logic data_rvalid;
211208
logic [MemDataWidth-1:0] data_rdata;
212209
logic data_err;
213-
logic [RegFileDataWidth-1:0] rf_rdata_a_ecc;
214-
logic [RegFileDataWidth-1:0] rf_rdata_b_ecc;
210+
logic [RegFileDataWidth-1:0] rf_rdata_a;
211+
logic [RegFileDataWidth-1:0] rf_rdata_b;
215212
logic irq_software;
216213
logic irq_timer;
217214
logic irq_external;
@@ -237,8 +234,8 @@ module ibex_lockstep import ibex_pkg::*; #(
237234
assign shadow_inputs_in.data_rvalid = data_rvalid_i;
238235
assign shadow_inputs_in.data_rdata = data_rdata_i;
239236
assign shadow_inputs_in.data_err = data_err_i;
240-
assign shadow_inputs_in.rf_rdata_a_ecc = rf_rdata_a_ecc_i;
241-
assign shadow_inputs_in.rf_rdata_b_ecc = rf_rdata_b_ecc_i;
237+
assign shadow_inputs_in.rf_rdata_a = rf_rdata_a_i;
238+
assign shadow_inputs_in.rf_rdata_b = rf_rdata_b_i;
242239
assign shadow_inputs_in.irq_software = irq_software_i;
243240
assign shadow_inputs_in.irq_timer = irq_timer_i;
244241
assign shadow_inputs_in.irq_external = irq_external_i;
@@ -273,33 +270,26 @@ module ibex_lockstep import ibex_pkg::*; #(
273270
///////////////////
274271

275272
typedef struct packed {
276-
logic instr_req;
277-
logic [31:0] instr_addr;
278-
logic data_req;
279-
logic data_we;
280-
logic [3:0] data_be;
281-
logic [31:0] data_addr;
282-
logic [MemDataWidth-1:0] data_wdata;
283-
logic dummy_instr_id;
284-
logic dummy_instr_wb;
285-
logic [4:0] rf_raddr_a;
286-
logic [4:0] rf_raddr_b;
287-
logic [4:0] rf_waddr_wb;
288-
logic rf_we_wb;
289-
logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc;
290-
logic [IC_NUM_WAYS-1:0] ic_tag_req;
291-
logic ic_tag_write;
292-
logic [IC_INDEX_W-1:0] ic_tag_addr;
293-
logic [TagSizeECC-1:0] ic_tag_wdata;
294-
logic [IC_NUM_WAYS-1:0] ic_data_req;
295-
logic ic_data_write;
296-
logic [IC_INDEX_W-1:0] ic_data_addr;
297-
logic [LineSizeECC-1:0] ic_data_wdata;
298-
logic ic_scr_key_req;
299-
logic irq_pending;
300-
crash_dump_t crash_dump;
301-
logic double_fault_seen;
302-
ibex_mubi_t core_busy;
273+
logic instr_req;
274+
logic [31:0] instr_addr;
275+
logic data_req;
276+
logic data_we;
277+
logic [3:0] data_be;
278+
logic [31:0] data_addr;
279+
logic [MemDataWidth-1:0] data_wdata;
280+
logic [IC_NUM_WAYS-1:0] ic_tag_req;
281+
logic ic_tag_write;
282+
logic [IC_INDEX_W-1:0] ic_tag_addr;
283+
logic [TagSizeECC-1:0] ic_tag_wdata;
284+
logic [IC_NUM_WAYS-1:0] ic_data_req;
285+
logic ic_data_write;
286+
logic [IC_INDEX_W-1:0] ic_data_addr;
287+
logic [LineSizeECC-1:0] ic_data_wdata;
288+
logic ic_scr_key_req;
289+
logic irq_pending;
290+
crash_dump_t crash_dump;
291+
logic double_fault_seen;
292+
ibex_mubi_t core_busy;
303293
} delayed_outputs_t;
304294

305295
delayed_outputs_t [OutputsOffset-1:0] core_outputs_q;
@@ -314,13 +304,6 @@ module ibex_lockstep import ibex_pkg::*; #(
314304
assign core_outputs_in.data_be = data_be_i;
315305
assign core_outputs_in.data_addr = data_addr_i;
316306
assign core_outputs_in.data_wdata = data_wdata_i;
317-
assign core_outputs_in.dummy_instr_id = dummy_instr_id_i;
318-
assign core_outputs_in.dummy_instr_wb = dummy_instr_wb_i;
319-
assign core_outputs_in.rf_raddr_a = rf_raddr_a_i;
320-
assign core_outputs_in.rf_raddr_b = rf_raddr_b_i;
321-
assign core_outputs_in.rf_waddr_wb = rf_waddr_wb_i;
322-
assign core_outputs_in.rf_we_wb = rf_we_wb_i;
323-
assign core_outputs_in.rf_wdata_wb_ecc = rf_wdata_wb_ecc_i;
324307
assign core_outputs_in.ic_tag_req = ic_tag_req_i;
325308
assign core_outputs_in.ic_tag_write = ic_tag_write_i;
326309
assign core_outputs_in.ic_tag_addr = ic_tag_addr_i;
@@ -343,50 +326,65 @@ module ibex_lockstep import ibex_pkg::*; #(
343326
core_outputs_q[OutputsOffset-1] <= core_outputs_in;
344327
end
345328

329+
// The following outputs are generated by the shadow core and directly fed into the shadow core
330+
// register file. There is no need to compare those signals against the signals generated by the
331+
// main core in the lockstep comparison. A fault into one of those signals will cause a mismatch
332+
// in the main core and shadow core register file instances. As the outputs of both register
333+
// files are combined, the ECC checker inside the shadow core will detect the fault.
334+
logic [RegFileDataEccWidth-1:0] shadow_rf_wdata_wb_ecc;
335+
logic [4:0] shadow_rf_raddr_a;
336+
logic [4:0] shadow_rf_raddr_b;
337+
logic [4:0] shadow_rf_waddr_wb;
338+
logic shadow_rf_we_wb;
339+
logic shadow_dummy_instr_id;
340+
logic shadow_dummy_instr_wb;
341+
346342
///////////////////////////////
347343
// Shadow core instantiation //
348344
///////////////////////////////
349345

350346
logic shadow_alert_minor, shadow_alert_major_internal, shadow_alert_major_bus;
347+
logic [RegFileDataEccWidth - RegFileDataWidth - 1:0] shadow_rf_rdata_a_intg;
348+
logic [RegFileDataEccWidth - RegFileDataWidth - 1:0] shadow_rf_rdata_b_intg;
351349

352350
ibex_core #(
353-
.PMPEnable ( PMPEnable ),
354-
.PMPGranularity ( PMPGranularity ),
355-
.PMPNumRegions ( PMPNumRegions ),
356-
.PMPRstCfg ( PMPRstCfg ),
357-
.PMPRstAddr ( PMPRstAddr ),
358-
.PMPRstMsecCfg ( PMPRstMsecCfg ),
359-
.MHPMCounterNum ( MHPMCounterNum ),
360-
.MHPMCounterWidth ( MHPMCounterWidth ),
361-
.RV32E ( RV32E ),
362-
.RV32M ( RV32M ),
363-
.RV32B ( RV32B ),
364-
.RV32ZC ( RV32ZC ),
365-
.BranchTargetALU ( BranchTargetALU ),
366-
.ICache ( ICache ),
367-
.ICacheECC ( ICacheECC ),
368-
.BusSizeECC ( BusSizeECC ),
369-
.TagSizeECC ( TagSizeECC ),
370-
.LineSizeECC ( LineSizeECC ),
371-
.BranchPredictor ( BranchPredictor ),
372-
.DbgTriggerEn ( DbgTriggerEn ),
373-
.DbgHwBreakNum ( DbgHwBreakNum ),
374-
.WritebackStage ( WritebackStage ),
375-
.ResetAll ( ResetAll ),
376-
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
377-
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
378-
.SecureIbex ( SecureIbex ),
379-
.DummyInstructions ( DummyInstructions ),
380-
.RegFileECC ( RegFileECC ),
381-
.RegFileDataWidth ( RegFileDataWidth ),
382-
.MemECC ( MemECC ),
383-
.MemDataWidth ( MemDataWidth ),
384-
.DmBaseAddr ( DmBaseAddr ),
385-
.DmAddrMask ( DmAddrMask ),
386-
.DmHaltAddr ( DmHaltAddr ),
387-
.DmExceptionAddr ( DmExceptionAddr ),
388-
.CsrMvendorId ( CsrMvendorId ),
389-
.CsrMimpId ( CsrMimpId )
351+
.PMPEnable ( PMPEnable ),
352+
.PMPGranularity ( PMPGranularity ),
353+
.PMPNumRegions ( PMPNumRegions ),
354+
.PMPRstCfg ( PMPRstCfg ),
355+
.PMPRstAddr ( PMPRstAddr ),
356+
.PMPRstMsecCfg ( PMPRstMsecCfg ),
357+
.MHPMCounterNum ( MHPMCounterNum ),
358+
.MHPMCounterWidth ( MHPMCounterWidth ),
359+
.RV32E ( RV32E ),
360+
.RV32M ( RV32M ),
361+
.RV32B ( RV32B ),
362+
.RV32ZC ( RV32ZC ),
363+
.BranchTargetALU ( BranchTargetALU ),
364+
.ICache ( ICache ),
365+
.ICacheECC ( ICacheECC ),
366+
.BusSizeECC ( BusSizeECC ),
367+
.TagSizeECC ( TagSizeECC ),
368+
.LineSizeECC ( LineSizeECC ),
369+
.BranchPredictor ( BranchPredictor ),
370+
.DbgTriggerEn ( DbgTriggerEn ),
371+
.DbgHwBreakNum ( DbgHwBreakNum ),
372+
.WritebackStage ( WritebackStage ),
373+
.ResetAll ( ResetAll ),
374+
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
375+
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
376+
.SecureIbex ( SecureIbex ),
377+
.DummyInstructions ( DummyInstructions ),
378+
.RegFileECC ( RegFileECC ),
379+
.RegFileDataWidth ( RegFileDataEccWidth ),
380+
.MemECC ( MemECC ),
381+
.MemDataWidth ( MemDataWidth ),
382+
.DmBaseAddr ( DmBaseAddr ),
383+
.DmAddrMask ( DmAddrMask ),
384+
.DmHaltAddr ( DmHaltAddr ),
385+
.DmExceptionAddr ( DmExceptionAddr ),
386+
.CsrMvendorId ( CsrMvendorId ),
387+
.CsrMimpId ( CsrMimpId )
390388
) u_shadow_core (
391389
.clk_i (clk_i),
392390
.rst_ni (rst_shadow_n),
@@ -411,15 +409,15 @@ module ibex_lockstep import ibex_pkg::*; #(
411409
.data_rdata_i (shadow_inputs_q[0].data_rdata),
412410
.data_err_i (shadow_inputs_q[0].data_err),
413411

414-
.dummy_instr_id_o (shadow_outputs_d.dummy_instr_id),
415-
.dummy_instr_wb_o (shadow_outputs_d.dummy_instr_wb),
416-
.rf_raddr_a_o (shadow_outputs_d.rf_raddr_a),
417-
.rf_raddr_b_o (shadow_outputs_d.rf_raddr_b),
418-
.rf_waddr_wb_o (shadow_outputs_d.rf_waddr_wb),
419-
.rf_we_wb_o (shadow_outputs_d.rf_we_wb),
420-
.rf_wdata_wb_ecc_o (shadow_outputs_d.rf_wdata_wb_ecc),
421-
.rf_rdata_a_ecc_i (shadow_inputs_q[0].rf_rdata_a_ecc),
422-
.rf_rdata_b_ecc_i (shadow_inputs_q[0].rf_rdata_b_ecc),
412+
.dummy_instr_id_o (shadow_dummy_instr_id),
413+
.dummy_instr_wb_o (shadow_dummy_instr_wb),
414+
.rf_raddr_a_o (shadow_rf_raddr_a),
415+
.rf_raddr_b_o (shadow_rf_raddr_b),
416+
.rf_waddr_wb_o (shadow_rf_waddr_wb),
417+
.rf_we_wb_o (shadow_rf_we_wb),
418+
.rf_wdata_wb_ecc_o (shadow_rf_wdata_wb_ecc),
419+
.rf_rdata_a_ecc_i ({shadow_rf_rdata_a_intg, shadow_inputs_q[0].rf_rdata_a}),
420+
.rf_rdata_b_ecc_i ({shadow_rf_rdata_b_intg, shadow_inputs_q[0].rf_rdata_b}),
423421

424422
.ic_tag_req_o (shadow_outputs_d.ic_tag_req),
425423
.ic_tag_write_o (shadow_outputs_d.ic_tag_write),
@@ -498,6 +496,83 @@ module ibex_lockstep import ibex_pkg::*; #(
498496
shadow_outputs_q <= shadow_outputs_d;
499497
end
500498

499+
// The lower RegFileDataWidth bits (which are the data bits) are not fed into the shadow
500+
// register file as they are handled by the main register file.
501+
logic [RegFileDataWidth-1:0] unused_shadow_rf_wdata_wb_ecc;
502+
assign unused_shadow_rf_wdata_wb_ecc = shadow_rf_wdata_wb_ecc[RegFileDataWidth-1:0];
503+
504+
//////////////////////////
505+
// Shadow register file //
506+
//////////////////////////
507+
// SEC_CM: DATA_REG_SW.GLITCH_DETECT
508+
if (RegFile == RegFileFF) begin : gen_shadow_regfile_ff
509+
ibex_register_file_ff #(
510+
.RV32E (RV32E),
511+
.DataWidth (RegFileDataEccWidth - RegFileDataWidth),
512+
.DummyInstructions(DummyInstructions),
513+
.WordZeroVal (SecdedInv3932ZeroWord[RegFileDataEccWidth-1:RegFileDataWidth])
514+
) register_file_shadow_i (
515+
.clk_i (clk_i),
516+
.rst_ni (rst_shadow_n),
517+
518+
.test_en_i (test_en_i),
519+
.dummy_instr_id_i (shadow_dummy_instr_id),
520+
.dummy_instr_wb_i (shadow_dummy_instr_wb),
521+
522+
.raddr_a_i (shadow_rf_raddr_a),
523+
.rdata_a_o (shadow_rf_rdata_a_intg),
524+
.raddr_b_i (shadow_rf_raddr_b),
525+
.rdata_b_o (shadow_rf_rdata_b_intg),
526+
.waddr_a_i (shadow_rf_waddr_wb),
527+
.wdata_a_i (shadow_rf_wdata_wb_ecc[RegFileDataEccWidth-1:RegFileDataWidth]),
528+
.we_a_i (shadow_rf_we_wb)
529+
);
530+
end else if (RegFile == RegFileFPGA) begin : gen_regfile_fpga
531+
ibex_register_file_fpga #(
532+
.RV32E (RV32E),
533+
.DataWidth (RegFileDataEccWidth - RegFileDataWidth),
534+
.DummyInstructions(DummyInstructions),
535+
.WordZeroVal (SecdedInv3932ZeroWord[RegFileDataEccWidth-1:RegFileDataWidth])
536+
) register_file_shadow_i (
537+
.clk_i (clk_i),
538+
.rst_ni (rst_shadow_n),
539+
540+
.test_en_i (test_en_i),
541+
.dummy_instr_id_i (shadow_dummy_instr_id),
542+
.dummy_instr_wb_i (shadow_dummy_instr_wb),
543+
544+
.raddr_a_i (shadow_rf_raddr_a),
545+
.rdata_a_o (shadow_rf_rdata_a_intg),
546+
.raddr_b_i (shadow_rf_raddr_b),
547+
.rdata_b_o (shadow_rf_rdata_b_intg),
548+
.waddr_a_i (shadow_rf_waddr_wb),
549+
.wdata_a_i (shadow_rf_wdata_wb_ecc[RegFileDataEccWidth-1:RegFileDataWidth]),
550+
.we_a_i (shadow_rf_we_wb)
551+
);
552+
end else if (RegFile == RegFileLatch) begin : gen_regfile_latch
553+
ibex_register_file_latch #(
554+
.RV32E (RV32E),
555+
.DataWidth (RegFileDataEccWidth - RegFileDataWidth),
556+
.DummyInstructions(DummyInstructions),
557+
.WordZeroVal (SecdedInv3932ZeroWord[RegFileDataEccWidth-1:RegFileDataWidth])
558+
) register_file_shadow_i (
559+
.clk_i (clk_i),
560+
.rst_ni (rst_shadow_n),
561+
562+
.test_en_i (test_en_i),
563+
.dummy_instr_id_i (shadow_dummy_instr_id),
564+
.dummy_instr_wb_i (shadow_dummy_instr_wb),
565+
566+
.raddr_a_i (shadow_rf_raddr_a),
567+
.rdata_a_o (shadow_rf_rdata_a_intg),
568+
.raddr_b_i (shadow_rf_raddr_b),
569+
.rdata_b_o (shadow_rf_rdata_b_intg),
570+
.waddr_a_i (shadow_rf_waddr_wb),
571+
.wdata_a_i (shadow_rf_wdata_wb_ecc[RegFileDataEccWidth-1:RegFileDataWidth]),
572+
.we_a_i (shadow_rf_we_wb)
573+
);
574+
end
575+
501576
/////////////////////////
502577
// Compare the outputs //
503578
/////////////////////////

0 commit comments

Comments
 (0)