Skip to content

Commit 1d3978b

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 22f6ed2 commit 1d3978b

File tree

2 files changed

+236
-203
lines changed

2 files changed

+236
-203
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 = prim_util_pkg::vbits(LockstepOffset);
120117
// Core outputs are delayed for an extra cycle due to shadow output registers
121118
localparam int unsigned OutputsOffset = LockstepOffset + 1;
@@ -230,8 +227,8 @@ module ibex_lockstep import ibex_pkg::*; #(
230227
logic data_rvalid;
231228
logic [MemDataWidth-1:0] data_rdata;
232229
logic data_err;
233-
logic [RegFileDataWidth-1:0] rf_rdata_a_ecc;
234-
logic [RegFileDataWidth-1:0] rf_rdata_b_ecc;
230+
logic [RegFileDataWidth-1:0] rf_rdata_a;
231+
logic [RegFileDataWidth-1:0] rf_rdata_b;
235232
logic irq_software;
236233
logic irq_timer;
237234
logic irq_external;
@@ -310,8 +307,8 @@ module ibex_lockstep import ibex_pkg::*; #(
310307
assign shadow_inputs_in.data_rvalid = data_rvalid_i;
311308
assign shadow_inputs_in.data_rdata = data_rdata_i;
312309
assign shadow_inputs_in.data_err = data_err_i;
313-
assign shadow_inputs_in.rf_rdata_a_ecc = rf_rdata_a_ecc_i;
314-
assign shadow_inputs_in.rf_rdata_b_ecc = rf_rdata_b_ecc_i;
310+
assign shadow_inputs_in.rf_rdata_a = rf_rdata_a_i;
311+
assign shadow_inputs_in.rf_rdata_b = rf_rdata_b_i;
315312
assign shadow_inputs_in.irq_software = irq_software_i;
316313
assign shadow_inputs_in.irq_timer = irq_timer_i;
317314
assign shadow_inputs_in.irq_external = irq_external_i;
@@ -326,33 +323,26 @@ module ibex_lockstep import ibex_pkg::*; #(
326323
///////////////////
327324

328325
typedef struct packed {
329-
logic instr_req;
330-
logic [31:0] instr_addr;
331-
logic data_req;
332-
logic data_we;
333-
logic [3:0] data_be;
334-
logic [31:0] data_addr;
335-
logic [MemDataWidth-1:0] data_wdata;
336-
logic dummy_instr_id;
337-
logic dummy_instr_wb;
338-
logic [4:0] rf_raddr_a;
339-
logic [4:0] rf_raddr_b;
340-
logic [4:0] rf_waddr_wb;
341-
logic rf_we_wb;
342-
logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc;
343-
logic [IC_NUM_WAYS-1:0] ic_tag_req;
344-
logic ic_tag_write;
345-
logic [IC_INDEX_W-1:0] ic_tag_addr;
346-
logic [TagSizeECC-1:0] ic_tag_wdata;
347-
logic [IC_NUM_WAYS-1:0] ic_data_req;
348-
logic ic_data_write;
349-
logic [IC_INDEX_W-1:0] ic_data_addr;
350-
logic [LineSizeECC-1:0] ic_data_wdata;
351-
logic ic_scr_key_req;
352-
logic irq_pending;
353-
crash_dump_t crash_dump;
354-
logic double_fault_seen;
355-
ibex_mubi_t core_busy;
326+
logic instr_req;
327+
logic [31:0] instr_addr;
328+
logic data_req;
329+
logic data_we;
330+
logic [3:0] data_be;
331+
logic [31:0] data_addr;
332+
logic [MemDataWidth-1:0] data_wdata;
333+
logic [IC_NUM_WAYS-1:0] ic_tag_req;
334+
logic ic_tag_write;
335+
logic [IC_INDEX_W-1:0] ic_tag_addr;
336+
logic [TagSizeECC-1:0] ic_tag_wdata;
337+
logic [IC_NUM_WAYS-1:0] ic_data_req;
338+
logic ic_data_write;
339+
logic [IC_INDEX_W-1:0] ic_data_addr;
340+
logic [LineSizeECC-1:0] ic_data_wdata;
341+
logic ic_scr_key_req;
342+
logic irq_pending;
343+
crash_dump_t crash_dump;
344+
logic double_fault_seen;
345+
ibex_mubi_t core_busy;
356346
} delayed_outputs_t;
357347

358348
delayed_outputs_t [OutputsOffset-1:0] core_outputs_q;
@@ -367,13 +357,6 @@ module ibex_lockstep import ibex_pkg::*; #(
367357
assign core_outputs_in.data_be = data_be_i;
368358
assign core_outputs_in.data_addr = data_addr_i;
369359
assign core_outputs_in.data_wdata = data_wdata_i;
370-
assign core_outputs_in.dummy_instr_id = dummy_instr_id_i;
371-
assign core_outputs_in.dummy_instr_wb = dummy_instr_wb_i;
372-
assign core_outputs_in.rf_raddr_a = rf_raddr_a_i;
373-
assign core_outputs_in.rf_raddr_b = rf_raddr_b_i;
374-
assign core_outputs_in.rf_waddr_wb = rf_waddr_wb_i;
375-
assign core_outputs_in.rf_we_wb = rf_we_wb_i;
376-
assign core_outputs_in.rf_wdata_wb_ecc = rf_wdata_wb_ecc_i;
377360
assign core_outputs_in.ic_tag_req = ic_tag_req_i;
378361
assign core_outputs_in.ic_tag_write = ic_tag_write_i;
379362
assign core_outputs_in.ic_tag_addr = ic_tag_addr_i;
@@ -396,50 +379,65 @@ module ibex_lockstep import ibex_pkg::*; #(
396379
core_outputs_q[OutputsOffset-1] <= core_outputs_in;
397380
end
398381

382+
// The following outputs are generated by the shadow core and directly fed into the shadow core
383+
// register file. There is no need to compare those signals against the signals generated by the
384+
// main core in the lockstep comparison. A fault into one of those signals will cause a mismatch
385+
// in the main core and shadow core register file instances. As the outputs of both register
386+
// files are combined, the ECC checker inside the shadow core will detect the fault.
387+
logic [RegFileDataEccWidth-1:0] shadow_rf_wdata_wb_ecc;
388+
logic [4:0] shadow_rf_raddr_a;
389+
logic [4:0] shadow_rf_raddr_b;
390+
logic [4:0] shadow_rf_waddr_wb;
391+
logic shadow_rf_we_wb;
392+
logic shadow_dummy_instr_id;
393+
logic shadow_dummy_instr_wb;
394+
399395
///////////////////////////////
400396
// Shadow core instantiation //
401397
///////////////////////////////
402398

403399
logic shadow_alert_minor, shadow_alert_major_internal, shadow_alert_major_bus;
400+
logic [RegFileDataEccWidth - RegFileDataWidth - 1:0] shadow_rf_rdata_a_intg;
401+
logic [RegFileDataEccWidth - RegFileDataWidth - 1:0] shadow_rf_rdata_b_intg;
404402

405403
ibex_core #(
406-
.PMPEnable ( PMPEnable ),
407-
.PMPGranularity ( PMPGranularity ),
408-
.PMPNumRegions ( PMPNumRegions ),
409-
.PMPRstCfg ( PMPRstCfg ),
410-
.PMPRstAddr ( PMPRstAddr ),
411-
.PMPRstMsecCfg ( PMPRstMsecCfg ),
412-
.MHPMCounterNum ( MHPMCounterNum ),
413-
.MHPMCounterWidth ( MHPMCounterWidth ),
414-
.RV32E ( RV32E ),
415-
.RV32M ( RV32M ),
416-
.RV32B ( RV32B ),
417-
.RV32ZC ( RV32ZC ),
418-
.BranchTargetALU ( BranchTargetALU ),
419-
.ICache ( ICache ),
420-
.ICacheECC ( ICacheECC ),
421-
.BusSizeECC ( BusSizeECC ),
422-
.TagSizeECC ( TagSizeECC ),
423-
.LineSizeECC ( LineSizeECC ),
424-
.BranchPredictor ( BranchPredictor ),
425-
.DbgTriggerEn ( DbgTriggerEn ),
426-
.DbgHwBreakNum ( DbgHwBreakNum ),
427-
.WritebackStage ( WritebackStage ),
428-
.ResetAll ( ResetAll ),
429-
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
430-
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
431-
.SecureIbex ( SecureIbex ),
432-
.DummyInstructions ( DummyInstructions ),
433-
.RegFileECC ( RegFileECC ),
434-
.RegFileDataWidth ( RegFileDataWidth ),
435-
.MemECC ( MemECC ),
436-
.MemDataWidth ( MemDataWidth ),
437-
.DmBaseAddr ( DmBaseAddr ),
438-
.DmAddrMask ( DmAddrMask ),
439-
.DmHaltAddr ( DmHaltAddr ),
440-
.DmExceptionAddr ( DmExceptionAddr ),
441-
.CsrMvendorId ( CsrMvendorId ),
442-
.CsrMimpId ( CsrMimpId )
404+
.PMPEnable ( PMPEnable ),
405+
.PMPGranularity ( PMPGranularity ),
406+
.PMPNumRegions ( PMPNumRegions ),
407+
.PMPRstCfg ( PMPRstCfg ),
408+
.PMPRstAddr ( PMPRstAddr ),
409+
.PMPRstMsecCfg ( PMPRstMsecCfg ),
410+
.MHPMCounterNum ( MHPMCounterNum ),
411+
.MHPMCounterWidth ( MHPMCounterWidth ),
412+
.RV32E ( RV32E ),
413+
.RV32M ( RV32M ),
414+
.RV32B ( RV32B ),
415+
.RV32ZC ( RV32ZC ),
416+
.BranchTargetALU ( BranchTargetALU ),
417+
.ICache ( ICache ),
418+
.ICacheECC ( ICacheECC ),
419+
.BusSizeECC ( BusSizeECC ),
420+
.TagSizeECC ( TagSizeECC ),
421+
.LineSizeECC ( LineSizeECC ),
422+
.BranchPredictor ( BranchPredictor ),
423+
.DbgTriggerEn ( DbgTriggerEn ),
424+
.DbgHwBreakNum ( DbgHwBreakNum ),
425+
.WritebackStage ( WritebackStage ),
426+
.ResetAll ( ResetAll ),
427+
.RndCnstLfsrSeed ( RndCnstLfsrSeed ),
428+
.RndCnstLfsrPerm ( RndCnstLfsrPerm ),
429+
.SecureIbex ( SecureIbex ),
430+
.DummyInstructions ( DummyInstructions ),
431+
.RegFileECC ( RegFileECC ),
432+
.RegFileDataWidth ( RegFileDataEccWidth ),
433+
.MemECC ( MemECC ),
434+
.MemDataWidth ( MemDataWidth ),
435+
.DmBaseAddr ( DmBaseAddr ),
436+
.DmAddrMask ( DmAddrMask ),
437+
.DmHaltAddr ( DmHaltAddr ),
438+
.DmExceptionAddr ( DmExceptionAddr ),
439+
.CsrMvendorId ( CsrMvendorId ),
440+
.CsrMimpId ( CsrMimpId )
443441
) u_shadow_core (
444442
.clk_i (clk_i),
445443
.rst_ni (rst_shadow_n),
@@ -464,15 +462,15 @@ module ibex_lockstep import ibex_pkg::*; #(
464462
.data_rdata_i (shadow_inputs_q[0].data_rdata),
465463
.data_err_i (shadow_inputs_q[0].data_err),
466464

467-
.dummy_instr_id_o (shadow_outputs_d.dummy_instr_id),
468-
.dummy_instr_wb_o (shadow_outputs_d.dummy_instr_wb),
469-
.rf_raddr_a_o (shadow_outputs_d.rf_raddr_a),
470-
.rf_raddr_b_o (shadow_outputs_d.rf_raddr_b),
471-
.rf_waddr_wb_o (shadow_outputs_d.rf_waddr_wb),
472-
.rf_we_wb_o (shadow_outputs_d.rf_we_wb),
473-
.rf_wdata_wb_ecc_o (shadow_outputs_d.rf_wdata_wb_ecc),
474-
.rf_rdata_a_ecc_i (shadow_inputs_q[0].rf_rdata_a_ecc),
475-
.rf_rdata_b_ecc_i (shadow_inputs_q[0].rf_rdata_b_ecc),
465+
.dummy_instr_id_o (shadow_dummy_instr_id),
466+
.dummy_instr_wb_o (shadow_dummy_instr_wb),
467+
.rf_raddr_a_o (shadow_rf_raddr_a),
468+
.rf_raddr_b_o (shadow_rf_raddr_b),
469+
.rf_waddr_wb_o (shadow_rf_waddr_wb),
470+
.rf_we_wb_o (shadow_rf_we_wb),
471+
.rf_wdata_wb_ecc_o (shadow_rf_wdata_wb_ecc),
472+
.rf_rdata_a_ecc_i ({shadow_rf_rdata_a_intg, shadow_inputs_q[0].rf_rdata_a}),
473+
.rf_rdata_b_ecc_i ({shadow_rf_rdata_b_intg, shadow_inputs_q[0].rf_rdata_b}),
476474

477475
.ic_tag_req_o (shadow_outputs_d.ic_tag_req),
478476
.ic_tag_write_o (shadow_outputs_d.ic_tag_write),
@@ -551,6 +549,83 @@ module ibex_lockstep import ibex_pkg::*; #(
551549
shadow_outputs_q <= shadow_outputs_d;
552550
end
553551

552+
// The lower RegFileDataWidth bits (which are the data bits) are not fed into the shadow
553+
// register file as they are handled by the main register file.
554+
logic [RegFileDataWidth-1:0] unused_shadow_rf_wdata_wb_ecc;
555+
assign unused_shadow_rf_wdata_wb_ecc = shadow_rf_wdata_wb_ecc[RegFileDataWidth-1:0];
556+
557+
//////////////////////////
558+
// Shadow register file //
559+
//////////////////////////
560+
// SEC_CM: DATA_REG_SW.GLITCH_DETECT
561+
if (RegFile == RegFileFF) begin : gen_shadow_regfile_ff
562+
ibex_register_file_ff #(
563+
.RV32E (RV32E),
564+
.DataWidth (RegFileDataEccWidth - RegFileDataWidth),
565+
.DummyInstructions(DummyInstructions),
566+
.WordZeroVal (SecdedInv3932ZeroWord[RegFileDataEccWidth-1:RegFileDataWidth])
567+
) register_file_shadow_i (
568+
.clk_i (clk_i),
569+
.rst_ni (rst_shadow_n),
570+
571+
.test_en_i (test_en_i),
572+
.dummy_instr_id_i (shadow_dummy_instr_id),
573+
.dummy_instr_wb_i (shadow_dummy_instr_wb),
574+
575+
.raddr_a_i (shadow_rf_raddr_a),
576+
.rdata_a_o (shadow_rf_rdata_a_intg),
577+
.raddr_b_i (shadow_rf_raddr_b),
578+
.rdata_b_o (shadow_rf_rdata_b_intg),
579+
.waddr_a_i (shadow_rf_waddr_wb),
580+
.wdata_a_i (shadow_rf_wdata_wb_ecc[RegFileDataEccWidth-1:RegFileDataWidth]),
581+
.we_a_i (shadow_rf_we_wb)
582+
);
583+
end else if (RegFile == RegFileFPGA) begin : gen_regfile_fpga
584+
ibex_register_file_fpga #(
585+
.RV32E (RV32E),
586+
.DataWidth (RegFileDataEccWidth - RegFileDataWidth),
587+
.DummyInstructions(DummyInstructions),
588+
.WordZeroVal (SecdedInv3932ZeroWord[RegFileDataEccWidth-1:RegFileDataWidth])
589+
) register_file_shadow_i (
590+
.clk_i (clk_i),
591+
.rst_ni (rst_shadow_n),
592+
593+
.test_en_i (test_en_i),
594+
.dummy_instr_id_i (shadow_dummy_instr_id),
595+
.dummy_instr_wb_i (shadow_dummy_instr_wb),
596+
597+
.raddr_a_i (shadow_rf_raddr_a),
598+
.rdata_a_o (shadow_rf_rdata_a_intg),
599+
.raddr_b_i (shadow_rf_raddr_b),
600+
.rdata_b_o (shadow_rf_rdata_b_intg),
601+
.waddr_a_i (shadow_rf_waddr_wb),
602+
.wdata_a_i (shadow_rf_wdata_wb_ecc[RegFileDataEccWidth-1:RegFileDataWidth]),
603+
.we_a_i (shadow_rf_we_wb)
604+
);
605+
end else if (RegFile == RegFileLatch) begin : gen_regfile_latch
606+
ibex_register_file_latch #(
607+
.RV32E (RV32E),
608+
.DataWidth (RegFileDataEccWidth - RegFileDataWidth),
609+
.DummyInstructions(DummyInstructions),
610+
.WordZeroVal (SecdedInv3932ZeroWord[RegFileDataEccWidth-1:RegFileDataWidth])
611+
) register_file_shadow_i (
612+
.clk_i (clk_i),
613+
.rst_ni (rst_shadow_n),
614+
615+
.test_en_i (test_en_i),
616+
.dummy_instr_id_i (shadow_dummy_instr_id),
617+
.dummy_instr_wb_i (shadow_dummy_instr_wb),
618+
619+
.raddr_a_i (shadow_rf_raddr_a),
620+
.rdata_a_o (shadow_rf_rdata_a_intg),
621+
.raddr_b_i (shadow_rf_raddr_b),
622+
.rdata_b_o (shadow_rf_rdata_b_intg),
623+
.waddr_a_i (shadow_rf_waddr_wb),
624+
.wdata_a_i (shadow_rf_wdata_wb_ecc[RegFileDataEccWidth-1:RegFileDataWidth]),
625+
.we_a_i (shadow_rf_we_wb)
626+
);
627+
end
628+
554629
/////////////////////////
555630
// Compare the outputs //
556631
/////////////////////////

0 commit comments

Comments
 (0)