diff --git a/Bender.yml b/Bender.yml
index 14bfe737..53568b8a 100644
--- a/Bender.yml
+++ b/Bender.yml
@@ -17,6 +17,19 @@ sources:
- rtl/ODRG_unit/odrg_manager_reg_pkg.sv
- rtl/ecc_wrap/ecc_manager_reg_pkg.sv
- rtl/pulpissimo_tcls/tcls_manager_reg_pkg.sv
+ - rtl/lowrisc_ecc/prim_secded_13_8_cor.sv
+ - rtl/lowrisc_ecc/prim_secded_13_8_dec.sv
+ - rtl/lowrisc_ecc/prim_secded_13_8_enc.sv
+ - rtl/lowrisc_ecc/prim_secded_22_16_cor.sv
+ - rtl/lowrisc_ecc/prim_secded_22_16_dec.sv
+ - rtl/lowrisc_ecc/prim_secded_22_16_enc.sv
+ - rtl/lowrisc_ecc/prim_secded_39_32_cor.sv
+ - rtl/lowrisc_ecc/prim_secded_39_32_dec.sv
+ - rtl/lowrisc_ecc/prim_secded_39_32_enc.sv
+ - rtl/lowrisc_ecc/prim_secded_72_64_cor.sv
+ - rtl/lowrisc_ecc/prim_secded_72_64_dec.sv
+ - rtl/lowrisc_ecc/prim_secded_72_64_enc.sv
+ - rtl/lowrisc_ecc/prim_secded_pkg.sv
- rtl/ODRG_unit/triple_core_barrier.sv
- rtl/hsiao_ecc/hsiao_ecc_pkg.sv
- rtl/hsiao_ecc/hsiao_ecc_enc.sv
@@ -24,11 +37,13 @@ sources:
- rtl/hsiao_ecc/hsiao_ecc_cor.sv
- rtl/TMR_voter.sv
- rtl/TMR_word_voter.sv
+ - rtl/HMR/resp_suppress.sv
# Level 1
- rtl/ODRG_unit/odrg_manager_reg_top.sv
- rtl/ecc_wrap/ecc_manager_reg_top.sv
- rtl/pulpissimo_tcls/tcls_manager_reg_top.sv
- rtl/ecc_wrap/ecc_scrubber.sv
+ - rtl/ecc_wrap/ecc_scrubber_out.sv
- target: any(deprecated, axi_ecc, hci_ecc, pulp_ecc, test)
files:
@@ -92,6 +107,30 @@ sources:
- test/tb_tmr_word_voter.sv
- test/tb_bitwise_tmr_voter.sv
+ - files:
+ - rtl/HMR/rapid_recovery_pkg.sv
+ - rtl/HMR/recovery_csr.sv
+ - rtl/HMR/recovery_pc.sv
+ - rtl/HMR/recovery_rf.sv
+ - rtl/HMR/rapid_recovery_unit.sv
+ - rtl/HMR/DMR_checker.sv
+ - rtl/HMR/DMR_CSR_checker.sv
+ - rtl/HMR/DMR_address_generator.sv
+ # - rtl/HMR/DMR_controller.sv
+ - rtl/HMR/hmr_rapid_recovery_ctrl.sv
+ - rtl/HMR/hmr_registers_reg_pkg.sv
+ - rtl/HMR/hmr_core_regs_reg_pkg.sv
+ - rtl/HMR/hmr_dmr_regs_reg_pkg.sv
+ - rtl/HMR/hmr_tmr_regs_reg_pkg.sv
+ - rtl/HMR/hmr_registers_reg_top.sv
+ - rtl/HMR/hmr_core_regs_reg_top.sv
+ - rtl/HMR/hmr_dmr_regs_reg_top.sv
+ - rtl/HMR/hmr_dmr_ctrl.sv
+ - rtl/HMR/hmr_tmr_regs_reg_top.sv
+ - rtl/HMR/hmr_tmr_ctrl.sv
+ - rtl/HMR/HMR_wrap.sv
+ - rtl/HMR/hmr_unit.sv
+
vendor_package:
- name: lowrisc_opentitan
target_dir: "util/lowrisc_opentitan"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 79f119b7..074d5acc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,7 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Replace vendor.py script with bender vendor for ECC modules
- Update `ecc_manager` for configurability
-- Update secded testbench to use correctors and fix error injection
## 0.5.1 - 2023-04-12
### Added
@@ -29,11 +28,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Expose additional error logging signals
- Add scrubber to ECC SRAM wrap
- Add testing signals for tapeout
+- Add secded ECC corrector
### Changed
- Expose `ecc_sram` ecc error signals
- Rename cTCLS to ODRG
- Hide bus ecc behind bender targets, remove related dependencies
+- Update secded testbench to use correctors and fix error injection
## 0.4.0 - 2022-03-31
diff --git a/Makefile b/Makefile
index 64af21f9..afeed9ac 100644
--- a/Makefile
+++ b/Makefile
@@ -22,12 +22,60 @@ REG_TOOL = $(REG_PATH)/vendor/lowrisc_opentitan/util/regtool.py
HJSON_ODRG = rtl/ODRG_unit/ODRG_unit.hjson
HJSON_TCLS = rtl/pulpissimo_tcls/TCLS_unit.hjson
+HJSON_HMR = rtl/HMR/HMR_regs.hjson
+HJSON_HMR_core = rtl/HMR/HMR_core_regs.hjson
+HJSON_HMR_dmr = rtl/HMR/HMR_dmr_regs.hjson
+HJSON_HMR_tmr = rtl/HMR/HMR_tmr_regs.hjson
HJSON_ECC = rtl/ecc_wrap/ecc_sram_wrapper.hjson
TARGET_DIR_ODRG = rtl/ODRG_unit
TARGET_DIR_TCLS = rtl/pulpissimo_tcls
+TARGET_DIR_HMR = rtl/HMR
TARGET_DIR_ECC = rtl/ecc_wrap
+define HMR_H_HEADER_STRING
+/*
+ * Copyright (C) 2023 ETH Zurich and University of Bologna
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ARCHI_HMR_HMR_V1_H__
+#define __ARCHI_HMR_HMR_V1_H__
+
+#define HMR_IN_INTERLEAVED 1
+
+#define HMR_TOP_OFFSET 0x000
+#define HMR_CORE_OFFSET 0x100
+#define HMR_DMR_OFFSET 0x200
+#define HMR_TMR_OFFSET 0x300
+
+#define HMR_CORE_INCREMENT 0x010
+#define HMR_CORE_SLL 0x004
+#define HMR_DMR_INCREMENT 0x010
+#define HMR_DMR_SLL 0x004
+#define HMR_TMR_INCREMENT 0x010
+#define HMR_TMR_SLL 0x004
+\n
+endef
+define HMR_H_FINAL_STRING
+\n\n
+#endif // __ARCHI_HMR_HMR_V1_H__
+
+endef
+export HMR_H_HEADER_STRING
+export HMR_H_FINAL_STRING
+
.PHONY: gen_ODRG gen_TCLS gen_ecc_registers gen_ECC
gen_ODRG:
python $(REG_TOOL) $(HJSON_ODRG) -t $(TARGET_DIR_ODRG) -r
@@ -39,6 +87,24 @@ gen_TCLS:
python $(REG_TOOL) $(HJSON_TCLS) -d > $(TARGET_DIR_TCLS)/doc.md
python $(REG_TOOL) $(HJSON_TCLS) -D > $(TARGET_DIR_TCLS)/TCLS.h
+gen_HMR:
+ python $(REG_TOOL) $(HJSON_HMR) -t $(TARGET_DIR_HMR) -r
+ python $(REG_TOOL) $(HJSON_HMR) -d > $(TARGET_DIR_HMR)/doc.html
+ python $(REG_TOOL) $(HJSON_HMR) --doc > $(TARGET_DIR_HMR)/doc.md
+ python $(REG_TOOL) $(HJSON_HMR_core) -t $(TARGET_DIR_HMR) -r
+ python $(REG_TOOL) $(HJSON_HMR_dmr) -t $(TARGET_DIR_HMR) -r
+ python $(REG_TOOL) $(HJSON_HMR_tmr) -t $(TARGET_DIR_HMR) -r
+
+ @printf "$$HMR_H_HEADER_STRING" > $(TARGET_DIR_HMR)/hmr_v1.h
+ python $(REG_TOOL) $(HJSON_HMR) -D >> $(TARGET_DIR_HMR)/hmr_v1.h
+ @printf "\n\n" >> $(TARGET_DIR_HMR)/hmr_v1.h
+ python $(REG_TOOL) $(HJSON_HMR_core) -D >> $(TARGET_DIR_HMR)/hmr_v1.h
+ @printf "\n\n" >> $(TARGET_DIR_HMR)/hmr_v1.h
+ python $(REG_TOOL) $(HJSON_HMR_dmr) -D >> $(TARGET_DIR_HMR)/hmr_v1.h
+ @printf "\n\n" >> $(TARGET_DIR_HMR)/hmr_v1.h
+ python $(REG_TOOL) $(HJSON_HMR_tmr) -D >> $(TARGET_DIR_HMR)/hmr_v1.h
+ @printf "$$HMR_H_FINAL_STRING" >> $(TARGET_DIR_HMR)/hmr_v1.h
+
gen_ecc_registers:
python $(REG_TOOL) $(HJSON_ECC) -t $(TARGET_DIR_ECC) -r
python $(REG_TOOL) $(HJSON_ECC) -d > $(TARGET_DIR_ECC)/doc.md
diff --git a/rtl/HMR/DMR_CSR_checker.sv b/rtl/HMR/DMR_CSR_checker.sv
new file mode 100644
index 00000000..c883b18d
--- /dev/null
+++ b/rtl/HMR/DMR_CSR_checker.sv
@@ -0,0 +1,51 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * CS Registers Checker
+ *
+ */
+
+module DMR_CSR_checker
+ import rapid_recovery_pkg::*;
+(
+ input csrs_intf_t csr_a_i,
+ input csrs_intf_t csr_b_i,
+ output csrs_intf_t check_o,
+ output logic error_o
+);
+
+logic compare_mstatus;
+logic compare_mie;
+logic compare_mtvec;
+logic compare_mscratch;
+logic compare_mip;
+logic compare_mepc;
+logic compare_mcause;
+logic error;
+
+assign compare_mstatus = |(csr_a_i.csr_mstatus ^ csr_b_i.csr_mstatus);
+assign compare_mie = |(csr_a_i.csr_mie ^ csr_b_i.csr_mie);
+assign compare_mtvec = |(csr_a_i.csr_mtvec ^ csr_b_i.csr_mtvec);
+assign compare_mscratch = |(csr_a_i.csr_mscratch ^ csr_b_i.csr_mscratch);
+assign compare_mip = |(csr_a_i.csr_mip ^ csr_b_i.csr_mip);
+assign compare_mepc = |(csr_a_i.csr_mepc ^ csr_b_i.csr_mepc);
+assign compare_mcause = |(csr_a_i.csr_mcause ^ csr_b_i.csr_mcause);
+
+assign error = compare_mstatus |
+ compare_mie |
+ compare_mtvec |
+ compare_mscratch |
+ compare_mip |
+ compare_mepc |
+ compare_mcause;
+assign check_o = (error) ? csr_a_i : '0;
+assign error_o = error;
+
+endmodule : DMR_CSR_checker
diff --git a/rtl/HMR/DMR_address_generator.sv b/rtl/HMR/DMR_address_generator.sv
new file mode 100644
index 00000000..e832de28
--- /dev/null
+++ b/rtl/HMR/DMR_address_generator.sv
@@ -0,0 +1,71 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * Dual Modular Address Generator
+ * Generates addresses for RF refill
+ *
+ */
+
+module DMR_address_generator #(
+ parameter AddrWidth = 5
+)(
+ input logic clk_i ,
+ input logic rst_ni ,
+ input logic clear_i ,
+ input logic enable_i ,
+ output logic done_o ,
+ output logic fatal_o ,
+ output logic [AddrWidth-1:0] address_o
+);
+
+localparam int unsigned NumAddr = 2 ** (AddrWidth - 1);
+localparam int unsigned NumVotingSignals = 3;
+localparam int unsigned NumTMRResults = 1;
+localparam int unsigned ArrayWidth = NumVotingSignals + NumTMRResults;
+
+logic addr_count_err;
+logic [NumVotingSignals-1:0] addr_count_rst;
+logic [ArrayWidth-1:0][AddrWidth-1:0] addr_count;
+
+generate
+ for (genvar i = 0; i < NumVotingSignals; i++) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin : address_generator_counter
+ if (~rst_ni)
+ addr_count [i] <= '1;
+ else begin
+ if (clear_i || addr_count_rst [i])
+ addr_count [i] <= '1;
+ else if (enable_i)
+ addr_count [i] <= addr_count [i] + 1;
+ else
+ addr_count [i] <= addr_count [i];
+ end
+ end
+ assign addr_count_rst [i] = ( addr_count [i] == NumAddr/2 - 1) ? 1'b1 : 1'b0;
+ end
+endgenerate
+
+bitwise_TMR_voter #(
+ .DataWidth ( AddrWidth ),
+ .VoterType ( 0 )
+) address_counter_voter (
+ .a_i ( addr_count [0] ),
+ .b_i ( addr_count [1] ),
+ .c_i ( addr_count [2] ),
+ .majority_o ( addr_count [3] ),
+ .error_o ( addr_count_err ),
+ .error_cba_o ( /* ... */ )
+);
+
+assign address_o = addr_count [3]; // Result of TMR address voter
+assign fatal_o = addr_count_err; // Error from one of the two TMR voters
+assign done_o = |addr_count_rst;
+
+endmodule : DMR_address_generator
diff --git a/rtl/HMR/DMR_checker.sv b/rtl/HMR/DMR_checker.sv
new file mode 100644
index 00000000..ec4d9ceb
--- /dev/null
+++ b/rtl/HMR/DMR_checker.sv
@@ -0,0 +1,114 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * Dual Modular Redundancy Checker
+ * Compares the outputs generated by two IPs and returns error signals
+ * in case of mismatch
+ *
+ */
+
+module DMR_checker #(
+ parameter type check_bus_t = logic,
+ parameter int unsigned Pipeline = 0,
+ parameter bit AxiBus = 1'b0,
+ parameter bit AxiHasAce = 1'b0
+)(
+ input logic clk_i,
+ input logic rst_ni,
+ input check_bus_t inp_a_i,
+ input check_bus_t inp_b_i,
+ output check_bus_t check_o,
+ output logic error_o
+);
+
+check_bus_t compare;
+check_bus_t inp_q;
+logic error;
+
+if (AxiBus == 1) begin: gen_axi_checker
+ logic error_aw, error_w, error_ar, error_r, error_b, error_ac, error_cr, error_cd;
+ if (Pipeline) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin
+ if (~rst_ni) begin
+ compare <= '0;
+ inp_q <= '0;
+ end else begin
+ compare.aw <= inp_a_i.aw ^ inp_b_i.aw;
+ compare.aw_valid <= inp_a_i.aw_valid ^ inp_b_i.aw_valid;
+ compare.w <= inp_a_i.w ^ inp_b_i.w;
+ compare.w_valid <= inp_a_i.w_valid ^ inp_b_i.w_valid;
+ compare.ar <= inp_a_i.ar ^ inp_b_i.ar;
+ compare.ar_valid <= inp_a_i.ar_valid ^ inp_b_i.ar_valid;
+ compare.r_ready <= inp_a_i.r_ready ^ inp_b_i.r_ready;
+ compare.b_ready <= inp_a_i.b_ready ^ inp_b_i.b_ready;
+ if (AxiHasAce) begin
+ compare.ac_ready <= inp_a_i.ac_ready ^ inp_b_i.ac_ready;
+ compare.cr_valid <= inp_a_i.cr_valid ^ inp_b_i.cr_valid;
+ compare.cr_resp <= inp_a_i.cr_resp ^ inp_b_i.cr_resp;
+ compare.cd_valid <= inp_a_i.cd_valid ^ inp_b_i.cd_valid;
+ compare.cd <= inp_a_i.cd ^ inp_b_i.cd;
+ end
+ inp_q <= inp_a_i;
+ end
+ end
+ end else begin
+ assign compare.aw = inp_a_i.aw ^ inp_b_i.aw;
+ assign compare.aw_valid = inp_a_i.aw_valid ^ inp_b_i.aw_valid;
+ assign compare.w = inp_a_i.w ^ inp_b_i.w;
+ assign compare.w_valid = inp_a_i.w_valid ^ inp_b_i.w_valid;
+ assign compare.ar = inp_a_i.ar ^ inp_b_i.ar;
+ assign compare.ar_valid = inp_a_i.ar_valid ^ inp_b_i.ar_valid;
+ assign compare.r_ready = inp_a_i.r_ready ^ inp_b_i.r_ready;
+ assign compare.b_ready = inp_a_i.b_ready ^ inp_b_i.b_ready;
+ if (AxiHasAce) begin
+ assign compare.ac_ready = inp_a_i.ac_ready ^ inp_b_i.ac_ready;
+ assign compare.cr_valid = inp_a_i.cr_valid ^ inp_b_i.cr_valid;
+ assign compare.cr_resp = inp_a_i.cr_resp ^ inp_b_i.cr_resp;
+ assign compare.cd_valid = inp_a_i.cd_valid ^ inp_b_i.cd_valid;
+ assign compare.cd = inp_a_i.cd ^ inp_b_i.cd;
+ end
+ assign inp_q = inp_a_i;
+ end
+ assign error_aw = (|compare.aw) | compare.aw_valid;
+ assign error_w = (|compare.w) | compare.w_valid;
+ assign error_ar = (|compare.ar) | compare.ar_valid;
+ assign error_r = compare.r_ready;
+ assign error_b = compare.b_ready;
+ if (AxiHasAce) begin
+ assign error_ac = compare.ac_ready;
+ assign error_cr = (|compare.cr_resp) | compare.cr_valid;
+ assign error_cd = (|compare.cd) | compare.cd_valid;
+ end else begin
+ assign error_ac = '0;
+ assign error_cr = '0;
+ assign error_cd = '0;
+ end
+ assign error = error_aw | error_w | error_ar | error_r | error_b | error_ac | error_cr | error_cd;
+end else begin: gen_generic_checker
+ if (Pipeline) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin
+ if (~rst_ni) begin
+ compare <= '0;
+ inp_q <= '0;
+ end else begin
+ compare <= inp_a_i ^ inp_b_i;
+ inp_q <= inp_a_i;
+ end
+ end
+ end else begin
+ assign compare = inp_a_i ^ inp_b_i;
+ assign inp_q = inp_a_i;
+ end
+ assign error = |compare;
+end
+assign check_o = (error) ? '0 : inp_q;
+assign error_o = error;
+
+endmodule : DMR_checker
diff --git a/rtl/HMR/DMR_controller.sv b/rtl/HMR/DMR_controller.sv
new file mode 100644
index 00000000..9272a769
--- /dev/null
+++ b/rtl/HMR/DMR_controller.sv
@@ -0,0 +1,368 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * Dual Modular Redundancy Controller
+ * Handles the occurrence of errors and starts recovery routine
+ *
+ */
+
+module DMR_controller
+ import rapid_recovery_pkg::*;
+#(
+ parameter int unsigned NumCores = 0,
+ parameter bit DMRFixed = 1'b0,
+ parameter bit RapidRecovery = 1'b0,
+ parameter int unsigned RFAddrWidth = 6,
+ localparam int unsigned NumDMRGroups = NumCores/2,
+ localparam int unsigned NumDMRCores = NumDMRGroups * 2,
+ localparam int unsigned NumDMRLeftover = NumCores - NumDMRCores,
+ localparam int unsigned NumSysCores = DMRFixed ? NumDMRCores : NumCores
+)(
+ input logic clk_i ,
+ input logic rst_ni,
+ input logic [NumDMRGroups-1:0] dmr_rf_checker_error_port_a_i,
+ input logic [NumDMRGroups-1:0] dmr_rf_checker_error_port_b_i,
+ input logic [NumDMRGroups-1:0] dmr_core_checker_error_main_i,
+ input logic [NumDMRGroups-1:0] dmr_core_checker_error_data_i,
+ input regfile_write_t [NumDMRGroups-1:0] backup_regfile_write_i,
+ output regfile_write_t [NumDMRGroups-1:0] core_recovery_regfile_wport_o,
+ output logic [NumDMRGroups-1:0] regfile_readback_o,
+ output regfile_raddr_t [NumDMRGroups-1:0] regfile_raddr_o,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_pc_read_enable_o,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_pc_write_enable_o,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_core_debug_req_o,
+ input logic [NumDMRGroups-1:0] dmr_ctrl_core_debug_rsp_i,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_core_instr_lock_o,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_core_setback_o,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_core_recover_o,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_core_debug_resume_o,
+ output logic [NumDMRGroups-1:0] dmr_ctrl_core_clk_en_o
+);
+
+/********************************************************
+******************** Recovery Routine *******************
+*********************************************************/
+/************************
+ * Signals Declarations *
+ ************************/
+logic clear,
+ routine_start;
+logic core_instr_lock_rst,
+ core_recover_rst,
+ pc_write_enable_rst;
+logic addr_gen_start,
+ addr_gen_error,
+ addr_gen_done;
+
+logic restore_pc_cycles_d,
+ restore_pc_cycles_q,
+ restore_pc_cycles_rst;
+
+logic [RFAddrWidth-1:0] addr_gen_res;
+
+logic [NumDMRGroups-1:0] dmr_ctrl_core_setback_out ,
+ dmr_ctrl_core_debug_rsp_in ,
+ dmr_ctrl_core_clk_en_out,
+ dmr_ctrl_core_debug_req_out,
+ dmr_ctrl_pc_read_enable_out,
+ dmr_ctrl_pc_write_enable_d,
+ dmr_ctrl_pc_write_enable_q,
+ dmr_ctrl_core_recover_d,
+ dmr_ctrl_core_recover_q,
+ dmr_ctrl_core_instr_lock_d,
+ dmr_ctrl_core_instr_lock_q,
+ dmr_ctrl_core_clk_en_d,
+ dmr_ctrl_core_clk_en_q;
+
+recovery_routine_state_e current, next;
+logic [$clog2(NumDMRGroups)-1:0] error_index_d,
+ error_index_q;
+/******************
+ * Output Assigns *
+ ******************/
+for (genvar i = 0; i < NumDMRGroups; i++) begin
+ assign dmr_ctrl_core_setback_o [i] = dmr_ctrl_core_setback_out [i];
+ assign dmr_ctrl_core_clk_en_o [i] = dmr_ctrl_core_clk_en_out [i];
+ assign dmr_ctrl_pc_read_enable_o [i] = dmr_ctrl_pc_read_enable_out [i];
+ assign dmr_ctrl_pc_write_enable_o [i] = dmr_ctrl_pc_write_enable_q [i];
+ assign dmr_ctrl_core_instr_lock_o [i] = dmr_ctrl_core_instr_lock_q [i];
+ assign dmr_ctrl_core_debug_req_o [i] = dmr_ctrl_core_debug_req_out [i];
+ assign dmr_ctrl_core_recover_o [i] = dmr_ctrl_core_recover_q [i];
+ assign dmr_ctrl_core_debug_rsp_in [i] = dmr_ctrl_core_debug_rsp_i [i];
+ assign regfile_readback_o [i] = '0;
+ assign regfile_raddr_o [i] = '0;
+end
+
+/**************
+ * Comb logic *
+ **************/
+
+/*
+ * Error index identifier.
+ * Identifies the index of the group that is faulty.
+ */
+always_comb begin
+ error_index_d = error_index_q;
+ for (int i = 0; i < NumDMRGroups; i++) begin
+ if (dmr_rf_checker_error_port_a_i [i] ||
+ dmr_rf_checker_error_port_b_i [i] ||
+ dmr_core_checker_error_main_i [i] ||
+ dmr_core_checker_error_data_i [i] )
+ error_index_d = i;
+ end
+end
+
+/*
+ * Routine start signal.
+ * Checks if there are any errors from external checkers to start the FSM Recovery Routine.
+ */
+assign routine_start = (|dmr_rf_checker_error_port_a_i) |
+ (|dmr_rf_checker_error_port_a_i) |
+ (|dmr_core_checker_error_main_i) |
+ (|dmr_core_checker_error_data_i) ;
+/************
+* Registers *
+*************/
+
+/*
+ * Error index register.
+ * If the controller receives an error from one of the input NumDMRGroups,
+ * this register saves the index of the faulty input group.
+ */
+always_ff @(posedge clk_i, negedge rst_ni) begin : error_index_register
+ if (~rst_ni)
+ error_index_q <= '0;
+ else begin
+ if (clear)
+ error_index_q <= '0;
+ else
+ error_index_q <= error_index_d;
+ end
+end
+
+/*
+ * Instruction lock registers.
+ * These registers prevent PULP obi adapter to propagate
+ * inexistent instruction requests towards iCache while the cores are in debug mode (halted).
+ */
+generate
+ for (genvar i = 0; i < NumDMRGroups; i++) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin : instruction_lock_registers
+ if (~rst_ni) begin
+ dmr_ctrl_core_instr_lock_q [i] <= 1'b0;
+ end else begin
+ if (clear || core_instr_lock_rst) begin
+ dmr_ctrl_core_instr_lock_q [i] <= 1'b0;
+ end else
+ dmr_ctrl_core_instr_lock_q [i] <= dmr_ctrl_core_instr_lock_d [i];
+ end
+ end
+ end
+endgenerate
+
+/*
+ * Core clock enable.
+ * Clock gate the cores that do not need to recover during the recovery routine.
+ */
+generate
+ for (genvar i = 0; i < NumDMRGroups; i++) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin : core_clock_enable
+ if (~rst_ni) begin
+ dmr_ctrl_core_clk_en_q [i] <= 1'b1;
+ end else begin
+ if (clear) begin
+ dmr_ctrl_core_clk_en_q [i] <= 1'b1;
+ end else
+ dmr_ctrl_core_clk_en_q [i] <= dmr_ctrl_core_clk_en_d [i];
+ end
+ end
+ end
+endgenerate
+
+/*
+ * Core Recover Registers.
+ * These registers raise the recover signal towards the cores to
+ * allow their register files to be reloaded with the RRF content.
+ */
+generate
+ for (genvar i = 0; i < NumDMRGroups; i++) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin : core_recover_registers
+ if (~rst_ni) begin
+ dmr_ctrl_core_recover_q [i] <= 1'b0;
+ end else begin
+ if (clear || core_recover_rst) begin
+ dmr_ctrl_core_recover_q [i] <= 1'b0;
+ end else
+ dmr_ctrl_core_recover_q [i] <= dmr_ctrl_core_recover_d [i];
+ end
+ end
+ end
+endgenerate
+
+/*
+ * Program Counter Write Enable Register.
+ * During a recovery routine, this register blocks the Recovery PC
+ * from sampling new values from the cores.
+ */
+generate
+ for (genvar i = 0; i < NumDMRGroups; i++) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin : program_counter_write_enable
+ if (~rst_ni) begin
+ dmr_ctrl_pc_write_enable_q [i] <= 1'b1;
+ end else begin
+ if (clear || pc_write_enable_rst) begin
+ dmr_ctrl_pc_write_enable_q [i] <= 1'b1;
+ end else
+ dmr_ctrl_pc_write_enable_q [i] <= dmr_ctrl_pc_write_enable_d [i];
+ end
+ end
+ end
+endgenerate
+
+/*
+ * Program Counter Restore Counter.
+ * Counter that keeps the Recovery Routine FSM in the RECOVERY_PC state
+ * for two cycles to make sure that the PC state is safely restored.
+ */
+always_ff @(posedge clk_i, negedge rst_ni) begin : pc_restore_counter
+ if (~rst_ni)
+ restore_pc_cycles_q <= '0;
+ else begin
+ if (clear || restore_pc_cycles_rst)
+ restore_pc_cycles_q <= '0;
+ else
+ restore_pc_cycles_q <= restore_pc_cycles_d;
+ end
+end
+
+/***********************
+* RF Address Generator *
+************************/
+DMR_address_generator #(
+ .AddrWidth ( RFAddrWidth )
+) RF_address_generator (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .clear_i ( clear ),
+ .enable_i ( addr_gen_start ),
+ .done_o ( addr_gen_done ),
+ .fatal_o ( addr_gen_error ),
+ .address_o ( addr_gen_res )
+);
+
+/* Binding recovery signals towards RRF and cores */
+always_comb begin : RF_ports_binding
+ core_recovery_regfile_wport_o = '0;
+ for (int i = 0; i < NumDMRGroups; i++) begin
+ if (i == error_index_q) begin
+ core_recovery_regfile_wport_o[i].we_a = (addr_gen_start) ? 1'b1 : 1'b0;
+ core_recovery_regfile_wport_o[i].waddr_a = addr_gen_res;
+ core_recovery_regfile_wport_o[i].we_b = (addr_gen_start) ? 1'b1 : 1'b0;
+ core_recovery_regfile_wport_o[i].waddr_b = 5'd16 + addr_gen_res;
+ end else
+ core_recovery_regfile_wport_o = '0;
+ end
+end
+
+/********************************
+* Recovery Routine State Update *
+*********************************/
+always_ff @(posedge clk_i, negedge rst_ni) begin : recovery_routine_register
+ if (~rst_ni)
+ current <= IDLE;
+ else begin
+ current <= next;
+ end
+end
+
+/***********************
+* Recovery Routine FSM *
+************************/
+always_comb begin : recovery_routine_fsm
+ next = current;
+ clear = 1'b0;
+ addr_gen_start = 1'b0;
+ core_recover_rst = '0;
+ pc_write_enable_rst = 1'b0;
+ core_instr_lock_rst = 1'b0;
+ restore_pc_cycles_rst = 1'b0;
+ dmr_ctrl_core_setback_out = '0;
+ dmr_ctrl_core_clk_en_out = '1;
+ dmr_ctrl_core_recover_d = dmr_ctrl_core_recover_q;
+ dmr_ctrl_core_instr_lock_d = dmr_ctrl_core_instr_lock_q;
+ dmr_ctrl_core_clk_en_d = dmr_ctrl_core_clk_en_q;
+ dmr_ctrl_core_debug_req_out = '0;
+ dmr_ctrl_core_debug_resume_o = '0;
+ dmr_ctrl_pc_read_enable_out = '0;
+ dmr_ctrl_pc_write_enable_d = dmr_ctrl_pc_write_enable_q;
+ restore_pc_cycles_d = restore_pc_cycles_q;
+ case (current)
+ IDLE: begin
+ if (routine_start) begin
+ next = RESET;
+ end else
+ next = current;
+ end
+
+ RESET: begin
+ dmr_ctrl_core_setback_out [error_index_q] = 1'b1;
+ dmr_ctrl_core_instr_lock_d [error_index_q] = 1'b1;
+ dmr_ctrl_pc_write_enable_d [error_index_q] = 1'b0;
+ for (int i = 0; i < NumDMRGroups; i++) begin
+ if (i != error_index_q)
+ dmr_ctrl_core_clk_en_d [i] = 1'b0;
+ end
+ next = HALT_REQ;
+ end
+
+ HALT_REQ: begin
+ dmr_ctrl_core_debug_req_out [error_index_q] = 1'b1;
+ next = HALT_WAIT;
+ end
+
+ HALT_WAIT: begin
+ if (dmr_ctrl_core_debug_rsp_in [error_index_q]) begin
+ next = RESTORE_PC;
+ end else
+ next = current;
+ end
+
+ RESTORE_PC: begin
+ dmr_ctrl_pc_read_enable_out [error_index_q] = 1'b1;
+ restore_pc_cycles_d = restore_pc_cycles_q + 1'd1;
+ if (restore_pc_cycles_q == 1'd1) begin
+ restore_pc_cycles_d = 1'd0;
+ next = RESTORE_RF;
+ end else
+ next = current;
+ end
+
+ RESTORE_RF: begin
+ dmr_ctrl_core_recover_d [error_index_q] = 1'b1;
+ addr_gen_start = 1'b1;
+ if (addr_gen_done) begin
+ dmr_ctrl_core_instr_lock_d [error_index_q] = 1'b0;
+ dmr_ctrl_core_debug_resume_o [error_index_q] = 1'b1;
+ next = EXIT;
+ end else
+ next = current;
+ end
+
+ RESTORE_CSR: begin
+ end
+
+ EXIT: begin
+ clear = 1'b1;
+ next = IDLE;
+ end
+ endcase
+end : recovery_routine_fsm
+
+endmodule : DMR_controller
diff --git a/rtl/HMR/HMR_core_regs.hjson b/rtl/HMR/HMR_core_regs.hjson
new file mode 100644
index 00000000..c55f5ede
--- /dev/null
+++ b/rtl/HMR/HMR_core_regs.hjson
@@ -0,0 +1,60 @@
+{ name: "HMR_core_regs",
+ clock_primary: "clk_i",
+ reset_primary: "rst_ni",
+ bus_interfaces: [
+ { protocol: "reg_iface",
+ direction: "device"
+ }
+ ],
+
+ regwidth: "32",
+ registers: [
+ { name: "Current_mode",
+ desc: "Value to determine wich redundancy mode the core with that ID is in.",
+ swaccess: "ro",
+ hwaccess: "hwo",
+ hwext: "true",
+ fields: [
+ { bits: "0",
+ name: "independent",
+ resval: "1",
+ desc: ""
+ },
+ { bits: "1",
+ name: "dual",
+ resval: "0",
+ desc: ""
+ },
+ { bits: "2",
+ name: "triple",
+ resval: "0",
+ desc: ""
+ }
+ ]
+
+ },
+ { name: "mismatches",
+ desc: "Mismatches of the core",
+ swaccess: "rw0c",
+ hwaccess: "hrw",
+ fields: [
+ { bits: "31:0",
+ name: "mismatches",
+ desc: "mismatch counter of the core"
+ }
+ ]
+ },
+ { name: "sp_store",
+ desc: "Stack Pointer storage register",
+ swaccess: "rw",
+ hwaccess: "hro",
+ hwqe: "true",
+ fields: [
+ { bits: "31:0",
+ name: "SP",
+ desc: "Stack Pointer"
+ }
+ ]
+ }
+ ]
+}
diff --git a/rtl/HMR/HMR_dmr_regs.hjson b/rtl/HMR/HMR_dmr_regs.hjson
new file mode 100644
index 00000000..12e16d44
--- /dev/null
+++ b/rtl/HMR/HMR_dmr_regs.hjson
@@ -0,0 +1,56 @@
+{
+ name: "HMR_dmr_regs",
+ clock_primary: "clk_i",
+ reset_primary: "rst_ni",
+ bus_interfaces: [
+ { protocol: "reg_iface",
+ direction: "device"
+ }
+ ],
+
+ regwidth: "32",
+
+ registers: [
+ { name: "DMR_enable",
+ desc: "DMR configuration enable.",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ resval: "0",
+ fields: [
+ { bits: "0",
+ name: "DMR_enable",
+ desc: "DMR configuration enable."
+ }
+ ]
+ },
+ { name: "DMR_config",
+ desc: "DMR configuration bits."
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ fields: [
+ { bits: "0",
+ name: "rapid_recovery",
+ desc: "Enable rapid recovery using an additional register file."
+ },
+ { bits: "1"
+ name: "force_recovery",
+ desc: "Forces recovery routine (if rapid_recovery is available)."
+ }
+ ]
+ },
+ { name: "checkpoint_addr",
+ desc: "Address for the last checkpoint.",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ fields: [
+ { bits: "31:0",
+ name: "checkpoint_addr",
+ desc: "Address for the last checkpoint."
+ }
+ ]
+ }
+ ]
+}
diff --git a/rtl/HMR/HMR_regs.hjson b/rtl/HMR/HMR_regs.hjson
new file mode 100644
index 00000000..c6a10cbc
--- /dev/null
+++ b/rtl/HMR/HMR_regs.hjson
@@ -0,0 +1,141 @@
+{
+ name: "HMR_registers",
+ clock_primary: "clk_i",
+ reset_primary: "rst_ni",
+ bus_interfaces: [
+ { protocol: "reg_iface",
+ direction: "device"
+ }
+ ],
+
+ regwidth: "32",
+
+ param_list: [
+ { name: "NumCores",
+ default: "12" # Supports up to 16 cores
+ },
+ { name: "NumDMRGroups",
+ default: "6"
+ },
+ { name: "NumTMRGroups",
+ default: "4"
+ }
+ ],
+
+ registers: [
+ { name: "avail_config",
+ desc: "Available Configurations from implemented hardware.",
+ swaccess: "ro",
+ hwaccess: "hwo",
+ hwext: "true",
+ fields: [
+ { bits: "0",
+ name: "independent",
+ desc: "Independent mode is available."
+ },
+ { bits: "1",
+ name: "dual",
+ desc: "Dual Modular Redundancy (DMR) is available."
+ },
+ { bits: "2",
+ name: "triple",
+ desc: "Triple Modular Redundancy (TMR) is available."
+ },
+ { bits: "8",
+ name: "rapid_recovery",
+ desc: "Rapid Recovery is available."
+ }
+ ]
+ },
+ { name: "cores_en",
+ desc: "Enabled cores, based on the configuration. Can be used for barriers.",
+ swaccess: "ro",
+ hwaccess: "hwo",
+ hwext: "true",
+ fields: [
+ { bits: "NumCores-1:0"
+ name: "cores_en",
+ desc: "Enabled cores."
+ }
+ ]
+ },
+ { name: "DMR_enable",
+ desc: "DMR configuration enable, on bit per DMR group.",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ hwext: "true",
+ resval: "0",
+ fields: [
+ { bits: "NumDMRGroups-1:0",
+ name: "DMR_enable",
+ desc: "DMR configuration enable."
+ }
+ ]
+ },
+ { name: "TMR_enable",
+ desc: "TMR configuration enable, one bit per TMR group.",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ hwext: "true",
+ resval: "0",
+ fields: [
+ { bits: "NumTMRGroups-1:0",
+ name: "TMR_enable",
+ desc: "TMR configuration enable."
+ }
+ ]
+ },
+ { name: "DMR_config",
+ desc: "DMR configuration bits."
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ hwext: "true",
+ fields: [
+ { bits: "0",
+ name: "rapid_recovery",
+ desc: "Enable rapid recovery using an additional register file."
+ },
+ { bits: "1"
+ name: "force_recovery",
+ desc: "Forces recovery routine (if rapid_recovery is available)."
+ }
+ ]
+ },
+ { name: "TMR_config",
+ desc: "TMR configuration bits."
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ hwext: "true",
+ fields: [
+ { bits: "0",
+ name: "delay_resynch",
+ resval: "0",
+ desc: "Enable wait-for-restoration"
+ },
+ { bits: "1",
+ name: "setback",
+ resval: "1",
+ desc: "Enable setback (synchronous reset) during re-synch."
+ },
+ { bits: "2",
+ name: "reload_setback",
+ resval: "1",
+ desc: "Enable setback on mismatch during reload section of re-synch (only possible with `setback`)"
+ },
+ { bits: "3",
+ name: "rapid_recovery",
+ desc: "Enable rapid recovery using additional register file."
+ },
+ { bits: "4",
+ name: "force_resynch",
+ resval: "0",
+ desc: "Forces a resynchronization routine"
+ }
+ ]
+ }
+ ]
+}
diff --git a/rtl/HMR/HMR_tmr_regs.hjson b/rtl/HMR/HMR_tmr_regs.hjson
new file mode 100644
index 00000000..8d6dab90
--- /dev/null
+++ b/rtl/HMR/HMR_tmr_regs.hjson
@@ -0,0 +1,60 @@
+{
+ name: "HMR_tmr_regs",
+ clock_primary: "clk_i",
+ reset_primary: "rst_ni",
+ bus_interfaces: [
+ { protocol: "reg_iface",
+ direction: "device"
+ }
+ ],
+
+ regwidth: "32",
+
+ registers: [
+ { name: "TMR_enable",
+ desc: "TMR configuration enable.",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ resval: "0",
+ fields: [
+ { bits: "0",
+ name: "TMR_enable",
+ desc: "TMR configuration enable."
+ }
+ ]
+ },
+ { name: "TMR_config",
+ desc: "TMR configuration bits."
+ swaccess: "rw",
+ hwaccess: "hrw",
+ hwqe: "true",
+ fields: [
+ { bits: "0",
+ name: "delay_resynch",
+ resval: "0",
+ desc: "Enable wait-for-restoration"
+ },
+ { bits: "1",
+ name: "setback",
+ resval: "1",
+ desc: "Enable setback (synchronous reset) during re-synch."
+ },
+ { bits: "2",
+ name: "reload_setback",
+ resval: "1",
+ desc: "Enable setback on mismatch during reload section of re-synch (only possible with `setback`)"
+ },
+ { bits: "3",
+ name: "rapid_recovery",
+ desc: "Enable rapid recovery using additional register file."
+ },
+ { bits: "4",
+ name: "force_resynch",
+ resval: "0",
+ desc: "Forces a resynchronization routine"
+ }
+ ]
+ }
+ ]
+}
diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv
new file mode 100644
index 00000000..ac19fb4a
--- /dev/null
+++ b/rtl/HMR/HMR_wrap.sv
@@ -0,0 +1,1944 @@
+// Copyright 2022 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Hybrid modular redundancy wrapping unit
+
+module HMR_wrap
+ import rapid_recovery_pkg::*;
+#(
+ // Wrapper parameters
+ /// Number of physical cores
+ parameter int unsigned NumCores = 0,
+ /// Enables support for Dual Modular Redundancy
+ parameter bit DMRSupported = 1'b1,
+ /// Locks HMR into permanent DMR mode
+ parameter bit DMRFixed = 1'b0,
+ /// Enables support for Triple Modular Redundancy
+ parameter bit TMRSupported = 1'b1,
+ /// Locks HMR into permanent TMR mode
+ parameter bit TMRFixed = 1'b0,
+ /// Enables rapid recovery with a backup register file, PC, ...
+ parameter bit RapidRecovery = 1'b0,
+ /// Separates voters and checkers for data, which are then only checked if data request is valid
+ parameter bit SeparateData = 1'b1,
+ /// Interleave DMR/TMR cores, alternatively with sequential grouping
+ parameter bit InterleaveGrps = 1'b1,
+ parameter int unsigned InstrDataWidth = 32,
+ parameter int unsigned DataWidth = 32,
+ parameter int unsigned BeWidth = 4,
+ parameter int unsigned UserWidth = 0,
+ parameter int unsigned NumExtPerf = 5,
+ parameter type reg_req_t = logic,
+ parameter type reg_resp_t = logic,
+ // Local parameters depending on the above ones
+ /// Number of TMR groups (virtual TMR cores)
+ localparam int unsigned NumTMRGroups = NumCores/3,
+ /// Number of physical cores used for TMR
+ localparam int unsigned NumTMRCores = NumTMRGroups * 3,
+ /// Number of physical cores NOT used for TMR
+ localparam int unsigned NumTMRLeftover = NumCores - NumTMRCores,
+ /// Number of DMR groups (virtual DMR cores)
+ localparam int unsigned NumDMRGroups = NumCores/2,
+ /// Nubmer of physical cores used for DMR
+ localparam int unsigned NumDMRCores = NumDMRGroups * 2,
+ /// Number of physical cores NOT used for DMR
+ localparam int unsigned NumDMRLeftover = NumCores - NumDMRCores,
+ /// Number of cores visible to the system (Fixed mode removes unneeded system ports)
+ localparam int unsigned NumSysCores = DMRFixed ? NumDMRCores : TMRFixed ? NumTMRCores : NumCores
+) (
+ input logic clk_i ,
+ input logic rst_ni,
+
+ // Port to configuration unit
+ input reg_req_t reg_request_i ,
+ output reg_resp_t reg_response_o,
+
+ // TMR signals
+ output logic [NumTMRGroups-1:0] tmr_failure_o ,
+ output logic [ NumSysCores-1:0] tmr_error_o , // Should this not be NumTMRCores? or NumCores?
+ output logic [NumTMRGroups-1:0] tmr_resynch_req_o,
+ output logic [ NumCores-1:0] tmr_sw_synch_req_o,
+ input logic [NumTMRGroups-1:0] tmr_cores_synch_i,
+
+ // DMR signals
+ output logic [NumDMRGroups-1:0] dmr_failure_o ,
+ output logic [ NumSysCores-1:0] dmr_error_o , // Should this not be NumDMRCores? or NumCores?
+ output logic [NumDMRGroups-1:0] dmr_resynch_req_o,
+ output logic [ NumCores-1:0] dmr_sw_synch_req_o,
+ input logic [NumDMRGroups-1:0] dmr_cores_synch_i,
+
+ // Backup Port from Cores' CSRs
+ input csrs_intf_t [NumCores-1:0] backup_csr_i,
+ // Recovery Port to Cores' CSRs
+ output csrs_intf_t [NumCores-1:0] recovery_csr_o,
+ // Backup Port from Cores'Program Counter
+ input logic [ NumCores-1:0][DataWidth-1:0] backup_program_counter_i,
+ output logic [ NumCores-1:0] pc_recover_o,
+ output logic [ NumCores-1:0][DataWidth-1:0] recovery_program_counter_o,
+ input logic [ NumCores-1:0] backup_branch_i,
+ input logic [ NumCores-1:0][DataWidth-1:0] backup_branch_addr_i,
+ output logic [ NumCores-1:0] recovery_branch_o,
+ output logic [ NumCores-1:0][DataWidth-1:0] recovery_branch_addr_o,
+ // Backup ports from Cores' RFs
+ input regfile_write_t [NumCores-1:0] backup_regfile_wport_i,
+ output regfile_write_t [NumCores-1:0] core_recovery_regfile_wport_o,
+ // Nonstandard core control signals
+ output logic [ NumCores-1:0] core_setback_o ,
+ output logic [ NumCores-1:0] core_instr_lock_o ,
+ output logic [ NumCores-1:0] core_recover_o ,
+ output logic [ NumCores-1:0] core_debug_resume_o ,
+
+ // Ports connecting to System
+ input logic [NumSysCores-1:0][ 3:0] sys_core_id_i ,
+ input logic [NumSysCores-1:0][ 5:0] sys_cluster_id_i ,
+
+ input logic [NumSysCores-1:0] sys_clock_en_i ,
+ input logic [NumSysCores-1:0] sys_fetch_en_i ,
+ input logic [NumSysCores-1:0][ 31:0] sys_boot_addr_i ,
+ output logic [NumSysCores-1:0] sys_core_busy_o ,
+
+ input logic [NumSysCores-1:0] sys_irq_req_i ,
+ output logic [NumSysCores-1:0] sys_irq_ack_o ,
+ input logic [NumSysCores-1:0][ 4:0] sys_irq_id_i ,
+ output logic [NumSysCores-1:0][ 4:0] sys_irq_ack_id_o ,
+
+ output logic [NumSysCores-1:0] sys_instr_req_o ,
+ input logic [NumSysCores-1:0] sys_instr_gnt_i ,
+ output logic [NumSysCores-1:0][ 31:0] sys_instr_addr_o ,
+ input logic [NumSysCores-1:0][InstrDataWidth-1:0] sys_instr_r_rdata_i,
+ input logic [NumSysCores-1:0] sys_instr_r_valid_i,
+ input logic [NumSysCores-1:0] sys_instr_err_i ,
+
+ input logic [NumSysCores-1:0] sys_debug_req_i ,
+
+ output logic [NumSysCores-1:0] sys_data_req_o ,
+ output logic [NumSysCores-1:0][ 31:0] sys_data_add_o ,
+ output logic [NumSysCores-1:0] sys_data_wen_o ,
+ output logic [NumSysCores-1:0][ DataWidth-1:0] sys_data_wdata_o ,
+ output logic [NumSysCores-1:0][ UserWidth-1:0] sys_data_user_o ,
+ output logic [NumSysCores-1:0][ BeWidth-1:0] sys_data_be_o ,
+ input logic [NumSysCores-1:0] sys_data_gnt_i ,
+ input logic [NumSysCores-1:0] sys_data_r_opc_i ,
+ input logic [NumSysCores-1:0][ DataWidth-1:0] sys_data_r_rdata_i ,
+ input logic [NumSysCores-1:0][ UserWidth-1:0] sys_data_r_user_i ,
+ input logic [NumSysCores-1:0] sys_data_r_valid_i ,
+ input logic [NumSysCores-1:0] sys_data_err_i ,
+
+ input logic [NumSysCores-1:0][NumExtPerf-1:0] sys_perf_counters_i,
+
+ // Ports connecting to the cores
+ output logic [ NumCores-1:0][ 3:0] core_core_id_o ,
+ output logic [ NumCores-1:0][ 5:0] core_cluster_id_o ,
+
+ output logic [ NumCores-1:0] core_clock_en_o ,
+ output logic [ NumCores-1:0] core_fetch_en_o ,
+ output logic [ NumCores-1:0][ 31:0] core_boot_addr_o ,
+ input logic [ NumCores-1:0] core_core_busy_i ,
+
+ output logic [ NumCores-1:0] core_irq_req_o ,
+ input logic [ NumCores-1:0] core_irq_ack_i ,
+ output logic [ NumCores-1:0][ 4:0] core_irq_id_o ,
+ input logic [ NumCores-1:0][ 4:0] core_irq_ack_id_i ,
+
+ input logic [ NumCores-1:0] core_instr_req_i ,
+ output logic [ NumCores-1:0] core_instr_gnt_o ,
+ input logic [ NumCores-1:0][ 31:0] core_instr_addr_i ,
+ output logic [ NumCores-1:0][InstrDataWidth-1:0] core_instr_r_rdata_o,
+ output logic [ NumCores-1:0] core_instr_r_valid_o,
+ output logic [ NumCores-1:0] core_instr_err_o ,
+
+ output logic [ NumCores-1:0] core_debug_req_o ,
+ input logic [ NumCores-1:0] core_debug_halted_i ,
+
+ input logic [ NumCores-1:0] core_data_req_i ,
+ input logic [ NumCores-1:0][ 31:0] core_data_add_i ,
+ input logic [ NumCores-1:0] core_data_wen_i ,
+ input logic [ NumCores-1:0][ DataWidth-1:0] core_data_wdata_i ,
+ input logic [ NumCores-1:0][ UserWidth-1:0] core_data_user_i ,
+ input logic [ NumCores-1:0][ BeWidth-1:0] core_data_be_i ,
+ output logic [ NumCores-1:0] core_data_gnt_o ,
+ output logic [ NumCores-1:0] core_data_r_opc_o ,
+ output logic [ NumCores-1:0][ DataWidth-1:0] core_data_r_rdata_o ,
+ output logic [ NumCores-1:0][ UserWidth-1:0] core_data_r_user_o ,
+ output logic [ NumCores-1:0] core_data_r_valid_o ,
+ output logic [ NumCores-1:0] core_data_err_o ,
+
+ output logic [ NumCores-1:0][NumExtPerf-1:0] core_perf_counters_o
+
+ // APU/SHARED_FPU not implemented
+);
+ function int max(int a, int b);
+ return (a > b) ? a : b;
+ endfunction
+
+ localparam int unsigned NumBackupRegfiles = max(DMRSupported || DMRFixed ? NumDMRGroups : 0, TMRSupported || TMRFixed ? NumTMRGroups : 0);
+
+ function int tmr_group_id (int core_id);
+ if (InterleaveGrps) return core_id % NumTMRGroups;
+ else return (core_id/3);
+ endfunction
+
+ function int tmr_core_id (int group_id, int core_offset);
+ if (InterleaveGrps) return group_id + core_offset * NumTMRGroups;
+ else return (group_id * 3) + core_offset;
+ endfunction
+
+ function int tmr_shared_id (int group_id);
+ if (InterleaveGrps || !(DMRSupported || DMRFixed)) return group_id;
+ else return group_id + group_id/2;
+ endfunction
+
+ function int tmr_offset_id (int core_id);
+ if (InterleaveGrps) return core_id / NumTMRGroups;
+ else return core_id % 3;
+ endfunction
+
+ function int dmr_group_id (int core_id);
+ if (InterleaveGrps) return core_id % NumDMRGroups;
+ else return (core_id/2);
+ endfunction
+
+ function int dmr_core_id (int group_id, int core_offset);
+ if (InterleaveGrps) return group_id + core_offset * NumDMRGroups;
+ else return (group_id * 2) + core_offset;
+ endfunction
+
+ function int dmr_shared_id (int group_id);
+ return group_id;
+ endfunction
+
+ function int dmr_offset_id (int core_id);
+ if (InterleaveGrps) return core_id / NumDMRGroups;
+ else return core_id % 2;
+ endfunction
+
+ if (TMRFixed && DMRFixed) $fatal(1, "Cannot fix both TMR and DMR!");
+
+ localparam int unsigned CtrlConcatWidth = 1 + 1 + 5 + 1 + 32 + 1;
+ // busy irq_ack irq_ack_id i_req i_addr d_req
+ localparam int unsigned RapidRecoveryConcatWidth = RapidRecovery ? 165 + 65 + 76 : 0;
+ // csr pc rf
+ localparam int unsigned DataConcatWidth = 32 + 1 + DataWidth + BeWidth + UserWidth;
+ // data_add data_wen data_wdata data_be data_user
+ localparam int unsigned MainConcatWidth = RapidRecoveryConcatWidth +
+ (SeparateData ? CtrlConcatWidth
+ : CtrlConcatWidth + DataConcatWidth);
+
+ localparam int unsigned RFAddrWidth = 6;
+
+ logic [ NumCores-1:0][MainConcatWidth-1:0] main_concat_in;
+ logic [NumTMRGroups-1:0][MainConcatWidth-1:0] main_tmr_out;
+ logic [NumDMRGroups-1:0][MainConcatWidth-1:0] main_dmr_out;
+
+ logic [ NumCores-1:0][DataConcatWidth-1:0] data_concat_in;
+ logic [NumTMRGroups-1:0][DataConcatWidth-1:0] data_tmr_out;
+ logic [NumDMRGroups-1:0][DataConcatWidth-1:0] data_dmr_out;
+
+ logic [NumTMRGroups-1:0] tmr_failure, tmr_failure_main, tmr_failure_data;
+ logic [NumTMRGroups-1:0][2:0] tmr_error, tmr_error_main, tmr_error_data;
+ logic [NumTMRGroups-1:0] tmr_single_mismatch;
+
+ logic [NumDMRGroups-1:0] dmr_failure, dmr_failure_main, dmr_failure_data;
+ // logic [NumDMRGroups-1:0][2:0] dmr_error, dmr_error_main, dmr_error_data;
+ // logic [NumDMRGroups-1:0] dmr_single_mismatch;
+
+ logic [NumTMRGroups-1:0] tmr_core_busy_out;
+ logic [NumTMRGroups-1:0] tmr_irq_ack_out;
+ logic [NumTMRGroups-1:0][ 4:0] tmr_irq_ack_id_out;
+ logic [NumTMRGroups-1:0] tmr_instr_req_out;
+ logic [NumTMRGroups-1:0][ 31:0] tmr_instr_addr_out;
+ logic [NumTMRGroups-1:0] tmr_data_req_out;
+ logic [NumTMRGroups-1:0][ 31:0] tmr_data_add_out;
+ logic [NumTMRGroups-1:0] tmr_data_wen_out;
+ logic [NumTMRGroups-1:0][ DataWidth-1:0] tmr_data_wdata_out;
+ logic [NumTMRGroups-1:0][ UserWidth-1:0] tmr_data_user_out;
+ logic [NumTMRGroups-1:0][ BeWidth-1:0] tmr_data_be_out;
+
+ logic [NumDMRGroups-1:0] dmr_core_busy_out;
+ logic [NumDMRGroups-1:0] dmr_irq_ack_out;
+ logic [NumDMRGroups-1:0][ 4:0] dmr_irq_ack_id_out;
+ logic [NumDMRGroups-1:0] dmr_instr_req_out;
+ logic [NumDMRGroups-1:0][ 31:0] dmr_instr_addr_out;
+ logic [NumDMRGroups-1:0] dmr_data_req_out;
+ logic [NumDMRGroups-1:0][ 31:0] dmr_data_add_out;
+ logic [NumDMRGroups-1:0] dmr_data_wen_out;
+ logic [NumDMRGroups-1:0][ DataWidth-1:0] dmr_data_wdata_out;
+ logic [NumDMRGroups-1:0][ UserWidth-1:0] dmr_data_user_out;
+ logic [NumDMRGroups-1:0][ BeWidth-1:0] dmr_data_be_out;
+
+
+ logic [ NumDMRGroups-1:0][RFAddrWidth-1:0] dmr_backup_regfile_waddr_a,
+ dmr_backup_regfile_waddr_b;
+ logic [ NumDMRGroups-1:0][ DataWidth-1:0] dmr_backup_program_counter,
+ dmr_backup_regfile_wdata_a,
+ dmr_backup_regfile_wdata_b,
+ dmr_backup_branch_addr_int;
+ logic [ NumDMRGroups-1:0] dmr_backup_branch_int,
+ dmr_start_recovery,
+ dmr_backup_regfile_we_a,
+ dmr_backup_regfile_we_b,
+ dmr_recovery_finished;
+ logic [ NumTMRGroups-1:0][RFAddrWidth-1:0] tmr_backup_regfile_waddr_a,
+ tmr_backup_regfile_waddr_b;
+ logic [ NumTMRGroups-1:0][ DataWidth-1:0] tmr_backup_program_counter,
+ tmr_backup_regfile_wdata_a,
+ tmr_backup_regfile_wdata_b,
+ tmr_backup_branch_addr_int;
+ logic [ NumTMRGroups-1:0] tmr_backup_branch_int,
+ tmr_start_recovery,
+ tmr_backup_regfile_we_a,
+ tmr_backup_regfile_we_b,
+ tmr_recovery_finished;
+
+ logic [NumBackupRegfiles-1:0][RFAddrWidth-1:0] backup_regfile_waddr_a,
+ backup_regfile_waddr_b;
+ logic [NumBackupRegfiles-1:0][ DataWidth-1:0] backup_branch_addr_int,
+ recovery_branch_addr_out,
+ backup_program_counter_int,
+ recovery_program_counter_out,
+ backup_regfile_wdata_a,
+ backup_regfile_wdata_b;
+ logic [NumBackupRegfiles-1:0] backup_branch_int,
+ backup_regfile_we_a,
+ backup_regfile_we_b,
+ backup_program_counter_error,
+ recovery_branch_out,
+ backup_enable,
+ recovery_csr_enable_out,
+ recovery_pc_enable_out,
+ recovery_debug_req_out,
+ recovery_debug_halted_in,
+ recovery_instr_lock_out,
+ recovery_setback_out,
+ recovery_trigger_out,
+ recovery_debug_resume_out,
+ start_recovery,
+ recovery_finished;
+
+ logic [NumBackupRegfiles-1:0] rapid_recovery_backup_enable;
+ regfile_raddr_t [NumBackupRegfiles-1:0] core_regfile_raddr_out;
+ regfile_rdata_t [NumBackupRegfiles-1:0] core_recovery_regfile_rdata_out;
+ regfile_write_t [NumBackupRegfiles-1:0] core_recovery_regfile_wport_out;
+ csrs_intf_t [NumBackupRegfiles-1:0] backup_csr_int, dmr_backup_csr, tmr_backup_csr, recovery_csr_out;
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_concat
+ if (SeparateData) begin : gen_separate_data
+ assign main_concat_in[i] = {core_core_busy_i[i], core_irq_ack_i[i], core_irq_ack_id_i[i],
+ core_instr_req_i[i], core_instr_addr_i[i], core_data_req_i[i],
+ // CSRs signals
+ backup_csr_i[i].csr_mstatus , // 7-bits
+ backup_csr_i[i].csr_mie , // 32-bits
+ backup_csr_i[i].csr_mtvec , // 24-bits
+ backup_csr_i[i].csr_mscratch, // 32-bits
+ backup_csr_i[i].csr_mip , // 32-bits
+ backup_csr_i[i].csr_mepc , // 32-bits
+ backup_csr_i[i].csr_mcause , // 6-bits
+ // PC signals
+ backup_program_counter_i[i], // 32-bits
+ backup_branch_i[i], backup_branch_addr_i[i], // 1-bits + 32-bits
+ // RF signals
+ backup_regfile_wport_i[i].wdata_a, // 32-bits
+ backup_regfile_wport_i[i].waddr_a, // 6-bits
+ backup_regfile_wport_i[i].wdata_b, // 32-bits
+ backup_regfile_wport_i[i].waddr_b};// 6-bits
+ assign data_concat_in[i] = {core_data_add_i[i], core_data_wen_i[i], core_data_wdata_i[i],
+ core_data_be_i[i], core_data_user_i[i]};
+ end else begin : gen_single_group
+ assign main_concat_in[i] = {core_core_busy_i[i], core_irq_ack_i[i], core_irq_ack_id_i[i],
+ core_instr_req_i[i], core_instr_addr_i[i], core_data_req_i[i], core_data_add_i[i],
+ core_data_wen_i[i], core_data_wdata_i[i], core_data_be_i[i], core_data_user_i[i],
+ // CSRs signals
+ backup_csr_i[i].csr_mstatus , // 7-bits
+ backup_csr_i[i].csr_mie , // 32-bits
+ backup_csr_i[i].csr_mtvec , // 24-bits
+ backup_csr_i[i].csr_mscratch, // 32-bits
+ backup_csr_i[i].csr_mip , // 32-bits
+ backup_csr_i[i].csr_mepc , // 32-bits
+ backup_csr_i[i].csr_mcause , // 6-bits
+ // PC signals
+ backup_program_counter_i[i], // 32-bits
+ backup_branch_i[i], backup_branch_addr_i[i], // 1-bits + 32-bits
+ // RF signals
+ backup_regfile_wport_i[i].wdata_a, // 32-bits
+ backup_regfile_wport_i[i].waddr_a, // 6-bits
+ backup_regfile_wport_i[i].wdata_b, // 32-bits
+ backup_regfile_wport_i[i].waddr_b};// 6-bits
+ assign data_concat_in = '0;
+ end
+ end
+
+ logic [NumSysCores-1:0] filt_instr_req, filt_data_req;
+ logic [NumSysCores-1:0] filt_instr_r_valid, filt_data_r_valid;
+ logic [NumSysCores-1:0] filt_instr_gnt, filt_data_gnt;
+ logic [NumSysCores-1:0] filt_data_we;
+ logic [NumSysCores-1:0][31:0] filt_instr_addr, filt_data_addr;
+ logic [NumSysCores-1:0][DataWidth-1:0] filt_data_data;
+ logic [NumSysCores-1:0][BeWidth-1:0] filt_data_be;
+
+ for (genvar i = 0; i < NumSysCores; i++) begin
+ resp_suppress #(
+ .AW (32),
+ .DW (DataWidth)
+ ) i_instr_suppress (
+ .clk_i,
+ .rst_ni,
+
+ .ctrl_setback_i (core_setback_o[i]),
+
+ .req_i (filt_instr_req [i]),
+ .gnt_o (filt_instr_gnt [i]),
+ .r_valid_o (filt_instr_r_valid[i]),
+ .we_i ('0),
+ .addr_i (filt_instr_addr [i]),
+ .data_i ('0),
+ .be_i ('0),
+
+ .req_o (sys_instr_req_o[i]),
+ .gnt_i (sys_instr_gnt_i[i]),
+ .r_valid_i (sys_instr_r_valid_i[i]),
+ .we_o (),
+ .addr_o (sys_instr_addr_o[i]),
+ .data_o (),
+ .be_o ()
+ );
+ resp_suppress #(
+ .AW (32),
+ .DW (DataWidth)
+ ) i_data_suppress (
+ .clk_i,
+ .rst_ni,
+
+ .ctrl_setback_i (core_setback_o[i]),
+
+ .req_i (filt_data_req [i]),
+ .gnt_o (filt_data_gnt [i]),
+ .r_valid_o (filt_data_r_valid[i]),
+ .we_i (filt_data_we [i]),
+ .addr_i (filt_data_addr [i]),
+ .data_i (filt_data_data [i]),
+ .be_i (filt_data_be [i]),
+
+ .req_o (sys_data_req_o [i]),
+ .gnt_i (sys_data_gnt_i [i]),
+ .r_valid_i (sys_data_r_valid_i[i]),
+ .we_o (sys_data_wen_o [i]),
+ .addr_o (sys_data_add_o [i]),
+ .data_o (sys_data_wdata_o [i]),
+ .be_o (sys_data_be_o [i])
+ );
+ end
+
+ /***************************
+ * HMR Control Registers *
+ ***************************/
+
+ logic [NumCores-1:0] core_en_as_master;
+ logic [NumCores-1:0] core_in_independent;
+ logic [NumCores-1:0] core_in_dmr;
+ logic [NumCores-1:0] core_in_tmr;
+ logic [NumCores-1:0] dmr_core_rapid_recovery_en;
+ logic [NumCores-1:0] tmr_core_rapid_recovery_en;
+
+ logic [NumDMRGroups-1:0][1:0] dmr_setback_q;
+ logic [NumDMRGroups-1:0] dmr_grp_in_independent;
+ logic [NumDMRGroups-1:0] dmr_rapid_recovery_en;
+
+ logic [NumTMRGroups-1:0][2:0] tmr_setback_q;
+ logic [NumTMRGroups-1:0] tmr_grp_in_independent;
+ logic [NumTMRGroups-1:0] tmr_rapid_recovery_en;
+
+ logic [NumCores-1:0] sp_store_is_zero;
+ logic [NumCores-1:0] sp_store_will_be_zero;
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_global_status
+ assign core_in_independent[i] = ~core_in_dmr[i] & ~core_in_tmr[i];
+ assign core_in_dmr[i] = (DMRSupported || DMRFixed) && i < NumDMRCores ? ~dmr_grp_in_independent[dmr_group_id(i)] : '0;
+ assign core_in_tmr[i] = (TMRSupported || TMRFixed) && i < NumTMRCores ? ~tmr_grp_in_independent[tmr_group_id(i)] : '0;
+ assign core_en_as_master[i] = ((tmr_core_id(tmr_group_id(i), 0) == i || i>=NumTMRCores) ? 1'b1 : ~core_in_tmr[i]) &
+ ((dmr_core_id(dmr_group_id(i), 0) == i || i>=NumDMRCores) ? 1'b1 : ~core_in_dmr[i]);
+ assign dmr_core_rapid_recovery_en[i] = (DMRSupported || DMRFixed) && i < NumDMRCores && RapidRecovery ? dmr_rapid_recovery_en[dmr_group_id(i)] : '0;
+ assign tmr_core_rapid_recovery_en[i] = (TMRSupported || TMRFixed) && i < NumTMRCores && RapidRecovery ? tmr_rapid_recovery_en[tmr_group_id(i)] : '0;
+ end
+
+ reg_req_t [3:0] top_register_reqs;
+ reg_resp_t [3:0] top_register_resps;
+
+ // 0x000-0x100 -> Top config
+ // 0x100-0x200 -> Core configs
+ // 0x200-0x300 -> DMR configs
+ // 0x300-0x400 -> TMR configs
+
+ reg_demux #(
+ .NoPorts ( 4 ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_resp_t )
+ ) i_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( reg_request_i.addr[9:8] ),
+ .in_req_i ( reg_request_i ),
+ .in_rsp_o ( reg_response_o ),
+ .out_req_o ( top_register_reqs ),
+ .out_rsp_i ( top_register_resps )
+ );
+
+ // Global config registers
+
+ hmr_registers_reg_pkg::hmr_registers_hw2reg_t hmr_hw2reg;
+ hmr_registers_reg_pkg::hmr_registers_reg2hw_t hmr_reg2hw;
+
+ hmr_registers_reg_top #(
+ .reg_req_t( reg_req_t ),
+ .reg_rsp_t( reg_resp_t )
+ ) i_hmr_registers (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(top_register_reqs[0] ),
+ .reg_rsp_o(top_register_resps[0]),
+ .reg2hw (hmr_reg2hw),
+ .hw2reg (hmr_hw2reg),
+ .devmode_i('0)
+ );
+
+ assign hmr_hw2reg.avail_config.independent.d = ~(TMRFixed | DMRFixed);
+ assign hmr_hw2reg.avail_config.dual.d = DMRFixed | DMRSupported;
+ assign hmr_hw2reg.avail_config.triple.d = TMRFixed | TMRSupported;
+ assign hmr_hw2reg.avail_config.rapid_recovery.d = RapidRecovery;
+
+ always_comb begin : proc_reg_status
+ hmr_hw2reg.cores_en.d = '0;
+ hmr_hw2reg.cores_en.d = core_en_as_master;
+
+ hmr_hw2reg.dmr_enable.d = '0;
+ hmr_hw2reg.dmr_enable.d[NumDMRGroups-1:0] = ~dmr_grp_in_independent;
+ hmr_hw2reg.tmr_enable.d = '0;
+ hmr_hw2reg.tmr_enable.d[NumTMRGroups-1:0] = ~tmr_grp_in_independent;
+ end
+
+ assign hmr_hw2reg.tmr_config.delay_resynch.d = '0;
+ assign hmr_hw2reg.tmr_config.setback.d = '0;
+ assign hmr_hw2reg.tmr_config.reload_setback.d = '0;
+ assign hmr_hw2reg.tmr_config.force_resynch.d = '0;
+ assign hmr_hw2reg.tmr_config.rapid_recovery.d = '0;
+
+ assign hmr_hw2reg.dmr_config.rapid_recovery.d = '0;
+ assign hmr_hw2reg.dmr_config.force_recovery.d = '0;
+
+ // Core Config Registers
+
+ reg_req_t [NumCores-1:0] core_register_reqs;
+ reg_resp_t [NumCores-1:0] core_register_resps;
+
+ // 4 words per core
+
+ reg_demux #(
+ .NoPorts ( NumCores ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_resp_t )
+ ) i_core_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( top_register_reqs [1].addr[4+$clog2(NumCores)-1:4] ),
+ .in_req_i ( top_register_reqs [1] ),
+ .in_rsp_o ( top_register_resps[1] ),
+ .out_req_o ( core_register_reqs ),
+ .out_rsp_i ( core_register_resps )
+ );
+
+ hmr_core_regs_reg_pkg::hmr_core_regs_reg2hw_t [NumCores-1:0] core_config_reg2hw;
+ hmr_core_regs_reg_pkg::hmr_core_regs_hw2reg_t [NumCores-1:0] core_config_hw2reg;
+
+ logic [NumCores-1:0] tmr_incr_mismatches;
+ logic [NumCores-1:0] dmr_incr_mismatches;
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_registers
+ hmr_core_regs_reg_top #(
+ .reg_req_t(reg_req_t),
+ .reg_rsp_t(reg_resp_t)
+ ) icore_registers (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i( core_register_reqs [i] ),
+ .reg_rsp_o( core_register_resps[i] ),
+ .reg2hw ( core_config_reg2hw [i] ),
+ .hw2reg ( core_config_hw2reg [i] ),
+ .devmode_i('0)
+ );
+
+ assign core_config_hw2reg[i].mismatches.d = core_config_reg2hw[i].mismatches.q + 1;
+ assign core_config_hw2reg[i].mismatches.de = tmr_incr_mismatches[i] | dmr_incr_mismatches[i];
+ assign core_config_hw2reg[i].current_mode.independent.d = core_in_independent[i];
+ assign core_config_hw2reg[i].current_mode.dual.d = core_in_dmr[i];
+ assign core_config_hw2reg[i].current_mode.triple.d = core_in_tmr[i];
+ assign sp_store_is_zero[i] = core_config_reg2hw[i].sp_store.q == '0;
+ assign sp_store_will_be_zero[i] = core_config_reg2hw[i].sp_store.qe && core_register_reqs[i].wdata == '0;
+ end
+
+
+ /**********************************************************
+ ******************** TMR Voters & Regs *******************
+ **********************************************************/
+
+ if (TMRSupported || TMRFixed) begin : gen_tmr_logic
+ if (TMRFixed && NumCores % 3 != 0) $warning("Extra cores added not properly handled!");
+
+ reg_req_t [NumTMRGroups-1:0] tmr_register_reqs;
+ reg_resp_t [NumTMRGroups-1:0] tmr_register_resps;
+ logic [NumTMRGroups-1:0] tmr_sw_synch_req;
+
+ localparam TMRSelWidth = $clog2(NumTMRGroups);
+
+ /***************
+ * Registers *
+ ***************/
+ reg_demux #(
+ .NoPorts ( NumTMRGroups ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_resp_t )
+ ) i_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( top_register_reqs[3].addr[4+$clog2(NumTMRGroups)-1:4] ),
+ .in_req_i ( top_register_reqs[3] ),
+ .in_rsp_o ( top_register_resps[3] ),
+ .out_req_o ( tmr_register_reqs ),
+ .out_rsp_i ( tmr_register_resps )
+ );
+
+ for (genvar i = NumTMRCores; i < NumCores; i++) begin : gen_extra_core_assigns
+ assign tmr_incr_mismatches[i] = '0;
+ assign tmr_sw_synch_req_o[i] = '0;
+ end
+
+ for (genvar i = 0; i < NumTMRGroups; i++) begin : gen_tmr_groups
+
+ hmr_tmr_ctrl #(
+ .reg_req_t ( reg_req_t ),
+ .reg_resp_t ( reg_resp_t ),
+ .TMRFixed ( TMRFixed ),
+ .InterleaveGrps ( InterleaveGrps ),
+ .DefaultInTMR ( 1'b0 ),
+ .RapidRecovery ( RapidRecovery )
+ ) i_tmr_ctrl (
+ .clk_i,
+ .rst_ni,
+
+ .reg_req_i ( tmr_register_reqs[i] ),
+ .reg_resp_o ( tmr_register_resps[i] ),
+
+ .tmr_enable_q_i ( hmr_reg2hw.tmr_enable.q[i] ),
+ .tmr_enable_qe_i ( hmr_reg2hw.tmr_enable.qe ),
+ .delay_resynch_q_i ( hmr_reg2hw.tmr_config.delay_resynch.q ),
+ .delay_resynch_qe_i ( hmr_reg2hw.tmr_config.delay_resynch.qe ),
+ .setback_q_i ( hmr_reg2hw.tmr_config.setback.q ),
+ .setback_qe_i ( hmr_reg2hw.tmr_config.setback.qe ),
+ .reload_setback_q_i ( hmr_reg2hw.tmr_config.reload_setback.q ),
+ .reload_setback_qe_i ( hmr_reg2hw.tmr_config.reload_setback.qe ),
+ .rapid_recovery_q_i ( hmr_reg2hw.tmr_config.rapid_recovery.q ),
+ .rapid_recovery_qe_i ( hmr_reg2hw.tmr_config.rapid_recovery.qe ),
+ .force_resynch_q_i ( hmr_reg2hw.tmr_config.force_resynch.q ),
+ .force_resynch_qe_i ( hmr_reg2hw.tmr_config.force_resynch.qe ),
+
+ .setback_o ( tmr_setback_q[i] ),
+ .sw_resynch_req_o ( tmr_resynch_req_o[i] ),
+ .sw_synch_req_o ( tmr_sw_synch_req[i] ),
+ .grp_in_independent_o ( tmr_grp_in_independent[i] ),
+ .rapid_recovery_en_o ( tmr_rapid_recovery_en[i] ),
+ .tmr_incr_mismatches_o( {tmr_incr_mismatches[tmr_core_id(i,0)], tmr_incr_mismatches[tmr_core_id(i,1)], tmr_incr_mismatches[tmr_core_id(i,2)]} ),
+ .tmr_single_mismatch_i( tmr_single_mismatch[i] ),
+ .tmr_error_i ( tmr_error[i] ),
+ .tmr_failure_i ( tmr_failure[i] ),
+ .sp_store_is_zero ( sp_store_is_zero[tmr_core_id(i, 0)] ),
+ .sp_store_will_be_zero( sp_store_will_be_zero[tmr_core_id(i, 0)] ),
+
+ .fetch_en_i ( sys_fetch_en_i[tmr_core_id(i, 0)] ),
+ .cores_synch_i ( tmr_cores_synch_i[i] ),
+
+ .recovery_request_o ( tmr_start_recovery [i] ),
+ .recovery_finished_i ( tmr_recovery_finished [i] )
+ );
+
+ assign tmr_sw_synch_req_o[tmr_core_id(i, 0)] = tmr_sw_synch_req[i];
+ assign tmr_sw_synch_req_o[tmr_core_id(i, 1)] = tmr_sw_synch_req[i];
+ assign tmr_sw_synch_req_o[tmr_core_id(i, 2)] = tmr_sw_synch_req[i];
+
+ assign tmr_failure[i] = tmr_data_req_out[i] ?
+ tmr_failure_main[i] | tmr_failure_data[i] :
+ tmr_failure_main[i];
+ assign tmr_error[i] = tmr_data_req_out[i] ?
+ tmr_error_main[i] | tmr_error_data[i] :
+ tmr_error_main[i];
+ assign tmr_single_mismatch[i] = tmr_error[i] != 3'b000;
+
+ bitwise_TMR_voter #(
+ .DataWidth( MainConcatWidth ),
+ .VoterType( 0 )
+ ) i_main_voter (
+ .a_i ( main_concat_in[tmr_core_id(i, 0)] ),
+ .b_i ( main_concat_in[tmr_core_id(i, 1)] ),
+ .c_i ( main_concat_in[tmr_core_id(i, 2)] ),
+ .majority_o ( main_tmr_out [i ] ),
+ .error_o ( tmr_failure_main[i] ),
+ .error_cba_o( tmr_error_main[i ] )
+ );
+ if (SeparateData) begin : gen_data_voter
+ bitwise_TMR_voter #(
+ .DataWidth( DataConcatWidth ),
+ .VoterType( 0 )
+ ) i_data_voter (
+ .a_i ( data_concat_in[tmr_core_id(i, 0)] ),
+ .b_i ( data_concat_in[tmr_core_id(i, 1)] ),
+ .c_i ( data_concat_in[tmr_core_id(i, 2)] ),
+ .majority_o ( data_tmr_out [i ] ),
+ .error_o ( tmr_failure_data[i] ),
+ .error_cba_o( tmr_error_data[i ] )
+ );
+
+ assign {tmr_core_busy_out[i], tmr_irq_ack_out[i], tmr_irq_ack_id_out[i],
+ tmr_instr_req_out[i], tmr_instr_addr_out[i], tmr_data_req_out[i],
+ // CSRs signals
+ tmr_backup_csr[i].csr_mstatus , // 7-bits
+ tmr_backup_csr[i].csr_mie , // 32-bits
+ tmr_backup_csr[i].csr_mtvec , // 24-bits
+ tmr_backup_csr[i].csr_mscratch, // 32-bits
+ tmr_backup_csr[i].csr_mip , // 32-bits
+ tmr_backup_csr[i].csr_mepc , // 32-bits
+ tmr_backup_csr[i].csr_mcause , // 6-bits
+ // PC signals
+ tmr_backup_program_counter[i], // 32-bits
+ tmr_backup_branch_int[i], tmr_backup_branch_addr_int[i], // 1-bits + 32-bits
+ // RF signals
+ tmr_backup_regfile_wdata_a[i], // 32-bits
+ tmr_backup_regfile_waddr_a[i], // 6-bits
+ tmr_backup_regfile_wdata_b[i], // 32-bits
+ tmr_backup_regfile_waddr_b[i]}
+ = main_tmr_out[i];
+ assign {tmr_data_add_out[i], tmr_data_wen_out[i], tmr_data_wdata_out[i],
+ tmr_data_be_out[i], tmr_data_user_out[i]} = data_tmr_out[i];
+ end else begin : gen_data_in_main
+ assign tmr_failure_data[i] = 1'b0;
+ assign tmr_error_data[i] = 3'b000;
+ assign {tmr_core_busy_out[i], tmr_irq_ack_out[i], tmr_irq_ack_id_out[i],
+ tmr_instr_req_out[i], tmr_instr_addr_out[i], tmr_data_req_out[i],
+ tmr_data_add_out[i], tmr_data_wen_out[i], tmr_data_wdata_out[i],
+ tmr_data_be_out[i], tmr_data_user_out[i],
+ // CSRs signals
+ tmr_backup_csr[i].csr_mstatus , // 7-bits
+ tmr_backup_csr[i].csr_mie , // 32-bits
+ tmr_backup_csr[i].csr_mtvec , // 24-bits
+ tmr_backup_csr[i].csr_mscratch, // 32-bits
+ tmr_backup_csr[i].csr_mip , // 32-bits
+ tmr_backup_csr[i].csr_mepc , // 32-bits
+ tmr_backup_csr[i].csr_mcause , // 6-bits
+ // PC signals
+ tmr_backup_program_counter[i], // 32-bits
+ tmr_backup_branch_int[i], tmr_backup_branch_addr_int[i], // 1-bits + 32-bits
+ // RF signals
+ tmr_backup_regfile_wdata_a[i], // 32-bits
+ tmr_backup_regfile_waddr_a[i], // 6-bits
+ tmr_backup_regfile_wdata_b[i], // 32-bits
+ tmr_backup_regfile_waddr_b[i]} = main_tmr_out[i];
+ end
+
+ if (RapidRecovery) begin : gen_rapid_recovery_connection
+
+ bitwise_TMR_voter #(
+ .DataWidth( 1 ),
+ .VoterType( 0 )
+ ) i_voter_regfile_we_a (
+ .a_i ( backup_regfile_wport_i[tmr_core_id(i, 0)].we_a ),
+ .b_i ( backup_regfile_wport_i[tmr_core_id(i, 1)].we_a ),
+ .c_i ( backup_regfile_wport_i[tmr_core_id(i, 2)].we_a ),
+ .majority_o ( tmr_backup_regfile_we_a [i] ),
+ .error_o ( ),
+ .error_cba_o( )
+ );
+
+ bitwise_TMR_voter #(
+ .DataWidth( 1 ),
+ .VoterType( 0 )
+ ) i_voter_regfile_we_b (
+ .a_i ( backup_regfile_wport_i[tmr_core_id(i, 0)].we_b ),
+ .b_i ( backup_regfile_wport_i[tmr_core_id(i, 1)].we_b ),
+ .c_i ( backup_regfile_wport_i[tmr_core_id(i, 2)].we_b ),
+ .majority_o ( tmr_backup_regfile_we_b [i] ),
+ .error_o ( ),
+ .error_cba_o( )
+ );
+
+ end else begin : gen_standard_failure
+ assign tmr_failure [i] = tmr_data_req_out [i] ? (tmr_failure_main[i] | tmr_failure_data[i])
+ : tmr_failure_main[i];
+ end
+ end
+ end else begin : gen_no_tmr_voted
+ assign tmr_error_main = '0;
+ assign tmr_error_data = '0;
+ assign tmr_error = '0;
+ assign tmr_failure_main = '0;
+ assign tmr_failure_data = '0;
+ assign tmr_failure = '0;
+ assign main_tmr_out = '0;
+ assign data_tmr_out = '0;
+ assign {tmr_core_busy_out, tmr_irq_ack_out, tmr_irq_ack_id_out,
+ tmr_instr_req_out, tmr_instr_addr_out, tmr_data_req_out,
+ tmr_data_add_out, tmr_data_wen_out, tmr_data_wdata_out,
+ tmr_data_be_out, tmr_data_user_out} = '0;
+ assign top_register_resps[3].rdata = '0;
+ assign top_register_resps[3].error = 1'b1;
+ assign top_register_resps[3].ready = 1'b1;
+ assign tmr_incr_mismatches = '0;
+ assign tmr_grp_in_independent = '0;
+ assign tmr_setback_q = '0;
+ assign tmr_resynch_req_o = '0;
+ assign tmr_sw_synch_req_o = '0;
+ end
+
+ /************************************************************
+ ******************** DMR Voters and Regs *******************
+ ************************************************************/
+
+ if (DMRSupported || DMRFixed) begin: gen_dmr_logic
+
+ hmr_dmr_regs_reg_pkg::hmr_dmr_regs_reg2hw_t [NumDMRGroups-1:0] dmr_reg2hw;
+ hmr_dmr_regs_reg_pkg::hmr_dmr_regs_hw2reg_t [NumDMRGroups-1:0] dmr_hw2reg;
+
+ reg_req_t [NumDMRGroups-1:0] dmr_register_reqs;
+ reg_resp_t [NumDMRGroups-1:0] dmr_register_resps;
+ logic [NumDMRGroups-1:0] dmr_sw_synch_req;
+
+ localparam DMRSelWidth = $clog2(NumDMRGroups);
+
+ /***************
+ * Registers *
+ ***************/
+ reg_demux #(
+ .NoPorts ( NumDMRGroups ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_resp_t )
+ ) i_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( top_register_reqs[2].addr[4+$clog2(NumDMRGroups)-1:4] ),
+ .in_req_i ( top_register_reqs[2] ),
+ .in_rsp_o ( top_register_resps[2] ),
+ .out_req_o ( dmr_register_reqs ),
+ .out_rsp_i ( dmr_register_resps )
+ );
+
+ for (genvar i = NumDMRCores; i < NumCores; i++) begin : gen_extra_core_assigns
+ assign dmr_incr_mismatches[i] = '0;
+ assign dmr_sw_synch_req_o[i] = '0;
+ end
+
+ for (genvar i = 0; i < NumDMRGroups; i++) begin : gen_dmr_groups
+
+ hmr_dmr_ctrl #(
+ .reg_req_t ( reg_req_t ),
+ .reg_resp_t ( reg_resp_t ),
+ .InterleaveGrps( InterleaveGrps ),
+ .DMRFixed ( DMRFixed ),
+ .RapidRecovery ( RapidRecovery ),
+ .DefaultInDMR ( 1'b0 )
+ ) i_dmr_ctrl (
+ .clk_i,
+ .rst_ni,
+
+ .reg_req_i ( dmr_register_reqs [i] ),
+ .reg_resp_o ( dmr_register_resps[i] ),
+
+ .dmr_enable_q_i ( hmr_reg2hw.dmr_enable.q[i] ),
+ .dmr_enable_qe_i ( hmr_reg2hw.dmr_enable.qe ),
+ .rapid_recovery_q_i ( hmr_reg2hw.dmr_config.rapid_recovery.q ),
+ .rapid_recovery_qe_i ( hmr_reg2hw.dmr_config.rapid_recovery.qe ),
+ .force_recovery_q_i ( hmr_reg2hw.dmr_config.force_recovery.q ),
+ .force_recovery_qe_i ( hmr_reg2hw.dmr_config.force_recovery.qe ),
+
+ .setback_o ( dmr_setback_q [i] ),
+ .sw_resynch_req_o ( dmr_resynch_req_o [i] ),
+ .sw_synch_req_o ( dmr_sw_synch_req [i] ),
+ .grp_in_independent_o ( dmr_grp_in_independent[i] ),
+ .rapid_recovery_en_o ( dmr_rapid_recovery_en [i] ),
+ .dmr_incr_mismatches_o ( {dmr_incr_mismatches[dmr_core_id(i, 0)], dmr_incr_mismatches[dmr_core_id(i, 1)]} ),
+ .dmr_error_i ( dmr_failure [i] ),
+
+ .fetch_en_i ( sys_fetch_en_i[dmr_core_id(i, 0)] ),
+ .cores_synch_i ( dmr_cores_synch_i[i] ),
+
+ .recovery_request_o ( dmr_start_recovery [i] ),
+ .recovery_finished_i ( dmr_recovery_finished[i] )
+ );
+
+ assign dmr_sw_synch_req_o[dmr_core_id(i, 0)] = dmr_sw_synch_req[i];
+ assign dmr_sw_synch_req_o[dmr_core_id(i, 1)] = dmr_sw_synch_req[i];
+
+ /*********************
+ * DMR Core Checkers *
+ *********************/
+ DMR_checker #(
+ .DataWidth ( MainConcatWidth )
+ ) dmr_core_checker_main (
+ .inp_a_i ( main_concat_in [dmr_core_id(i, 0)] ),
+ .inp_b_i ( main_concat_in [dmr_core_id(i, 1)] ),
+ .check_o ( main_dmr_out [i] ),
+ .error_o ( dmr_failure_main [i] )
+ );
+ if (SeparateData) begin : gen_data_checker
+ DMR_checker # (
+ .DataWidth ( DataConcatWidth )
+ ) dmr_core_checker_data (
+ .inp_a_i ( data_concat_in [dmr_core_id(i, 0)] ),
+ .inp_b_i ( data_concat_in [dmr_core_id(i, 1)] ),
+ .check_o ( data_dmr_out [i] ),
+ .error_o ( dmr_failure_data [i] )
+ );
+ assign {dmr_core_busy_out[i], dmr_irq_ack_out[i] , dmr_irq_ack_id_out[i],
+ dmr_instr_req_out[i], dmr_instr_addr_out[i], dmr_data_req_out[i],
+ // CSRs signals
+ dmr_backup_csr[i].csr_mstatus , // 7-bits
+ dmr_backup_csr[i].csr_mie , // 32-bits
+ dmr_backup_csr[i].csr_mtvec , // 24-bits
+ dmr_backup_csr[i].csr_mscratch, // 32-bits
+ dmr_backup_csr[i].csr_mip , // 32-bits
+ dmr_backup_csr[i].csr_mepc , // 32-bits
+ dmr_backup_csr[i].csr_mcause , // 6-bits
+ // PC signals
+ dmr_backup_program_counter[i], // 32-bits
+ dmr_backup_branch_int[i], dmr_backup_branch_addr_int[i], // 1-bits + 32-bits
+ // RF signals
+ dmr_backup_regfile_wdata_a[i], // 32-bits
+ dmr_backup_regfile_waddr_a[i], // 6-bits
+ dmr_backup_regfile_wdata_b[i], // 32-bits
+ dmr_backup_regfile_waddr_b[i]} // 6-bits
+ = main_dmr_out[i];
+ assign {dmr_data_add_out[i], dmr_data_wen_out[i] , dmr_data_wdata_out[i],
+ dmr_data_be_out[i] , dmr_data_user_out[i] }
+ = data_dmr_out[i];
+ end else begin : gen_data_in_main
+ assign dmr_failure_data[i] = 1'b0;
+ assign {dmr_core_busy_out[i], dmr_irq_ack_out[i] , dmr_irq_ack_id_out[i],
+ dmr_instr_req_out[i], dmr_instr_addr_out[i], dmr_data_req_out[i] ,
+ dmr_data_add_out[i] , dmr_data_wen_out[i] , dmr_data_wdata_out[i],
+ dmr_data_be_out[i] , dmr_data_user_out[i],
+ // CSRs signals
+ dmr_backup_csr[i].csr_mstatus , // 7-bits
+ dmr_backup_csr[i].csr_mie , // 32-bits
+ dmr_backup_csr[i].csr_mtvec , // 24-bits
+ dmr_backup_csr[i].csr_mscratch, // 32-bits
+ dmr_backup_csr[i].csr_mip , // 32-bits
+ dmr_backup_csr[i].csr_mepc , // 32-bits
+ dmr_backup_csr[i].csr_mcause , // 6-bits
+ // PC signals
+ dmr_backup_program_counter[i], // 32-bits
+ dmr_backup_branch_int[i], dmr_backup_branch_addr_int[i], // 1-bits + 32-bits
+ // RF signals
+ dmr_backup_regfile_wdata_a[i], // 32-bits
+ dmr_backup_regfile_waddr_a[i], // 6-bits
+ dmr_backup_regfile_wdata_b[i], // 32-bits
+ dmr_backup_regfile_waddr_b[i]} // 6-bits
+ = main_dmr_out[i];
+ end
+
+ if (RapidRecovery) begin : gen_rapid_recovery_connection
+
+ assign dmr_failure [i] = (dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i])
+ : dmr_failure_main[i]) ;
+
+ assign dmr_backup_regfile_we_a [i] = backup_regfile_wport_i[dmr_core_id(i, 0)].we_a
+ & backup_regfile_wport_i[dmr_core_id(i, 1)].we_a
+ & ~dmr_failure [i];
+
+ assign dmr_backup_regfile_we_b [i] = backup_regfile_wport_i[dmr_core_id(i, 0)].we_b
+ & backup_regfile_wport_i[dmr_core_id(i, 1)].we_b
+ & ~dmr_failure [i];
+
+ end else begin : gen_standard_failure
+ assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i])
+ : dmr_failure_main[i];
+ end
+ end
+ end else begin: no_dmr_checkers
+ assign dmr_failure_main = '0;
+ assign dmr_failure_data = '0;
+ assign dmr_failure = '0;
+ assign dmr_incr_mismatches = '0;
+ assign main_dmr_out = '0;
+ assign data_dmr_out = '0;
+ assign {dmr_core_busy_out, dmr_irq_ack_out , dmr_irq_ack_id_out,
+ dmr_instr_req_out, dmr_instr_addr_out, dmr_data_req_out ,
+ dmr_data_add_out , dmr_data_wen_out , dmr_data_wdata_out,
+ dmr_data_be_out , dmr_data_user_out}
+ = '0;
+ assign top_register_resps[2].rdata = '0;
+ assign top_register_resps[2].error = 1'b1;
+ assign top_register_resps[2].ready = 1'b1;
+ assign dmr_sw_synch_req_o = '0;
+ end
+
+ // RapidRecovery output signals
+ if (RapidRecovery) begin : gen_rapid_recovery
+ for (genvar i = 0; i < NumBackupRegfiles; i++) begin : gen_groups
+ // Write Enable signal for backup registers
+ assign rapid_recovery_backup_enable[i] = core_in_tmr[i] ? (i < NumTMRGroups ? backup_enable[i] : 1'b0) // TMR mode
+ : core_in_dmr[i] ? (backup_enable[i] & ~dmr_failure[i] ) // DMR mode
+ : 1'b1; // Independent mode
+ // TODO: Only supports interleaved mode!!!
+
+
+
+ hmr_rapid_recovery_ctrl #(
+ .RFAddrWidth( RFAddrWidth )
+ ) i_rapid_recovery_ctrl (
+ .clk_i,
+ .rst_ni,
+ .start_recovery_i ( start_recovery [i] ),
+ .recovery_finished_o ( recovery_finished [i] ),
+ .setback_o ( recovery_setback_out [i] ),
+ .instr_lock_o ( recovery_instr_lock_out [i] ),
+ .debug_req_o ( recovery_debug_req_out [i] ),
+ .debug_halt_i ( recovery_debug_halted_in [i] ),
+ .debug_resume_o ( recovery_debug_resume_out [i] ),
+ .recovery_regfile_waddr_o ( core_recovery_regfile_wport_out[i] ),
+ .backup_enable_o ( backup_enable [i] ),
+ .recover_csr_enable_o ( recovery_csr_enable_out [i] ),
+ .recover_pc_enable_o ( recovery_pc_enable_out [i] ),
+ .recover_rf_enable_o ( recovery_trigger_out [i] )
+ );
+
+ /*************************
+ * Recovery CS Registers *
+ *************************/
+ recovery_csr #(
+ .ECCEnabled ( 1 )
+ ) RCSR (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .read_enable_i ( recovery_csr_enable_out [i] ),
+ .write_enable_i ( rapid_recovery_backup_enable [i] ),
+ .backup_csr_i ( backup_csr_int [i] ),
+ .recovery_csr_o ( recovery_csr_out [i] )
+ );
+
+ /****************************
+ * Recovery Program Counter *
+ ****************************/
+ recovery_pc #(
+ .ECCEnabled ( 1 )
+ ) RPC (
+ // Control Ports
+ .clk_i,
+ .rst_ni,
+ .clear_i ( '0 ),
+ .read_enable_i ( recovery_pc_enable_out [i] ),
+ .write_enable_i ( rapid_recovery_backup_enable [i] ),
+ // Backup Ports
+ .backup_program_counter_i ( backup_program_counter_int [i] ),
+ .backup_branch_i ( backup_branch_int [i] ),
+ .backup_branch_addr_i ( backup_branch_addr_int [i] ),
+ // Recovery Pors
+ .recovery_program_counter_o ( recovery_program_counter_out [i] ),
+ .recovery_branch_o ( recovery_branch_out [i] ),
+ .recovery_branch_addr_o ( recovery_branch_addr_out [i] )
+ );
+
+ /***************************
+ * Recovery Register Files *
+ ***************************/
+ recovery_rf #(
+ .ECCEnabled ( 1 ),
+ .ADDR_WIDTH ( RFAddrWidth )
+ ) RRF (
+ .clk_i,
+ .rst_ni,
+ .test_en_i ( '0 ),
+ //Read port A
+ .raddr_a_i ( core_recovery_regfile_wport_out[i].waddr_a ),
+ .rdata_a_o ( core_recovery_regfile_rdata_out[i].rdata_a ),
+ //Read port B
+ .raddr_b_i ( core_recovery_regfile_wport_out[i].waddr_b ),
+ .rdata_b_o ( core_recovery_regfile_rdata_out[i].rdata_b ),
+ //Read port C
+ .raddr_c_i ( '0 ),
+ .rdata_c_o ( ),
+ // Write Port A
+ .waddr_a_i ( backup_regfile_waddr_a [i] ),
+ .wdata_a_i ( backup_regfile_wdata_a [i] ),
+ .we_a_i ( backup_regfile_we_a[i] &
+ rapid_recovery_backup_enable [i] ),
+ // Write Port B
+ .waddr_b_i ( backup_regfile_waddr_b [i] ),
+ .wdata_b_i ( backup_regfile_wdata_b [i] ),
+ .we_b_i ( backup_regfile_we_b[i] &
+ rapid_recovery_backup_enable [i] )
+ );
+
+ end
+
+ always_comb begin : proc_dmr_tmr_assignments
+ backup_csr_int = '0;
+ backup_program_counter_int = '0;
+ backup_program_counter_error = '0;
+ backup_branch_int = '0;
+ backup_branch_addr_int = '0;
+ backup_regfile_wdata_a = '0;
+ backup_regfile_wdata_b = '0;
+ backup_regfile_we_a = '0;
+ backup_regfile_we_b = '0;
+ backup_regfile_waddr_a = '0;
+ backup_regfile_waddr_b = '0;
+ start_recovery = '0;
+ dmr_recovery_finished = '0;
+ tmr_recovery_finished = '0;
+ recovery_debug_halted_in = '0;
+
+ // Continually backup master cores in interleaved mode for fast entry
+ if (InterleaveGrps) begin
+ for (int i = 0; i < NumBackupRegfiles; i++) begin
+ backup_csr_int [i] = backup_csr_i [i];
+ backup_program_counter_int [i] = backup_program_counter_i [i];
+ backup_branch_int [i] = backup_branch_i [i];
+ backup_branch_addr_int [i] = backup_branch_addr_i [i];
+ backup_regfile_wdata_a [i] = backup_regfile_wport_i[i].wdata_a;
+ backup_regfile_wdata_b [i] = backup_regfile_wport_i[i].wdata_b;
+ backup_regfile_we_a [i] = backup_regfile_wport_i[i].we_a;
+ backup_regfile_we_b [i] = backup_regfile_wport_i[i].we_b;
+ backup_regfile_waddr_a [i] = backup_regfile_wport_i[i].waddr_a;
+ backup_regfile_waddr_b [i] = backup_regfile_wport_i[i].waddr_b;
+ end
+ end
+
+ for (int i = 0; i < NumDMRGroups; i++) begin
+ if ((DMRFixed || (DMRSupported && ~dmr_grp_in_independent[i])) && dmr_core_rapid_recovery_en[dmr_core_id(i, 0)]) begin
+ backup_csr_int [dmr_shared_id(i)] = dmr_backup_csr [i];
+ backup_program_counter_int [dmr_shared_id(i)] = dmr_backup_program_counter [i];
+ // backup_program_counter_error[dmr_shared_id(i)] = dmr_backup_program_counter_error[i];
+ backup_branch_int [dmr_shared_id(i)] = dmr_backup_branch_int [i];
+ backup_branch_addr_int [dmr_shared_id(i)] = dmr_backup_branch_addr_int [i];
+ backup_regfile_wdata_a [dmr_shared_id(i)] = dmr_backup_regfile_wdata_a [i];
+ backup_regfile_wdata_b [dmr_shared_id(i)] = dmr_backup_regfile_wdata_b [i];
+ backup_regfile_we_a [dmr_shared_id(i)] = dmr_backup_regfile_we_a [i];
+ backup_regfile_we_b [dmr_shared_id(i)] = dmr_backup_regfile_we_b [i];
+ backup_regfile_waddr_a [dmr_shared_id(i)] = dmr_backup_regfile_waddr_a [i];
+ backup_regfile_waddr_b [dmr_shared_id(i)] = dmr_backup_regfile_waddr_b [i];
+ start_recovery [dmr_shared_id(i)] = dmr_start_recovery [i];
+ dmr_recovery_finished[i] = recovery_finished[dmr_shared_id(i)];
+ recovery_debug_halted_in [dmr_shared_id(i)] = core_debug_halted_i [dmr_core_id(dmr_group_id(i), 0)]
+ & core_debug_halted_i [dmr_core_id(dmr_group_id(i), 1)];
+ end
+ end
+
+ for (int i = 0; i < NumTMRGroups; i++) begin
+ if ((TMRFixed || (TMRSupported && ~tmr_grp_in_independent[i])) && tmr_core_rapid_recovery_en[tmr_core_id(i, 0)]) begin
+ backup_csr_int [tmr_shared_id(i)] = tmr_backup_csr [i];
+ backup_program_counter_int [tmr_shared_id(i)] = tmr_backup_program_counter [i];
+ backup_branch_int [tmr_shared_id(i)] = tmr_backup_branch_int [i];
+ backup_branch_addr_int [tmr_shared_id(i)] = tmr_backup_branch_addr_int [i];
+ backup_regfile_wdata_a [tmr_shared_id(i)] = tmr_backup_regfile_wdata_a [i];
+ backup_regfile_wdata_b [tmr_shared_id(i)] = tmr_backup_regfile_wdata_b [i];
+ backup_regfile_we_a [tmr_shared_id(i)] = tmr_backup_regfile_we_a [i];
+ backup_regfile_we_b [tmr_shared_id(i)] = tmr_backup_regfile_we_b [i];
+ backup_regfile_waddr_a [tmr_shared_id(i)] = tmr_backup_regfile_waddr_a [i];
+ backup_regfile_waddr_b [tmr_shared_id(i)] = tmr_backup_regfile_waddr_b [i];
+ start_recovery [tmr_shared_id(i)] = tmr_start_recovery [i];
+ tmr_recovery_finished[i] = recovery_finished[tmr_shared_id(i)];
+ recovery_debug_halted_in [tmr_shared_id(i)] = core_debug_halted_i [tmr_core_id(tmr_group_id(i), 0)]
+ & core_debug_halted_i [tmr_core_id(tmr_group_id(i), 1)]
+ & core_debug_halted_i [tmr_core_id(tmr_group_id(i), 2)];
+ end
+ end
+ end
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_cores
+ always_comb begin
+ if ((DMRFixed || (DMRSupported && core_in_dmr[i])) && dmr_core_rapid_recovery_en[i]) begin
+
+ core_debug_resume_o [i] = recovery_debug_resume_out [dmr_shared_id(dmr_group_id(i))];
+
+ // Setback
+ core_recover_o [i] = recovery_trigger_out [dmr_shared_id(dmr_group_id(i))];
+ core_instr_lock_o [i] = recovery_instr_lock_out [dmr_shared_id(dmr_group_id(i))];
+
+ // CSRs
+ recovery_csr_o [i] = recovery_csr_out [dmr_shared_id(dmr_group_id(i))];
+
+ // PC
+ pc_recover_o [i] = recovery_pc_enable_out [dmr_shared_id(dmr_group_id(i))];
+ recovery_program_counter_o [i] = recovery_program_counter_out [dmr_shared_id(dmr_group_id(i))];
+ recovery_branch_o [i] = recovery_branch_out [dmr_shared_id(dmr_group_id(i))];
+ recovery_branch_addr_o [i] = recovery_branch_addr_out [dmr_shared_id(dmr_group_id(i))];
+
+ // RF
+ core_recovery_regfile_wport_o[i].we_a = core_recovery_regfile_wport_out[dmr_shared_id(dmr_group_id(i))].we_a;
+ core_recovery_regfile_wport_o[i].waddr_a = core_recovery_regfile_wport_out[dmr_shared_id(dmr_group_id(i))].waddr_a;
+ core_recovery_regfile_wport_o[i].wdata_a = core_recovery_regfile_rdata_out[dmr_shared_id(dmr_group_id(i))].rdata_a;
+ core_recovery_regfile_wport_o[i].we_b = core_recovery_regfile_wport_out[dmr_shared_id(dmr_group_id(i))].we_b;
+ core_recovery_regfile_wport_o[i].waddr_b = core_recovery_regfile_wport_out[dmr_shared_id(dmr_group_id(i))].waddr_b;
+ core_recovery_regfile_wport_o[i].wdata_b = core_recovery_regfile_rdata_out[dmr_shared_id(dmr_group_id(i))].rdata_b;
+
+ end else if ((TMRFixed || (TMRSupported && core_in_tmr[i])) && tmr_core_rapid_recovery_en[i]) begin
+ core_debug_resume_o [i] = recovery_debug_resume_out [tmr_shared_id(tmr_group_id(i))];
+
+ // Setback
+ core_recover_o [i] = recovery_trigger_out [tmr_shared_id(tmr_group_id(i))];
+ core_instr_lock_o [i] = recovery_instr_lock_out [tmr_shared_id(tmr_group_id(i))];
+
+ // CSRs
+ recovery_csr_o [i] = recovery_csr_out [tmr_shared_id(tmr_group_id(i))];
+
+ // PC
+ pc_recover_o [i] = recovery_pc_enable_out [tmr_shared_id(tmr_group_id(i))];
+ recovery_program_counter_o [i] = recovery_program_counter_out [tmr_shared_id(tmr_group_id(i))];
+ recovery_branch_o [i] = recovery_branch_out [tmr_shared_id(tmr_group_id(i))];
+ recovery_branch_addr_o [i] = recovery_branch_addr_out [tmr_shared_id(tmr_group_id(i))];
+
+ // RF
+ // core_regfile_raddr_o [i] = core_regfile_raddr_out [tmr_shared_id(tmr_group_id(i))];
+ core_recovery_regfile_wport_o[i].we_a = core_recovery_regfile_wport_out[tmr_shared_id(tmr_group_id(i))].we_a;
+ core_recovery_regfile_wport_o[i].waddr_a = core_recovery_regfile_wport_out[tmr_shared_id(tmr_group_id(i))].waddr_a;
+ core_recovery_regfile_wport_o[i].wdata_a = core_recovery_regfile_rdata_out[tmr_shared_id(tmr_group_id(i))].rdata_a;
+ core_recovery_regfile_wport_o[i].we_b = core_recovery_regfile_wport_out[tmr_shared_id(tmr_group_id(i))].we_b;
+ core_recovery_regfile_wport_o[i].waddr_b = core_recovery_regfile_wport_out[tmr_shared_id(tmr_group_id(i))].waddr_b;
+ core_recovery_regfile_wport_o[i].wdata_b = core_recovery_regfile_rdata_out[tmr_shared_id(tmr_group_id(i))].rdata_b;
+
+ end else begin
+ // Disable RapidRecovery
+ core_debug_resume_o [i] = '0;
+
+ // Setback
+ core_recover_o [i] = '0;
+ core_instr_lock_o [i] = '0;
+
+ // CSRs
+ recovery_csr_o [i] = '0;
+
+ // PC
+ pc_recover_o [i] = '0;
+ recovery_program_counter_o [i] = '0;
+ recovery_branch_o [i] = '0;
+ recovery_branch_addr_o [i] = '0;
+
+ // RF
+ core_recovery_regfile_wport_o[i].we_a = '0;
+ core_recovery_regfile_wport_o[i].waddr_a = '0;
+ core_recovery_regfile_wport_o[i].wdata_a = '0;
+ core_recovery_regfile_wport_o[i].we_b = '0;
+ core_recovery_regfile_wport_o[i].waddr_b = '0;
+ core_recovery_regfile_wport_o[i].wdata_b = '0;
+ end
+ end
+ end
+
+ end else begin : gen_sw_recovery
+ for (genvar i = 0; i < NumCores; i++) begin : gen_cores
+ // Disable RapidRecovery
+ assign core_debug_resume_o [i] = '0;
+
+ // Setback
+ assign core_recover_o [i] = '0;
+ assign core_instr_lock_o [i] = '0;
+
+ // CSRs
+ assign recovery_csr_o [i] = '0;
+
+ // PC
+ assign pc_recover_o [i] = '0;
+ assign recovery_program_counter_o [i] = '0;
+ assign recovery_branch_o [i] = '0;
+ assign recovery_branch_addr_o [i] = '0;
+
+ // RF
+ assign core_recovery_regfile_wport_o[i].we_a = '0;
+ assign core_recovery_regfile_wport_o[i].waddr_a = '0;
+ assign core_recovery_regfile_wport_o[i].wdata_a = '0;
+ assign core_recovery_regfile_wport_o[i].we_b = '0;
+ assign core_recovery_regfile_wport_o[i].waddr_b = '0;
+ assign core_recovery_regfile_wport_o[i].wdata_b = '0;
+ end
+ end
+
+ // Assign output signals
+ if (DMRSupported && TMRSupported) begin : gen_full_HMR
+ /*****************
+ *** TMR & DMR ***
+ *****************/
+ if (TMRFixed || DMRFixed) $fatal(1, "Cannot support both TMR and DMR and fix one!");
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs
+ localparam TMRCoreIndex = tmr_core_id(tmr_group_id(i), 0);
+ localparam DMRCoreIndex = dmr_core_id(dmr_group_id(i), 0);
+
+ always_comb begin
+ // Special signals
+ if (RapidRecovery) begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]
+ | dmr_setback_q [dmr_group_id(i)][dmr_offset_id(i)]
+ | (core_in_dmr[i] ? recovery_setback_out [dmr_shared_id(dmr_group_id(i))] :
+ (core_in_tmr[i] ? recovery_setback_out [tmr_shared_id(tmr_group_id(i))] : '0));
+ end else begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]
+ | dmr_setback_q [dmr_group_id(i)][dmr_offset_id(i)];
+ end
+ if (i >= NumTMRCores && i >= NumDMRCores) begin
+ core_setback_o [i] = '0;
+ end else if (i < NumTMRCores && i >= NumDMRCores) begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]
+ | (RapidRecovery ? (core_in_tmr[i] ? recovery_setback_out [tmr_shared_id(tmr_group_id(i))] : '0) : '0);
+ end else if (i >= NumTMRCores && i < NumDMRCores) begin
+ core_setback_o [i] = dmr_setback_q [dmr_group_id(i)][dmr_offset_id(i)]
+ | (RapidRecovery ? (core_in_dmr[i] ? recovery_setback_out [dmr_shared_id(dmr_group_id(i))] : '0) : '0);
+ end
+ if (i < NumTMRCores && core_in_tmr[i]) begin : tmr_mode
+ // CTRL
+ core_core_id_o [i] = sys_core_id_i [TMRCoreIndex];
+ core_cluster_id_o [i] = sys_cluster_id_i [TMRCoreIndex];
+
+ core_clock_en_o [i] = sys_clock_en_i [TMRCoreIndex];
+ core_fetch_en_o [i] = sys_fetch_en_i [TMRCoreIndex];
+ core_boot_addr_o [i] = sys_boot_addr_i [TMRCoreIndex];
+
+ if (RapidRecovery) begin
+ core_debug_req_o [i] = sys_debug_req_i [TMRCoreIndex]
+ | recovery_debug_req_out [tmr_shared_id(tmr_group_id(i))];
+ end else begin
+ core_debug_req_o [i] = sys_debug_req_i [TMRCoreIndex];
+ end
+ core_perf_counters_o[i] = sys_perf_counters_i[TMRCoreIndex];
+
+ // IRQ
+ core_irq_req_o [i] = sys_irq_req_i [TMRCoreIndex];
+ core_irq_id_o [i] = sys_irq_id_i [TMRCoreIndex];
+
+ // INSTR
+ core_instr_gnt_o [i] = filt_instr_gnt [TMRCoreIndex];
+ core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[TMRCoreIndex];
+ core_instr_r_valid_o[i] = filt_instr_r_valid[TMRCoreIndex];
+ core_instr_err_o [i] = sys_instr_err_i [TMRCoreIndex];
+
+ // DATA
+ core_data_gnt_o [i] = filt_data_gnt [TMRCoreIndex];
+ core_data_r_opc_o [i] = sys_data_r_opc_i [TMRCoreIndex];
+ core_data_r_rdata_o [i] = sys_data_r_rdata_i [TMRCoreIndex];
+ core_data_r_user_o [i] = sys_data_r_user_i [TMRCoreIndex];
+ core_data_r_valid_o [i] = filt_data_r_valid [TMRCoreIndex];
+ core_data_err_o [i] = sys_data_err_i [TMRCoreIndex];
+ end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode
+ // CTRL
+ core_core_id_o [i] = sys_core_id_i [DMRCoreIndex];
+ core_cluster_id_o [i] = sys_cluster_id_i [DMRCoreIndex];
+
+ core_clock_en_o [i] = sys_clock_en_i [DMRCoreIndex];
+ core_fetch_en_o [i] = sys_fetch_en_i [DMRCoreIndex];
+ core_boot_addr_o [i] = sys_boot_addr_i [DMRCoreIndex];
+
+ if (RapidRecovery) begin
+ core_debug_req_o [i] = sys_debug_req_i [DMRCoreIndex]
+ | recovery_debug_req_out [dmr_shared_id(dmr_group_id(i))];
+ end else begin
+ core_debug_req_o [i] = sys_debug_req_i [DMRCoreIndex];
+ end
+ core_perf_counters_o[i] = sys_perf_counters_i[DMRCoreIndex];
+
+ // IRQ
+ core_irq_req_o [i] = sys_irq_req_i [DMRCoreIndex];
+ core_irq_id_o [i] = sys_irq_id_i [DMRCoreIndex];
+
+ // INSTR
+ core_instr_gnt_o [i] = filt_instr_gnt [DMRCoreIndex];
+ core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[DMRCoreIndex];
+ core_instr_r_valid_o[i] = filt_instr_r_valid[DMRCoreIndex];
+ core_instr_err_o [i] = sys_instr_err_i [DMRCoreIndex];
+
+ // DATA
+ core_data_gnt_o [i] = filt_data_gnt [DMRCoreIndex];
+ core_data_r_opc_o [i] = sys_data_r_opc_i [DMRCoreIndex];
+ core_data_r_rdata_o [i] = sys_data_r_rdata_i [DMRCoreIndex];
+ core_data_r_user_o [i] = sys_data_r_user_i [DMRCoreIndex];
+ core_data_r_valid_o [i] = filt_data_r_valid [DMRCoreIndex];
+ core_data_err_o [i] = sys_data_err_i [DMRCoreIndex];
+ end else begin : independent_mode
+ // CTRL
+ core_core_id_o [i] = sys_core_id_i [i];
+ core_cluster_id_o [i] = sys_cluster_id_i [i];
+
+ core_clock_en_o [i] = sys_clock_en_i [i];
+ core_fetch_en_o [i] = sys_fetch_en_i [i];
+ core_boot_addr_o [i] = sys_boot_addr_i [i];
+
+ core_debug_req_o [i] = sys_debug_req_i [i];
+ core_perf_counters_o[i] = sys_perf_counters_i[i];
+
+ // IRQ
+ core_irq_req_o [i] = sys_irq_req_i [i];
+ core_irq_id_o [i] = sys_irq_id_i [i];
+
+ // INSTR
+ core_instr_gnt_o [i] = filt_instr_gnt [i];
+ core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i];
+ core_instr_r_valid_o[i] = filt_instr_r_valid[i];
+ core_instr_err_o [i] = sys_instr_err_i [i];
+
+ // DATA
+ core_data_gnt_o [i] = filt_data_gnt [i];
+ core_data_r_opc_o [i] = sys_data_r_opc_i [i];
+ core_data_r_rdata_o [i] = sys_data_r_rdata_i [i];
+ core_data_r_user_o [i] = sys_data_r_user_i [i];
+ core_data_r_valid_o [i] = filt_data_r_valid [i];
+ core_data_err_o [i] = sys_data_err_i [i];
+ end
+ end
+ end
+
+ for (genvar i = 0; i < NumSysCores/*==NumCores*/; i++) begin : gen_core_outputs
+ localparam TMRCoreIndex = tmr_group_id(i);
+ localparam DMRCoreIndex = dmr_group_id(i);
+ always_comb begin
+ if (i < NumTMRCores && core_in_tmr[i]) begin : tmr_mode
+ if (tmr_core_id(tmr_group_id(i), 0) == i) begin : is_tmr_main_core
+ // CTRL
+ sys_core_busy_o [i] = tmr_core_busy_out [TMRCoreIndex];
+
+ // IRQ
+ sys_irq_ack_o [i] = tmr_irq_ack_out [TMRCoreIndex];
+ sys_irq_ack_id_o [i] = tmr_irq_ack_id_out[TMRCoreIndex];
+
+ // INSTR
+ filt_instr_req [i] = tmr_instr_req_out [TMRCoreIndex];
+ filt_instr_addr [i] = tmr_instr_addr_out[TMRCoreIndex];
+
+ // DATA
+ filt_data_req [i] = tmr_data_req_out [TMRCoreIndex];
+ filt_data_addr [i] = tmr_data_add_out [TMRCoreIndex];
+ filt_data_we [i] = tmr_data_wen_out [TMRCoreIndex];
+ filt_data_data [i] = tmr_data_wdata_out[TMRCoreIndex];
+ sys_data_user_o [i] = tmr_data_user_out [TMRCoreIndex];
+ filt_data_be [i] = tmr_data_be_out [TMRCoreIndex];
+ end else begin : disable_core // Assign disable
+ // CTLR
+ sys_core_busy_o [i] = '0;
+
+ // IRQ
+ sys_irq_ack_o [i] = '0;
+ sys_irq_ack_id_o [i] = '0;
+
+ // INSTR
+ filt_instr_req [i] = '0;
+ filt_instr_addr [i] = '0;
+
+ // DATA
+ filt_data_req [i] = '0;
+ filt_data_addr [i] = '0;
+ filt_data_we [i] = '0;
+ filt_data_data [i] = '0;
+ sys_data_user_o [i] = '0;
+ filt_data_be [i] = '0;
+ end
+ end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode
+ if (dmr_core_id(dmr_group_id(i), 0) == i) begin : is_dmr_main_core
+ // CTRL
+ sys_core_busy_o [i] = dmr_core_busy_out [DMRCoreIndex];
+
+ // IRQ
+ sys_irq_ack_o [i] = dmr_irq_ack_out [DMRCoreIndex];
+ sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[DMRCoreIndex];
+
+ // INSTR
+ filt_instr_req [i] = dmr_instr_req_out [DMRCoreIndex];
+ filt_instr_addr [i] = dmr_instr_addr_out[DMRCoreIndex];
+
+ // DATA
+ filt_data_req [i] = dmr_data_req_out [DMRCoreIndex];
+ filt_data_addr [i] = dmr_data_add_out [DMRCoreIndex];
+ filt_data_we [i] = dmr_data_wen_out [DMRCoreIndex];
+ filt_data_data [i] = dmr_data_wdata_out[DMRCoreIndex];
+ sys_data_user_o [i] = dmr_data_user_out [DMRCoreIndex];
+ filt_data_be [i] = dmr_data_be_out [DMRCoreIndex];
+ end else begin : disable_core // Assign disable
+ // CTLR
+ sys_core_busy_o [i] = '0;
+
+ // IRQ
+ sys_irq_ack_o [i] = '0;
+ sys_irq_ack_id_o [i] = '0;
+
+ // INSTR
+ filt_instr_req [i] = '0;
+ filt_instr_addr [i] = '0;
+
+ // DATA
+ filt_data_req [i] = '0;
+ filt_data_addr [i] = '0;
+ filt_data_we [i] = '0;
+ filt_data_data [i] = '0;
+ sys_data_user_o [i] = '0;
+ filt_data_be [i] = '0;
+ end
+ end else begin : independent_mode
+ // CTRL
+ sys_core_busy_o [i] = core_core_busy_i [i];
+
+ // IRQ
+ sys_irq_ack_o [i] = core_irq_ack_i [i];
+ sys_irq_ack_id_o [i] = core_irq_ack_id_i[i];
+
+ // INSTR
+ filt_instr_req [i] = core_instr_req_i [i];
+ filt_instr_addr [i] = core_instr_addr_i[i];
+
+ // DATA
+ filt_data_req [i] = core_data_req_i [i];
+ filt_data_addr [i] = core_data_add_i [i];
+ filt_data_we [i] = core_data_wen_i [i];
+ filt_data_data [i] = core_data_wdata_i[i];
+ sys_data_user_o [i] = core_data_user_i [i];
+ filt_data_be [i] = core_data_be_i [i];
+ end
+ end
+ end
+
+ end else if (TMRSupported || TMRFixed) begin : gen_TMR_only
+ /*****************
+ *** TMR only ***
+ *****************/
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs
+ localparam SysCoreIndex = TMRFixed ? i/3 : tmr_core_id(tmr_group_id(i), 0);
+ always_comb begin
+ // Special signals
+ // Setback
+ if (RapidRecovery) begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]
+ | recovery_setback_out [tmr_shared_id(tmr_group_id(i))];
+ end else begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)];
+ end
+ if (i >= NumTMRCores) begin
+ core_setback_o [i] = '0;
+ end
+ if (i < NumTMRCores && (TMRFixed || core_in_tmr[i])) begin : tmr_mode
+ // CTRL
+ core_core_id_o [i] = sys_core_id_i [SysCoreIndex];
+ core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex];
+
+ core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex];
+ core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex];
+ core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex];
+
+ if (RapidRecovery) begin
+ core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex]
+ | recovery_debug_req_out [tmr_shared_id(tmr_group_id(i))];
+ end else begin
+ core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex];
+ end
+ core_perf_counters_o[i] = sys_perf_counters_i[SysCoreIndex];
+
+ // IRQ
+ core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex];
+ core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex];
+
+ // INSTR
+ core_instr_gnt_o [i] = filt_instr_gnt [SysCoreIndex];
+ core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[SysCoreIndex];
+ core_instr_r_valid_o[i] = filt_instr_r_valid[SysCoreIndex];
+ core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex];
+
+ // DATA
+ core_data_gnt_o [i] = filt_data_gnt [SysCoreIndex];
+ core_data_r_opc_o [i] = sys_data_r_opc_i [SysCoreIndex];
+ core_data_r_rdata_o [i] = sys_data_r_rdata_i [SysCoreIndex];
+ core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex];
+ core_data_r_valid_o [i] = filt_data_r_valid [SysCoreIndex];
+ core_data_err_o [i] = sys_data_err_i [SysCoreIndex];
+ end else begin : independent_mode
+ // CTRL
+ core_core_id_o [i] = sys_core_id_i [i];
+ core_cluster_id_o [i] = sys_cluster_id_i [i];
+
+ core_clock_en_o [i] = sys_clock_en_i [i];
+ core_fetch_en_o [i] = sys_fetch_en_i [i];
+ core_boot_addr_o [i] = sys_boot_addr_i [i];
+
+ core_debug_req_o [i] = sys_debug_req_i [i];
+ core_perf_counters_o[i] = sys_perf_counters_i[i];
+
+ // IRQ
+ core_irq_req_o [i] = sys_irq_req_i [i];
+ core_irq_id_o [i] = sys_irq_id_i [i];
+
+ // INSTR
+ core_instr_gnt_o [i] = filt_instr_gnt [i];
+ core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i];
+ core_instr_r_valid_o[i] = filt_instr_r_valid[i];
+ core_instr_err_o [i] = sys_instr_err_i [i];
+
+ // DATA
+ core_data_gnt_o [i] = filt_data_gnt [i];
+ core_data_r_opc_o [i] = sys_data_r_opc_i [i];
+ core_data_r_rdata_o [i] = sys_data_r_rdata_i [i];
+ core_data_r_user_o [i] = sys_data_r_user_i [i];
+ core_data_r_valid_o [i] = filt_data_r_valid [i];
+ core_data_err_o [i] = sys_data_err_i [i];
+ end
+ end
+ end
+
+ for (genvar i = 0; i < NumSysCores; i++) begin : gen_core_outputs
+ localparam CoreCoreIndex = TMRFixed ? i : tmr_group_id(i);
+ if (TMRFixed && i < NumTMRGroups) begin : fixed_tmr
+ // CTRL
+ assign sys_core_busy_o [i] = tmr_core_busy_out[CoreCoreIndex];
+
+ // IRQ
+ assign sys_irq_ack_o [i] = tmr_irq_ack_out [CoreCoreIndex];
+ assign sys_irq_ack_id_o [i] = tmr_irq_ack_id_out[CoreCoreIndex];
+
+ // INSTR
+ assign filt_instr_req [i] = tmr_instr_req_out [CoreCoreIndex];
+ assign filt_instr_addr [i] = tmr_instr_addr_out[CoreCoreIndex];
+
+ // DATA
+ assign filt_data_req [i] = tmr_data_req_out [CoreCoreIndex];
+ assign filt_data_addr [i] = tmr_data_add_out [CoreCoreIndex];
+ assign filt_data_we [i] = tmr_data_wen_out [CoreCoreIndex];
+ assign filt_data_data [i] = tmr_data_wdata_out[CoreCoreIndex];
+ assign sys_data_user_o [i] = tmr_data_user_out [CoreCoreIndex];
+ assign filt_data_be [i] = tmr_data_be_out [CoreCoreIndex];
+ end else begin
+ if (i >= NumTMRCores) begin : independent_stragglers
+ // CTRL
+ assign sys_core_busy_o [i] = core_core_busy_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+
+ // IRQ
+ assign sys_irq_ack_o [i] = core_irq_ack_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+
+ // INSTR
+ assign filt_instr_req [i] = core_instr_req_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_instr_addr [i] = core_instr_addr_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+
+ // DATA
+ assign filt_data_req [i] = core_data_req_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_addr [i] = core_data_add_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_we [i] = core_data_wen_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_data [i] = core_data_wdata_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign sys_data_user_o [i] = core_data_user_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_be [i] = core_data_be_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ end else begin
+ always_comb begin
+ if (core_in_tmr[i]) begin : tmr_mode
+ if (tmr_core_id(tmr_group_id(i), 0) == i) begin : is_tmr_main_core
+ // CTRL
+ sys_core_busy_o [i] = tmr_core_busy_out[CoreCoreIndex];
+
+ // IRQ
+ sys_irq_ack_o [i] = tmr_irq_ack_out [CoreCoreIndex];
+ sys_irq_ack_id_o [i] = tmr_irq_ack_id_out[CoreCoreIndex];
+
+ // INSTR
+ filt_instr_req [i] = tmr_instr_req_out [CoreCoreIndex];
+ filt_instr_addr [i] = tmr_instr_addr_out[CoreCoreIndex];
+
+ // DATA
+ filt_data_req [i] = tmr_data_req_out [CoreCoreIndex];
+ filt_data_addr [i] = tmr_data_add_out [CoreCoreIndex];
+ filt_data_we [i] = tmr_data_wen_out [CoreCoreIndex];
+ filt_data_data [i] = tmr_data_wdata_out[CoreCoreIndex];
+ sys_data_user_o [i] = tmr_data_user_out [CoreCoreIndex];
+ filt_data_be [i] = tmr_data_be_out [CoreCoreIndex];
+ end else begin : disable_core // Assign disable
+ // CTLR
+ sys_core_busy_o [i] = '0;
+
+ // IRQ
+ sys_irq_ack_o [i] = '0;
+ sys_irq_ack_id_o [i] = '0;
+
+ // INSTR
+ filt_instr_req [i] = '0;
+ filt_instr_addr [i] = '0;
+
+ // DATA
+ filt_data_req [i] = '0;
+ filt_data_addr [i] = '0;
+ filt_data_we [i] = '0;
+ filt_data_data [i] = '0;
+ sys_data_user_o [i] = '0;
+ filt_data_be [i] = '0;
+ end
+ end else begin : independent_mode
+ // CTRL
+ sys_core_busy_o [i] = core_core_busy_i [i];
+
+ // IRQ
+ sys_irq_ack_o [i] = core_irq_ack_i [i];
+ sys_irq_ack_id_o [i] = core_irq_ack_id_i[i];
+
+ // INSTR
+ filt_instr_req [i] = core_instr_req_i [i];
+ filt_instr_addr [i] = core_instr_addr_i[i];
+
+ // DATA
+ filt_data_req [i] = core_data_req_i [i];
+ filt_data_addr [i] = core_data_add_i [i];
+ filt_data_we [i] = core_data_wen_i [i];
+ filt_data_data [i] = core_data_wdata_i[i];
+ sys_data_user_o [i] = core_data_user_i [i];
+ filt_data_be [i] = core_data_be_i [i];
+ end
+ end
+ end
+ end
+ end
+
+ end else if (DMRSupported || DMRFixed) begin : gen_DMR_only
+ /*****************
+ *** DMR only ***
+ *****************/
+ if (DMRFixed && NumCores % 2 != 0) $warning("Extra cores added not properly handled! :)");
+ // Binding DMR outputs to zero for now
+ assign dmr_failure_o = '0;
+ assign dmr_error_o = '0;
+ // assign dmr_resynch_req_o = '0;
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs
+ localparam SysCoreIndex = DMRFixed ? i/2 : dmr_core_id(dmr_group_id(i), 0);
+ always_comb begin
+ // Setback
+ if (RapidRecovery) begin
+ core_setback_o [i] = dmr_setback_q[dmr_group_id(i)][dmr_offset_id(i)]
+ | recovery_setback_out [dmr_shared_id(dmr_group_id(i))];
+ end else begin
+ core_setback_o [i] = '0;
+ end
+ if (i >= NumDMRCores) begin
+ core_setback_o [i] = '0;
+ end
+ if (i < NumDMRCores && (DMRFixed || core_in_dmr[i])) begin : dmr_mode
+ // CTRL
+ core_core_id_o [i] = sys_core_id_i [SysCoreIndex];
+ core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex];
+
+ core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex];
+ core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex];
+ core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex];
+
+ if (RapidRecovery) begin
+ core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex]
+ | recovery_debug_req_out [dmr_shared_id(dmr_group_id(i))];
+ end else begin
+ core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex];
+ end
+ core_perf_counters_o[i] = sys_perf_counters_i [SysCoreIndex];
+
+ // IRQ
+ core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex];
+ core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex];
+
+ // INSTR
+ core_instr_gnt_o [i] = filt_instr_gnt [SysCoreIndex];
+ core_instr_r_rdata_o[i] = sys_instr_r_rdata_i [SysCoreIndex];
+ core_instr_r_valid_o[i] = filt_instr_r_valid [SysCoreIndex];
+ core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex];
+
+ // DATA
+ core_data_gnt_o [i] = filt_data_gnt [SysCoreIndex];
+ core_data_r_opc_o [i] = sys_data_r_opc_i [SysCoreIndex];
+ core_data_r_rdata_o [i] = sys_data_r_rdata_i [SysCoreIndex];
+ core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex];
+ core_data_r_valid_o [i] = filt_data_r_valid [SysCoreIndex];
+ core_data_err_o [i] = sys_data_err_i [SysCoreIndex];
+ end else begin : gen_independent_mode
+ // CTRL
+ core_core_id_o [i] = sys_core_id_i [i];
+ core_cluster_id_o [i] = sys_cluster_id_i [i];
+
+ core_clock_en_o [i] = sys_clock_en_i [i];
+ core_fetch_en_o [i] = sys_fetch_en_i [i];
+ core_boot_addr_o [i] = sys_boot_addr_i [i];
+
+ core_debug_req_o [i] = sys_debug_req_i [i];
+ core_perf_counters_o[i] = sys_perf_counters_i[i];
+
+ // IRQ
+ core_irq_req_o [i] = sys_irq_req_i [i];
+ core_irq_id_o [i] = sys_irq_id_i [i];
+
+ // INSTR
+ core_instr_gnt_o [i] = filt_instr_gnt [i];
+ core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i];
+ core_instr_r_valid_o[i] = filt_instr_r_valid[i];
+ core_instr_err_o [i] = sys_instr_err_i [i];
+
+ // DATA
+ core_data_gnt_o [i] = filt_data_gnt [i];
+ core_data_r_opc_o [i] = sys_data_r_opc_i [i];
+ core_data_r_rdata_o [i] = sys_data_r_rdata_i [i];
+ core_data_r_user_o [i] = sys_data_r_user_i [i];
+ core_data_r_valid_o [i] = filt_data_r_valid [i];
+ core_data_err_o [i] = sys_data_err_i [i];
+ end
+ end
+ end // gen_core_inputs
+
+ for (genvar i = 0; i < NumSysCores; i++) begin : gen_core_outputs
+ localparam CoreCoreIndex = DMRFixed ? i : dmr_group_id(i);
+ if (DMRFixed && i < NumDMRGroups) begin : fixed_dmr
+ // CTRL
+ assign sys_core_busy_o [i] = dmr_core_busy_out[CoreCoreIndex];
+
+ // IRQ
+ assign sys_irq_ack_o [i] = dmr_irq_ack_out [CoreCoreIndex];
+ assign sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[CoreCoreIndex];
+
+ // INSTR
+ assign filt_instr_req [i] = dmr_instr_req_out [CoreCoreIndex];
+ assign filt_instr_addr [i] = dmr_instr_addr_out[CoreCoreIndex];
+
+ // DATA
+ assign filt_data_req [i] = dmr_data_req_out [CoreCoreIndex];
+ assign filt_data_addr [i] = dmr_data_add_out [CoreCoreIndex];
+ assign filt_data_we [i] = dmr_data_wen_out [CoreCoreIndex];
+ assign filt_data_data [i] = dmr_data_wdata_out[CoreCoreIndex];
+ assign sys_data_user_o [i] = dmr_data_user_out [CoreCoreIndex];
+ assign filt_data_be [i] = dmr_data_be_out [CoreCoreIndex];
+ end else begin
+ if (i >= NumDMRCores) begin : independent_stragglers
+ // CTRL
+ assign sys_core_busy_o [i] = dmr_core_busy_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+
+ // IRQ
+ assign sys_irq_ack_o [i] = dmr_irq_ack_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+
+ // INSTR
+ assign filt_instr_req [i] = dmr_instr_req_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_instr_addr [i] = dmr_instr_addr_out[TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+
+ // DATA
+ assign filt_data_req [i] = dmr_data_req_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_addr [i] = dmr_data_add_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_we [i] = dmr_data_wen_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_data [i] = dmr_data_wdata_out[TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign sys_data_user_o [i] = dmr_data_user_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign filt_data_be [i] = dmr_data_be_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ end else begin
+ always_comb begin
+ if (core_in_dmr[i]) begin : dmr_mode
+ if (dmr_core_id(dmr_group_id(i), 0) == i) begin : is_dmr_main_core
+ // CTRL
+ sys_core_busy_o [i] = dmr_core_busy_out[CoreCoreIndex];
+
+ // IRQ
+ sys_irq_ack_o [i] = dmr_irq_ack_out [CoreCoreIndex];
+ sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[CoreCoreIndex];
+
+ // INSTR
+ filt_instr_req [i] = dmr_instr_req_out [CoreCoreIndex];
+ filt_instr_addr [i] = dmr_instr_addr_out[CoreCoreIndex];
+
+ // DATA
+ filt_data_req [i] = dmr_data_req_out [CoreCoreIndex];
+ filt_data_addr [i] = dmr_data_add_out [CoreCoreIndex];
+ filt_data_we [i] = dmr_data_wen_out [CoreCoreIndex];
+ filt_data_data [i] = dmr_data_wdata_out[CoreCoreIndex];
+ sys_data_user_o [i] = dmr_data_user_out [CoreCoreIndex];
+ filt_data_be [i] = dmr_data_be_out [CoreCoreIndex];
+ end else begin : disable_core // Assign disable
+ // CTLR
+ sys_core_busy_o [i] = '0;
+
+ // IRQ
+ sys_irq_ack_o [i] = '0;
+ sys_irq_ack_id_o [i] = '0;
+
+ // INSTR
+ filt_instr_req [i] = '0;
+ filt_instr_addr [i] = '0;
+
+ // DATA
+ filt_data_req [i] = '0;
+ filt_data_addr [i] = '0;
+ filt_data_we [i] = '0;
+ filt_data_data [i] = '0;
+ sys_data_user_o [i] = '0;
+ filt_data_be [i] = '0;
+ end
+ end else begin : independent_mode
+ // CTRL
+ sys_core_busy_o [i] = core_core_busy_i [i];
+
+ // IRQ
+ sys_irq_ack_o [i] = core_irq_ack_i [i];
+ sys_irq_ack_id_o [i] = core_irq_ack_id_i[i];
+
+ // INSTR
+ filt_instr_req [i] = core_instr_req_i [i];
+ filt_instr_addr [i] = core_instr_addr_i[i];
+
+ // DATA
+ filt_data_req [i] = core_data_req_i [i];
+ filt_data_addr [i] = core_data_add_i [i];
+ filt_data_we [i] = core_data_wen_i [i];
+ filt_data_data [i] = core_data_wdata_i[i];
+ sys_data_user_o [i] = core_data_user_i [i];
+ filt_data_be [i] = core_data_be_i [i];
+ end
+ end
+ end
+ end
+ end
+
+ end else begin : gen_no_redundancy
+ /*****************
+ *** none ***
+ *****************/
+ // Direct assignment, disable all
+ assign core_setback_o = '0;
+
+ // CTRL
+ assign core_core_id_o = sys_core_id_i;
+ assign core_cluster_id_o = sys_cluster_id_i;
+
+ assign core_clock_en_o = sys_clock_en_i;
+ assign core_fetch_en_o = sys_fetch_en_i;
+ assign core_boot_addr_o = sys_boot_addr_i;
+ assign sys_core_busy_o = core_core_busy_i;
+
+ assign core_debug_req_o = sys_debug_req_i;
+ assign core_perf_counters_o = sys_perf_counters_i;
+
+ // IRQ
+ assign core_irq_req_o = sys_irq_req_i;
+ assign sys_irq_ack_o = core_irq_ack_i;
+ assign core_irq_id_o = sys_irq_id_i;
+ assign sys_irq_ack_id_o = core_irq_ack_id_i;
+
+ // INSTR
+ assign filt_instr_req = core_instr_req_i;
+ assign core_instr_gnt_o = filt_instr_gnt;
+ assign filt_instr_addr = core_instr_addr_i;
+ assign core_instr_r_rdata_o = sys_instr_r_rdata_i;
+ assign core_instr_r_valid_o = filt_instr_r_valid;
+ assign core_instr_err_o = sys_instr_err_i;
+
+ // DATA
+ assign filt_data_req = core_data_req_i;
+ assign filt_data_addr = core_data_add_i;
+ assign filt_data_we = core_data_wen_i;
+ assign filt_data_data = core_data_wdata_i;
+ assign sys_data_user_o = core_data_user_i;
+ assign filt_data_be = core_data_be_i;
+ assign core_data_gnt_o = filt_data_gnt;
+ assign core_data_r_opc_o = sys_data_r_opc_i;
+ assign core_data_r_rdata_o = sys_data_r_rdata_i;
+ assign core_data_r_user_o = sys_data_r_user_i;
+ assign core_data_r_valid_o = filt_data_r_valid;
+ assign core_data_err_o = sys_data_err_i;
+ end
+
+endmodule
diff --git a/rtl/HMR/doc.html b/rtl/HMR/doc.html
new file mode 100644
index 00000000..ab3898ef
--- /dev/null
+++ b/rtl/HMR/doc.html
@@ -0,0 +1,99 @@
+
+
+ |
+ HMR_registers.avail_config @ 0x0
+ Available Configurations from implemented hardware.
+ Reset default = 0x0, mask 0x107
+ |
+
+| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | |
+
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | |
+rapid_recovery |
+ |
+triple |
+dual |
+independent |
+
|
+| Bits | Type | Reset | Name | Description |
|---|
| 0 | ro | x | independent | Independent mode is available. |
| 1 | ro | x | dual | Dual Modular Redundancy (DMR) is available. |
| 2 | ro | x | triple | Triple Modular Redundancy (TMR) is available. |
| 7:3 | | | | Reserved |
| 8 | ro | x | rapid_recovery | Rapid Recovery is available. |
+
+
+
+ |
+ HMR_registers.cores_en @ 0x4
+ Enabled cores, based on the configuration. Can be used for barriers.
+ Reset default = 0x0, mask 0xfff
+ |
+
+| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | |
+
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | |
+cores_en |
+
|
+| Bits | Type | Reset | Name | Description |
|---|
| 11:0 | ro | x | cores_en | Enabled cores. |
+
+
+
+ |
+ HMR_registers.DMR_enable @ 0x8
+ DMR configuration enable, on bit per DMR group.
+ Reset default = 0x0, mask 0x3f
+ |
+
+| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | |
+
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | |
+DMR_enable |
+
|
+| Bits | Type | Reset | Name | Description |
|---|
| 5:0 | rw | 0x0 | DMR_enable | DMR configuration enable. |
+
+
+
+ |
+ HMR_registers.TMR_enable @ 0xc
+ TMR configuration enable, one bit per TMR group.
+ Reset default = 0x0, mask 0xf
+ |
+
+| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | |
+
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | |
+TMR_enable |
+
|
+| Bits | Type | Reset | Name | Description |
|---|
| 3:0 | rw | 0x0 | TMR_enable | TMR configuration enable. |
+
+
+
+ |
+ HMR_registers.DMR_config @ 0x10
+
+ Reset default = 0x0, mask 0x3
+ |
+
+| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | |
+
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | |
+force_recovery |
+rapid_recovery |
+
|
+| Bits | Type | Reset | Name | Description |
|---|
| 0 | rw | x | rapid_recovery | Enable rapid recovery using an additional register file. |
| 1 | rw | x | force_recovery | Forces recovery routine (if rapid_recovery is available). |
+
+
+
+ |
+ HMR_registers.TMR_config @ 0x14
+
+ Reset default = 0x6, mask 0x1f
+ |
+
+| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | |
+
+| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | |
+force_resynch |
+rapid_recovery |
+reload_setback |
+setback |
+delay_resynch |
+
|
+| Bits | Type | Reset | Name | Description |
|---|
| 0 | rw | 0x0 | delay_resynch | Enable wait-for-restoration |
| 1 | rw | 0x1 | setback | Enable setback (synchronous reset) during re-synch. |
| 2 | rw | 0x1 | reload_setback | Enable setback on mismatch during reload section of re-synch (only possible with setback) |
| 3 | rw | x | rapid_recovery | Enable rapid recovery using additional register file. |
| 4 | rw | 0x0 | force_resynch | Forces a resynchronization routine |
+
diff --git a/rtl/HMR/doc.md b/rtl/HMR/doc.md
new file mode 100644
index 00000000..892ab665
--- /dev/null
+++ b/rtl/HMR/doc.md
@@ -0,0 +1,312 @@
+
+
+
+
+The tables describe each key and the type of the value. The following
+types are used:
+
+Type | Description
+---- | -----------
+int | integer (binary 0b, octal 0o, decimal, hex 0x)
+xint | x for undefined otherwise int
+bitrange | bit number as decimal integer, or bit-range as decimal integers msb:lsb
+list | comma separated list enclosed in `[]`
+name list | comma separated list enclosed in `[]` of one or more groups that have just name and dscr keys. e.g. `{ name: "name", desc: "description"}`
+name list+ | name list that optionally contains a width
+parameter list | parameter list having default value optionally
+group | comma separated group of key:value enclosed in `{}`
+list of group | comma separated group of key:value enclosed in `{}` the second entry of the list is the sub group format
+string | string, typically short
+text | string, may be multi-line enclosed in `'''` may use `**bold**`, `*italic*` or `!!Reg` markup
+tuple | tuple enclosed in ()
+python int | Native Python type int (generated)
+python Bool | Native Python type Bool (generated)
+python list | Native Python type list (generated)
+python enum | Native Python type enum (generated)
+
+
+Register fields are tagged using the swaccess key to describe the
+permitted access and side-effects. This key must have one of these
+values:
+
+
+Key | Description
+--- | -----------
+none | No access
+ro | Read Only
+rc | Read Only, reading clears
+rw | Read/Write
+r0w1c | Read zero, Write with 1 clears
+rw1s | Read, Write with 1 sets
+rw1c | Read, Write with 1 clears
+rw0c | Read, Write with 0 clears
+wo | Write Only
+
+
+Register fields are tagged using the hwaccess key to describe the
+permitted access from hardware logic and side-effects. This key must
+have one of these values:
+
+
+Key | Description
+--- | -----------
+hro | Read Only
+hrw | Read/Write
+hwo | Write Only
+none | No Access Needed
+
+
+The top level of the JSON is a group containing the following keys:
+
+Key | Kind | Type | Description of Value
+--- | ---- | ---- | --------------------
+name | required | string | name of the component
+clock_primary | required | string | name of the primary clock
+bus_interfaces | required | list | bus interfaces for the device
+registers | required | list | list of register definition groups and offset control groups
+alert_list | optional | name list+ | list of peripheral alerts
+available_inout_list | optional | name list+ | list of available peripheral inouts
+available_input_list | optional | name list+ | list of available peripheral inputs
+available_output_list | optional | name list+ | list of available peripheral outputs
+hier_path | additional hierarchy path before the reg block instance
+interrupt_list | optional | name list+ | list of peripheral interrupts
+inter_signal_list | optional | list | list of inter-module signals
+no_auto_alert_regs | optional | string | Set to true to suppress automatic generation of alert test registers. Defaults to true if no alert_list is present. Otherwise this defaults to false.
+no_auto_intr_regs | optional | string | Set to true to suppress automatic generation of interrupt registers. Defaults to true if no interrupt_list is present. Otherwise this defaults to false.
+other_clock_list | optional | list | list of other chip clocks needed
+other_reset_list | optional | list | list of other resets
+param_list | optional | parameter list | list of parameters of the IP
+regwidth | optional | int | width of registers in bits (default 32)
+reset_primary | optional | string | primary reset used by the module
+reset_request_list | optional | list | list of signals requesting reset
+scan | optional | python Bool | Indicates the module have `scanmode_i`
+scan_reset | optional | python Bool | Indicates the module have `scan_rst_ni`
+scan_en | optional | python Bool | Indicates the module has `scan_en_i`
+SPDX-License-Identifier | optional | string | License ientifier (if using pure json) Only use this if unable to put this information in a comment at the top of the file.
+wakeup_list | optional | name list+ | list of peripheral wakeups
+
+The basic structure of a register definition file is thus:
+
+```hjson
+{
+ name: "GP",
+ regwidth: "32",
+ registers: [
+ // register definitions...
+ ]
+}
+
+```
+
+
+
+The list of registers includes register definition groups containing the following keys:
+
+Key | Kind | Type | Description of Value
+--- | ---- | ---- | --------------------
+name | required | string | name of the register
+desc | required | text | description of the register
+fields | required | list | list of register field description groups
+swaccess | optional | string | software access permission to use for fields that don't specify swaccess
+hwaccess | optional | string | hardware access permission to use for fields that don't specify hwaccess
+hwext | optional | string | 'true' if the register is stored outside of the register module
+hwqe | optional | string | 'true' if hardware uses 'q' enable signal, which is latched signal of software write pulse.
+hwre | optional | string | 'true' if hardware uses 're' signal, which is latched signal of software read pulse.
+regwen | optional | string | if register is write-protected by another register, that register name should be given here. empty-string for no register write protection
+resval | optional | int | reset value of full register (default 0)
+tags | optional | string | tags for the register, following the format 'tag_name:item1:item2...'
+shadowed | optional | string | 'true' if the register is shadowed
+update_err_alert | optional | string | alert that will be triggered if this shadowed register has update error
+storage_err_alert | optional | string | alert that will be triggered if this shadowed register has storage error
+
+
+The basic register definition group will follow this pattern:
+
+```hjson
+ { name: "REGA",
+ desc: "Description of register",
+ swaccess: "rw",
+ resval: "42",
+ fields: [
+ // bit field definitions...
+ ]
+ }
+```
+
+The name and brief description are required. If the swaccess key is
+provided it describes the access pattern that will be used by all
+bitfields in the register that do not override with their own swaccess
+key. This is a useful shortcut because in most cases a register will
+have the same access restrictions for all fields. The reset value of
+the register may also be provided here or in the individual fields. If
+it is provided in both places then they must match, if it is provided
+in neither place then the reset value defaults to zero for all except
+write-only fields when it defaults to x.
+
+
+
+In the fields list each field definition is a group itself containing the following keys:
+
+Key | Kind | Type | Description of Value
+--- | ---- | ---- | --------------------
+bits | required | bitrange | bit or bit range (msb:lsb)
+name | optional | string | name of the field
+desc | optional | text | description of field (required if the field has a name)
+swaccess | optional | string | software access permission, copied from register if not provided in field. (Tool adds if not provided.)
+hwaccess | optional | string | hardware access permission, copied from register if not prvided in field. (Tool adds if not provided.)
+resval | optional | xint | reset value, comes from register resval if not provided in field. Zero if neither are provided and the field is readable, x if neither are provided and the field is wo. Must match if both are provided.
+enum | optional | list | list of permitted enumeration groups
+tags | optional | string | tags for the field, followed by the format 'tag_name:item1:item2...'
+
+
+Field names should be relatively short because they will be used
+frequently (and need to fit in the register layout picture!) The field
+description is expected to be longer and will most likely make use of
+the Hjson ability to include multi-line strings. An example with three
+fields:
+
+```hjson
+ fields: [
+ { bits: "15:0",
+ name: "RXS",
+ desc: '''
+ Last 16 oversampled values of RX. These are captured at 16x the baud
+ rate clock. This is a shift register with the most recent bit in
+ bit 0 and the oldest in bit 15. Only valid when ENRXS is set.
+ '''
+ }
+ { bits: "16",
+ name: "ENRXS",
+ desc: '''
+ If this bit is set the receive oversampled data is collected
+ in the RXS field.
+ '''
+ }
+ {bits: "20:19", name: "TXILVL",
+ desc: "Trigger level for TX interrupts",
+ resval: "2",
+ enum: [
+ { value: "0", name: "txlvl1", desc: "1 character" },
+ { value: "1", name: "txlvl4", desc: "4 characters" },
+ { value: "2", name: "txlvl8", desc: "8 characters" },
+ { value: "3", name: "txlvl16", desc: "16 characters" }
+ ]
+ }
+ ]
+```
+
+In all of these the swaccess parameter is inherited from the register
+level, and will be added so this key is always available to the
+backend. The RXS and ENRXS will default to zero reset value (unless
+something different is provided for the register) and will have the
+key added, but TXILVL expicitly sets its reset value as 2.
+
+The missing bits 17 and 18 will be treated as reserved by the tool, as
+will any bits between 21 and the maximum in the register.
+
+The TXILVL is an example using an enumeration to specify all valid
+values for the field. In this case all possible values are described,
+if the list is incomplete then the field is marked with the rsvdenum
+key so the backend can take appropriate action. (If the enum field is
+more than 7 bits then the checking is not done.)
+
+
+
+Definitions in an enumeration group contain:
+
+Key | Kind | Type | Description of Value
+--- | ---- | ---- | --------------------
+name | required | string | name of the member of the enum
+desc | required | text | description when field has this value
+value | required | int | value of this member of the enum
+
+
+The list of registers may include single entry groups to control the offset, open a window or generate registers:
+
+Key | Kind | Type | Description of Value
+--- | ---- | ---- | --------------------
+reserved | optional | int | number of registers to reserve space for
+skipto | optional | int | set next register offset to value
+window | optional | group | group defining an address range for something other than standard registers
+multireg | optional | group | group defining registers generated from a base instance.
+
+
+
+
+Registers can protect themselves from software writes by using the
+register attribute regwen. When not an emptry string (the default
+value), regwen indicates that another register must be true in order
+to allow writes to this register. This is useful for the prevention
+of software modification. The register-enable register (call it
+REGWEN) must be one bit in width, and should default to 1 and be rw1c
+for preferred security control. This allows all writes to proceed
+until at some point software disables future modifications by clearing
+REGWEN. An error is reported if REGWEN does not exist, contains more
+than one bit, is not `rw1c` or does not default to 1. One REGWEN can
+protect multiple registers. The REGWEN register must precede those
+registers that refer to it in the .hjson register list. An example:
+
+```hjson
+ { name: "REGWEN",
+ desc: "Register write enable for a bank of registers",
+ swaccess: "rw1c",
+ fields: [ { bits: "0", resval: "1" } ]
+ }
+ { name: "REGA",
+ swaccess: "rw",
+ regwen: "REGWEN",
+ ...
+ }
+ { name: "REGB",
+ swaccess: "rw",
+ regwen: "REGWEN",
+ ...
+ }
+```
+
+
+A window defines an open region of the register space that can be used
+for things that are not registers (for example access to a buffer ram).
+
+
+Key | Kind | Type | Description of Value
+--- | ---- | ---- | --------------------
+name | required | string | name of the window
+desc | required | text | description of the window
+items | required | int | size in fieldaccess width words of the window
+swaccess | required | string | software access permitted
+data-intg-passthru | optional | string | True if the window has data integrity pass through. Defaults to false if not present.
+byte-write | optional | string | True if byte writes are supported. Defaults to false if not present.
+validbits | optional | int | Number of valid data bits within regwidth sized word. Defaults to regwidth. If smaller than the regwidth then in each word of the window bits [regwidth-1:validbits] are unused and bits [validbits-1:0] are valid.
+unusual | optional | string | True if window has unusual parameters (set to prevent Unusual: errors).Defaults to false if not present.
+
+
+The multireg expands on the register required fields and will generate
+a list of the generated registers (that contain all required and
+generated keys for an actual register).
+
+
+Key | Kind | Type | Description of Value
+--- | ---- | ---- | --------------------
+name | required | string | base name of the registers
+desc | required | text | description of the registers
+count | required | string | number of instances to generate. This field can be integer or string matching from param_list.
+cname | required | string | base name for each instance, mostly useful for referring to instance in messages.
+fields | required | list | list of register field description groups. Describes bit positions used for base instance.
+swaccess | optional | string | software access permission to use for fields that don't specify swaccess
+hwaccess | optional | string | hardware access permission to use for fields that don't specify hwaccess
+hwext | optional | string | 'true' if the register is stored outside of the register module
+hwqe | optional | string | 'true' if hardware uses 'q' enable signal, which is latched signal of software write pulse.
+hwre | optional | string | 'true' if hardware uses 're' signal, which is latched signal of software read pulse.
+regwen | optional | string | if register is write-protected by another register, that register name should be given here. empty-string for no register write protection
+resval | optional | int | reset value of full register (default 0)
+tags | optional | string | tags for the register, following the format 'tag_name:item1:item2...'
+shadowed | optional | string | 'true' if the register is shadowed
+update_err_alert | optional | string | alert that will be triggered if this shadowed register has update error
+storage_err_alert | optional | string | alert that will be triggered if this shadowed register has storage error
+regwen_multi | optional | python Bool | If true, regwen term increments along with current multireg count.
+compact | optional | python Bool | If true, allow multireg compacting.If false, do not compact.
+
+
+(end of output generated by `regtool.py --doc`)
+
diff --git a/rtl/HMR/hmr_core_regs_reg_pkg.sv b/rtl/HMR/hmr_core_regs_reg_pkg.sv
new file mode 100644
index 00000000..602bd91a
--- /dev/null
+++ b/rtl/HMR/hmr_core_regs_reg_pkg.sv
@@ -0,0 +1,80 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package hmr_core_regs_reg_pkg;
+
+ // Address widths within the block
+ parameter int BlockAw = 4;
+
+ ////////////////////////////
+ // Typedefs for registers //
+ ////////////////////////////
+
+ typedef struct packed {
+ logic [31:0] q;
+ } hmr_core_regs_reg2hw_mismatches_reg_t;
+
+ typedef struct packed {
+ logic [31:0] q;
+ logic qe;
+ } hmr_core_regs_reg2hw_sp_store_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ } independent;
+ struct packed {
+ logic d;
+ } dual;
+ struct packed {
+ logic d;
+ } triple;
+ } hmr_core_regs_hw2reg_current_mode_reg_t;
+
+ typedef struct packed {
+ logic [31:0] d;
+ logic de;
+ } hmr_core_regs_hw2reg_mismatches_reg_t;
+
+ // Register -> HW type
+ typedef struct packed {
+ hmr_core_regs_reg2hw_mismatches_reg_t mismatches; // [64:33]
+ hmr_core_regs_reg2hw_sp_store_reg_t sp_store; // [32:0]
+ } hmr_core_regs_reg2hw_t;
+
+ // HW -> register type
+ typedef struct packed {
+ hmr_core_regs_hw2reg_current_mode_reg_t current_mode; // [35:33]
+ hmr_core_regs_hw2reg_mismatches_reg_t mismatches; // [32:0]
+ } hmr_core_regs_hw2reg_t;
+
+ // Register offsets
+ parameter logic [BlockAw-1:0] HMR_CORE_REGS_CURRENT_MODE_OFFSET = 4'h 0;
+ parameter logic [BlockAw-1:0] HMR_CORE_REGS_MISMATCHES_OFFSET = 4'h 4;
+ parameter logic [BlockAw-1:0] HMR_CORE_REGS_SP_STORE_OFFSET = 4'h 8;
+
+ // Reset values for hwext registers and their fields
+ parameter logic [2:0] HMR_CORE_REGS_CURRENT_MODE_RESVAL = 3'h 1;
+ parameter logic [0:0] HMR_CORE_REGS_CURRENT_MODE_INDEPENDENT_RESVAL = 1'h 1;
+ parameter logic [0:0] HMR_CORE_REGS_CURRENT_MODE_DUAL_RESVAL = 1'h 0;
+ parameter logic [0:0] HMR_CORE_REGS_CURRENT_MODE_TRIPLE_RESVAL = 1'h 0;
+
+ // Register index
+ typedef enum int {
+ HMR_CORE_REGS_CURRENT_MODE,
+ HMR_CORE_REGS_MISMATCHES,
+ HMR_CORE_REGS_SP_STORE
+ } hmr_core_regs_id_e;
+
+ // Register width information to check illegal writes
+ parameter logic [3:0] HMR_CORE_REGS_PERMIT [3] = '{
+ 4'b 0001, // index[0] HMR_CORE_REGS_CURRENT_MODE
+ 4'b 1111, // index[1] HMR_CORE_REGS_MISMATCHES
+ 4'b 1111 // index[2] HMR_CORE_REGS_SP_STORE
+ };
+
+endpackage
+
diff --git a/rtl/HMR/hmr_core_regs_reg_top.sv b/rtl/HMR/hmr_core_regs_reg_top.sv
new file mode 100644
index 00000000..d9cf8ceb
--- /dev/null
+++ b/rtl/HMR/hmr_core_regs_reg_top.sv
@@ -0,0 +1,306 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+
+`include "common_cells/assertions.svh"
+
+module hmr_core_regs_reg_top #(
+ parameter type reg_req_t = logic,
+ parameter type reg_rsp_t = logic,
+ parameter int AW = 4
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ input reg_req_t reg_req_i,
+ output reg_rsp_t reg_rsp_o,
+ // To HW
+ output hmr_core_regs_reg_pkg::hmr_core_regs_reg2hw_t reg2hw, // Write
+ input hmr_core_regs_reg_pkg::hmr_core_regs_hw2reg_t hw2reg, // Read
+
+
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+ import hmr_core_regs_reg_pkg::* ;
+
+ localparam int DW = 32;
+ localparam int DBW = DW/8; // Byte Width
+
+ // register signals
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
+
+ logic addrmiss, wr_err;
+
+ logic [DW-1:0] reg_rdata_next;
+
+ // Below register interface can be changed
+ reg_req_t reg_intf_req;
+ reg_rsp_t reg_intf_rsp;
+
+
+ assign reg_intf_req = reg_req_i;
+ assign reg_rsp_o = reg_intf_rsp;
+
+
+ assign reg_we = reg_intf_req.valid & reg_intf_req.write;
+ assign reg_re = reg_intf_req.valid & ~reg_intf_req.write;
+ assign reg_addr = reg_intf_req.addr;
+ assign reg_wdata = reg_intf_req.wdata;
+ assign reg_be = reg_intf_req.wstrb;
+ assign reg_intf_rsp.rdata = reg_rdata;
+ assign reg_intf_rsp.error = reg_error;
+ assign reg_intf_rsp.ready = 1'b1;
+
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = (devmode_i & addrmiss) | wr_err;
+
+
+ // Define SW related signals
+ // Format: __{wd|we|qs}
+ // or _{wd|we|qs} if field == 1 or 0
+ logic current_mode_independent_qs;
+ logic current_mode_independent_re;
+ logic current_mode_dual_qs;
+ logic current_mode_dual_re;
+ logic current_mode_triple_qs;
+ logic current_mode_triple_re;
+ logic [31:0] mismatches_qs;
+ logic [31:0] mismatches_wd;
+ logic mismatches_we;
+ logic [31:0] sp_store_qs;
+ logic [31:0] sp_store_wd;
+ logic sp_store_we;
+
+ // Register instances
+ // R[current_mode]: V(True)
+
+ // F[independent]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_current_mode_independent (
+ .re (current_mode_independent_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.current_mode.independent.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (current_mode_independent_qs)
+ );
+
+
+ // F[dual]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_current_mode_dual (
+ .re (current_mode_dual_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.current_mode.dual.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (current_mode_dual_qs)
+ );
+
+
+ // F[triple]: 2:2
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_current_mode_triple (
+ .re (current_mode_triple_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.current_mode.triple.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (current_mode_triple_qs)
+ );
+
+
+ // R[mismatches]: V(False)
+
+ prim_subreg #(
+ .DW (32),
+ .SWACCESS("W0C"),
+ .RESVAL (32'h0)
+ ) u_mismatches (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (mismatches_we),
+ .wd (mismatches_wd),
+
+ // from internal hardware
+ .de (hw2reg.mismatches.de),
+ .d (hw2reg.mismatches.d ),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.mismatches.q ),
+
+ // to register interface (read)
+ .qs (mismatches_qs)
+ );
+
+
+ // R[sp_store]: V(False)
+
+ prim_subreg #(
+ .DW (32),
+ .SWACCESS("RW"),
+ .RESVAL (32'h0)
+ ) u_sp_store (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (sp_store_we),
+ .wd (sp_store_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0 ),
+
+ // to internal hardware
+ .qe (reg2hw.sp_store.qe),
+ .q (reg2hw.sp_store.q ),
+
+ // to register interface (read)
+ .qs (sp_store_qs)
+ );
+
+
+
+
+ logic [2:0] addr_hit;
+ always_comb begin
+ addr_hit = '0;
+ addr_hit[0] = (reg_addr == HMR_CORE_REGS_CURRENT_MODE_OFFSET);
+ addr_hit[1] = (reg_addr == HMR_CORE_REGS_MISMATCHES_OFFSET);
+ addr_hit[2] = (reg_addr == HMR_CORE_REGS_SP_STORE_OFFSET);
+ end
+
+ assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+ // Check sub-word write is permitted
+ always_comb begin
+ wr_err = (reg_we &
+ ((addr_hit[0] & (|(HMR_CORE_REGS_PERMIT[0] & ~reg_be))) |
+ (addr_hit[1] & (|(HMR_CORE_REGS_PERMIT[1] & ~reg_be))) |
+ (addr_hit[2] & (|(HMR_CORE_REGS_PERMIT[2] & ~reg_be)))));
+ end
+
+ assign current_mode_independent_re = addr_hit[0] & reg_re & !reg_error;
+
+ assign current_mode_dual_re = addr_hit[0] & reg_re & !reg_error;
+
+ assign current_mode_triple_re = addr_hit[0] & reg_re & !reg_error;
+
+ assign mismatches_we = addr_hit[1] & reg_we & !reg_error;
+ assign mismatches_wd = reg_wdata[31:0];
+
+ assign sp_store_we = addr_hit[2] & reg_we & !reg_error;
+ assign sp_store_wd = reg_wdata[31:0];
+
+ // Read data return
+ always_comb begin
+ reg_rdata_next = '0;
+ unique case (1'b1)
+ addr_hit[0]: begin
+ reg_rdata_next[0] = current_mode_independent_qs;
+ reg_rdata_next[1] = current_mode_dual_qs;
+ reg_rdata_next[2] = current_mode_triple_qs;
+ end
+
+ addr_hit[1]: begin
+ reg_rdata_next[31:0] = mismatches_qs;
+ end
+
+ addr_hit[2]: begin
+ reg_rdata_next[31:0] = sp_store_qs;
+ end
+
+ default: begin
+ reg_rdata_next = '1;
+ end
+ endcase
+ end
+
+ // Unused signal tieoff
+
+ // wdata / byte enable are not always fully used
+ // add a blanket unused statement to handle lint waivers
+ logic unused_wdata;
+ logic unused_be;
+ assign unused_wdata = ^reg_wdata;
+ assign unused_be = ^reg_be;
+
+ // Assertions for Register Interface
+ `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+endmodule
+
+module hmr_core_regs_reg_top_intf
+#(
+ parameter int AW = 4,
+ localparam int DW = 32
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ REG_BUS.in regbus_slave,
+ // To HW
+ output hmr_core_regs_reg_pkg::hmr_core_regs_reg2hw_t reg2hw, // Write
+ input hmr_core_regs_reg_pkg::hmr_core_regs_hw2reg_t hw2reg, // Read
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+ localparam int unsigned STRB_WIDTH = DW/8;
+
+`include "register_interface/typedef.svh"
+`include "register_interface/assign.svh"
+
+ // Define structs for reg_bus
+ typedef logic [AW-1:0] addr_t;
+ typedef logic [DW-1:0] data_t;
+ typedef logic [STRB_WIDTH-1:0] strb_t;
+ `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t)
+
+ reg_bus_req_t s_reg_req;
+ reg_bus_rsp_t s_reg_rsp;
+
+ // Assign SV interface to structs
+ `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave)
+ `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp)
+
+
+
+ hmr_core_regs_reg_top #(
+ .reg_req_t(reg_bus_req_t),
+ .reg_rsp_t(reg_bus_rsp_t),
+ .AW(AW)
+ ) i_regs (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(s_reg_req),
+ .reg_rsp_o(s_reg_rsp),
+ .reg2hw, // Write
+ .hw2reg, // Read
+ .devmode_i
+ );
+
+endmodule
+
+
diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv
new file mode 100644
index 00000000..35b638ba
--- /dev/null
+++ b/rtl/HMR/hmr_dmr_ctrl.sv
@@ -0,0 +1,189 @@
+// Copyright 2023 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Hybrid modular redundancy DMR control unit
+
+module hmr_dmr_ctrl
+ import rapid_recovery_pkg::*;
+#(
+ parameter bit InterleaveGrps = 1'b0,
+ parameter int unsigned DataWidth = 32,
+ parameter bit DMRFixed = 1'b0,
+ parameter bit DefaultInDMR = DMRFixed ? 1'b1 : 1'b0,
+ parameter bit RapidRecovery = 1'b0,
+ parameter type reg_req_t = logic,
+ parameter type reg_resp_t = logic
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ // input logic test_enable_i,
+
+ // Register interface
+ input reg_req_t reg_req_i,
+ output reg_resp_t reg_resp_o,
+
+ // CTRL from external (e.g. HMR ctrl regs)
+ input logic dmr_enable_q_i,
+ input logic dmr_enable_qe_i,
+ input logic rapid_recovery_q_i,
+ input logic rapid_recovery_qe_i,
+ input logic force_recovery_q_i,
+ input logic force_recovery_qe_i,
+
+ // DMR control signals
+ output logic [1:0] setback_o,
+ output logic sw_resynch_req_o,
+ output logic sw_synch_req_o,
+ output logic [DataWidth-1:0] checkpoint_o,
+ output logic grp_in_independent_o,
+ output logic rapid_recovery_en_o,
+ output logic [1:0] dmr_incr_mismatches_o,
+ input logic dmr_error_i,
+ output logic recovery_request_o,
+ input logic recovery_finished_i,
+
+ input logic fetch_en_i,
+ input logic cores_synch_i
+);
+
+ logic synch_req, synch_req_sent_d, synch_req_sent_q;
+ logic resynch_req, resynch_req_sent_d, resynch_req_sent_q;
+ logic cores_synch_q;
+
+ typedef enum logic [2:0] {NON_DMR, DMR_RUN, DMR_RESTORE} dmr_mode_e;
+ localparam dmr_mode_e DefaultDMRMode = DefaultInDMR || DMRFixed ? DMR_RUN : NON_DMR;
+
+ hmr_dmr_regs_reg_pkg::hmr_dmr_regs_reg2hw_t dmr_reg2hw;
+ hmr_dmr_regs_reg_pkg::hmr_dmr_regs_hw2reg_t dmr_hw2reg;
+
+ dmr_mode_e dmr_red_mode_d, dmr_red_mode_q;
+
+ assign grp_in_independent_o = dmr_red_mode_q == NON_DMR;
+ assign rapid_recovery_en_o = dmr_reg2hw.dmr_config.rapid_recovery.q && RapidRecovery;
+
+ assign sw_synch_req_o = synch_req & ~synch_req_sent_q;
+ assign synch_req_sent_d = synch_req;
+ assign sw_resynch_req_o = resynch_req & ~resynch_req_sent_q;
+ assign resynch_req_sent_d = resynch_req;
+ assign checkpoint_o = dmr_reg2hw.checkpoint_addr.q;
+
+ hmr_dmr_regs_reg_top #(
+ .reg_req_t(reg_req_t),
+ .reg_rsp_t(reg_resp_t)
+ ) i_dmr_regs (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(reg_req_i),
+ .reg_rsp_o(reg_resp_o),
+ .reg2hw (dmr_reg2hw),
+ .hw2reg (dmr_hw2reg),
+ .devmode_i('0)
+ );
+
+ // Global config update
+ assign dmr_hw2reg.dmr_enable.de = dmr_enable_qe_i;
+ assign dmr_hw2reg.dmr_enable.d = dmr_enable_q_i;
+ assign dmr_hw2reg.dmr_config.rapid_recovery.de = rapid_recovery_qe_i || ~RapidRecovery;
+ assign dmr_hw2reg.dmr_config.rapid_recovery.d = rapid_recovery_q_i && RapidRecovery;
+ assign dmr_hw2reg.dmr_config.force_recovery.d = force_recovery_qe_i ? force_recovery_q_i : 1'b0;
+
+ /**************************
+ * FSM for DMR lockstep *
+ **************************/
+
+ always_comb begin : proc_fsm
+ setback_o = 2'b00;
+ dmr_red_mode_d = dmr_red_mode_q;
+ dmr_incr_mismatches_o = '0;
+ recovery_request_o = 1'b0;
+ resynch_req = 1'b0;
+ synch_req = 1'b0;
+
+ dmr_hw2reg.dmr_config.force_recovery.de = force_recovery_qe_i;
+
+ case (dmr_red_mode_q)
+ DMR_RUN: begin
+ // If forced execute recovery
+ if (dmr_reg2hw.dmr_config.force_recovery.q && RapidRecovery && dmr_reg2hw.dmr_config.rapid_recovery.q) begin
+ dmr_hw2reg.dmr_config.force_recovery.de = 1'b1;
+ dmr_red_mode_d = DMR_RESTORE;
+ end
+
+ // If error detected, restore
+ if (dmr_error_i && RapidRecovery && dmr_reg2hw.dmr_config.rapid_recovery.q) begin
+ $display("[HMR-dual] %t - mismatch detected, rapid recovery starting", $realtime);
+ dmr_red_mode_d = DMR_RESTORE;
+ end
+
+ if (dmr_error_i && (!RapidRecovery || !dmr_reg2hw.dmr_config.rapid_recovery.q)) begin
+ $display("[HMR-dual] %t - mismatch detected, SW trigger", $realtime);
+ resynch_req = 1'b1;
+ end
+ end
+
+ DMR_RESTORE: begin
+ recovery_request_o = 1'b1;
+ if (recovery_finished_i) begin
+ $display("[HMR-dual] %t - mismatch restored", $realtime);
+ dmr_red_mode_d = DMR_RUN;
+ end
+ end
+
+ // Default: do nothing
+ endcase
+
+ // Logic to switch in and out of DMR
+ if (!DMRFixed) begin
+ // Set DMR mode on external signal that cores are synchronized
+ if (dmr_red_mode_q == NON_DMR && dmr_reg2hw.dmr_enable.q == 1'b1) begin
+ synch_req = 1'b1;
+ if (cores_synch_q == 1'b1) begin
+ if (dmr_reg2hw.dmr_config.rapid_recovery.q == 1'b1) begin
+ dmr_red_mode_d = DMR_RESTORE;
+ end else begin
+ dmr_red_mode_d = DMR_RUN;
+ setback_o = 2'b11;
+ end
+ end
+ end
+ // Before core startup: set DMR mode from reg2hw.dmr_enable
+ if (fetch_en_i == 0) begin
+ if (dmr_reg2hw.dmr_enable.q == 1'b0) begin
+ dmr_red_mode_d = NON_DMR;
+ end else begin
+ synch_req = 1'b0;
+ dmr_red_mode_d = DMR_RUN;
+ end
+ end
+ // split tolerant mode to performance mode anytime (but require correct core state)
+ if (dmr_red_mode_q == DMR_RUN) begin
+ if (dmr_reg2hw.dmr_enable.q == 1'b0) begin
+ dmr_red_mode_d = NON_DMR;
+ setback_o = 2'b10;
+ end
+ end
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin : proc_red_mode
+ if(!rst_ni) begin
+ dmr_red_mode_q <= DefaultDMRMode;
+ synch_req_sent_q <= '0;
+ resynch_req_sent_q <= '0;
+ cores_synch_q <= '0;
+ end else begin
+ dmr_red_mode_q <= dmr_red_mode_d;
+ synch_req_sent_q <= synch_req_sent_d;
+ resynch_req_sent_q <= resynch_req_sent_d;
+ cores_synch_q <= cores_synch_i;
+ end
+ end
+
+endmodule
diff --git a/rtl/HMR/hmr_dmr_regs_reg_pkg.sv b/rtl/HMR/hmr_dmr_regs_reg_pkg.sv
new file mode 100644
index 00000000..95199d4c
--- /dev/null
+++ b/rtl/HMR/hmr_dmr_regs_reg_pkg.sv
@@ -0,0 +1,92 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package hmr_dmr_regs_reg_pkg;
+
+ // Address widths within the block
+ parameter int BlockAw = 4;
+
+ ////////////////////////////
+ // Typedefs for registers //
+ ////////////////////////////
+
+ typedef struct packed {
+ logic q;
+ logic qe;
+ } hmr_dmr_regs_reg2hw_dmr_enable_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } rapid_recovery;
+ struct packed {
+ logic q;
+ logic qe;
+ } force_recovery;
+ } hmr_dmr_regs_reg2hw_dmr_config_reg_t;
+
+ typedef struct packed {
+ logic [31:0] q;
+ logic qe;
+ } hmr_dmr_regs_reg2hw_checkpoint_addr_reg_t;
+
+ typedef struct packed {
+ logic d;
+ logic de;
+ } hmr_dmr_regs_hw2reg_dmr_enable_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ logic de;
+ } rapid_recovery;
+ struct packed {
+ logic d;
+ logic de;
+ } force_recovery;
+ } hmr_dmr_regs_hw2reg_dmr_config_reg_t;
+
+ typedef struct packed {
+ logic [31:0] d;
+ logic de;
+ } hmr_dmr_regs_hw2reg_checkpoint_addr_reg_t;
+
+ // Register -> HW type
+ typedef struct packed {
+ hmr_dmr_regs_reg2hw_dmr_enable_reg_t dmr_enable; // [38:37]
+ hmr_dmr_regs_reg2hw_dmr_config_reg_t dmr_config; // [36:33]
+ hmr_dmr_regs_reg2hw_checkpoint_addr_reg_t checkpoint_addr; // [32:0]
+ } hmr_dmr_regs_reg2hw_t;
+
+ // HW -> register type
+ typedef struct packed {
+ hmr_dmr_regs_hw2reg_dmr_enable_reg_t dmr_enable; // [38:37]
+ hmr_dmr_regs_hw2reg_dmr_config_reg_t dmr_config; // [36:33]
+ hmr_dmr_regs_hw2reg_checkpoint_addr_reg_t checkpoint_addr; // [32:0]
+ } hmr_dmr_regs_hw2reg_t;
+
+ // Register offsets
+ parameter logic [BlockAw-1:0] HMR_DMR_REGS_DMR_ENABLE_OFFSET = 4'h 0;
+ parameter logic [BlockAw-1:0] HMR_DMR_REGS_DMR_CONFIG_OFFSET = 4'h 4;
+ parameter logic [BlockAw-1:0] HMR_DMR_REGS_CHECKPOINT_ADDR_OFFSET = 4'h 8;
+
+ // Register index
+ typedef enum int {
+ HMR_DMR_REGS_DMR_ENABLE,
+ HMR_DMR_REGS_DMR_CONFIG,
+ HMR_DMR_REGS_CHECKPOINT_ADDR
+ } hmr_dmr_regs_id_e;
+
+ // Register width information to check illegal writes
+ parameter logic [3:0] HMR_DMR_REGS_PERMIT [3] = '{
+ 4'b 0001, // index[0] HMR_DMR_REGS_DMR_ENABLE
+ 4'b 0001, // index[1] HMR_DMR_REGS_DMR_CONFIG
+ 4'b 1111 // index[2] HMR_DMR_REGS_CHECKPOINT_ADDR
+ };
+
+endpackage
+
diff --git a/rtl/HMR/hmr_dmr_regs_reg_top.sv b/rtl/HMR/hmr_dmr_regs_reg_top.sv
new file mode 100644
index 00000000..209d9348
--- /dev/null
+++ b/rtl/HMR/hmr_dmr_regs_reg_top.sv
@@ -0,0 +1,312 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+
+`include "common_cells/assertions.svh"
+
+module hmr_dmr_regs_reg_top #(
+ parameter type reg_req_t = logic,
+ parameter type reg_rsp_t = logic,
+ parameter int AW = 4
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ input reg_req_t reg_req_i,
+ output reg_rsp_t reg_rsp_o,
+ // To HW
+ output hmr_dmr_regs_reg_pkg::hmr_dmr_regs_reg2hw_t reg2hw, // Write
+ input hmr_dmr_regs_reg_pkg::hmr_dmr_regs_hw2reg_t hw2reg, // Read
+
+
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+ import hmr_dmr_regs_reg_pkg::* ;
+
+ localparam int DW = 32;
+ localparam int DBW = DW/8; // Byte Width
+
+ // register signals
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
+
+ logic addrmiss, wr_err;
+
+ logic [DW-1:0] reg_rdata_next;
+
+ // Below register interface can be changed
+ reg_req_t reg_intf_req;
+ reg_rsp_t reg_intf_rsp;
+
+
+ assign reg_intf_req = reg_req_i;
+ assign reg_rsp_o = reg_intf_rsp;
+
+
+ assign reg_we = reg_intf_req.valid & reg_intf_req.write;
+ assign reg_re = reg_intf_req.valid & ~reg_intf_req.write;
+ assign reg_addr = reg_intf_req.addr;
+ assign reg_wdata = reg_intf_req.wdata;
+ assign reg_be = reg_intf_req.wstrb;
+ assign reg_intf_rsp.rdata = reg_rdata;
+ assign reg_intf_rsp.error = reg_error;
+ assign reg_intf_rsp.ready = 1'b1;
+
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = (devmode_i & addrmiss) | wr_err;
+
+
+ // Define SW related signals
+ // Format: __{wd|we|qs}
+ // or _{wd|we|qs} if field == 1 or 0
+ logic dmr_enable_qs;
+ logic dmr_enable_wd;
+ logic dmr_enable_we;
+ logic dmr_config_rapid_recovery_qs;
+ logic dmr_config_rapid_recovery_wd;
+ logic dmr_config_rapid_recovery_we;
+ logic dmr_config_force_recovery_qs;
+ logic dmr_config_force_recovery_wd;
+ logic dmr_config_force_recovery_we;
+ logic [31:0] checkpoint_addr_qs;
+ logic [31:0] checkpoint_addr_wd;
+ logic checkpoint_addr_we;
+
+ // Register instances
+ // R[dmr_enable]: V(False)
+
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h0)
+ ) u_dmr_enable (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (dmr_enable_we),
+ .wd (dmr_enable_wd),
+
+ // from internal hardware
+ .de (hw2reg.dmr_enable.de),
+ .d (hw2reg.dmr_enable.d ),
+
+ // to internal hardware
+ .qe (reg2hw.dmr_enable.qe),
+ .q (reg2hw.dmr_enable.q ),
+
+ // to register interface (read)
+ .qs (dmr_enable_qs)
+ );
+
+
+ // R[dmr_config]: V(False)
+
+ // F[rapid_recovery]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h0)
+ ) u_dmr_config_rapid_recovery (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (dmr_config_rapid_recovery_we),
+ .wd (dmr_config_rapid_recovery_wd),
+
+ // from internal hardware
+ .de (hw2reg.dmr_config.rapid_recovery.de),
+ .d (hw2reg.dmr_config.rapid_recovery.d ),
+
+ // to internal hardware
+ .qe (reg2hw.dmr_config.rapid_recovery.qe),
+ .q (reg2hw.dmr_config.rapid_recovery.q ),
+
+ // to register interface (read)
+ .qs (dmr_config_rapid_recovery_qs)
+ );
+
+
+ // F[force_recovery]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h0)
+ ) u_dmr_config_force_recovery (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (dmr_config_force_recovery_we),
+ .wd (dmr_config_force_recovery_wd),
+
+ // from internal hardware
+ .de (hw2reg.dmr_config.force_recovery.de),
+ .d (hw2reg.dmr_config.force_recovery.d ),
+
+ // to internal hardware
+ .qe (reg2hw.dmr_config.force_recovery.qe),
+ .q (reg2hw.dmr_config.force_recovery.q ),
+
+ // to register interface (read)
+ .qs (dmr_config_force_recovery_qs)
+ );
+
+
+ // R[checkpoint_addr]: V(False)
+
+ prim_subreg #(
+ .DW (32),
+ .SWACCESS("RW"),
+ .RESVAL (32'h0)
+ ) u_checkpoint_addr (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (checkpoint_addr_we),
+ .wd (checkpoint_addr_wd),
+
+ // from internal hardware
+ .de (hw2reg.checkpoint_addr.de),
+ .d (hw2reg.checkpoint_addr.d ),
+
+ // to internal hardware
+ .qe (reg2hw.checkpoint_addr.qe),
+ .q (reg2hw.checkpoint_addr.q ),
+
+ // to register interface (read)
+ .qs (checkpoint_addr_qs)
+ );
+
+
+
+
+ logic [2:0] addr_hit;
+ always_comb begin
+ addr_hit = '0;
+ addr_hit[0] = (reg_addr == HMR_DMR_REGS_DMR_ENABLE_OFFSET);
+ addr_hit[1] = (reg_addr == HMR_DMR_REGS_DMR_CONFIG_OFFSET);
+ addr_hit[2] = (reg_addr == HMR_DMR_REGS_CHECKPOINT_ADDR_OFFSET);
+ end
+
+ assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+ // Check sub-word write is permitted
+ always_comb begin
+ wr_err = (reg_we &
+ ((addr_hit[0] & (|(HMR_DMR_REGS_PERMIT[0] & ~reg_be))) |
+ (addr_hit[1] & (|(HMR_DMR_REGS_PERMIT[1] & ~reg_be))) |
+ (addr_hit[2] & (|(HMR_DMR_REGS_PERMIT[2] & ~reg_be)))));
+ end
+
+ assign dmr_enable_we = addr_hit[0] & reg_we & !reg_error;
+ assign dmr_enable_wd = reg_wdata[0];
+
+ assign dmr_config_rapid_recovery_we = addr_hit[1] & reg_we & !reg_error;
+ assign dmr_config_rapid_recovery_wd = reg_wdata[0];
+
+ assign dmr_config_force_recovery_we = addr_hit[1] & reg_we & !reg_error;
+ assign dmr_config_force_recovery_wd = reg_wdata[1];
+
+ assign checkpoint_addr_we = addr_hit[2] & reg_we & !reg_error;
+ assign checkpoint_addr_wd = reg_wdata[31:0];
+
+ // Read data return
+ always_comb begin
+ reg_rdata_next = '0;
+ unique case (1'b1)
+ addr_hit[0]: begin
+ reg_rdata_next[0] = dmr_enable_qs;
+ end
+
+ addr_hit[1]: begin
+ reg_rdata_next[0] = dmr_config_rapid_recovery_qs;
+ reg_rdata_next[1] = dmr_config_force_recovery_qs;
+ end
+
+ addr_hit[2]: begin
+ reg_rdata_next[31:0] = checkpoint_addr_qs;
+ end
+
+ default: begin
+ reg_rdata_next = '1;
+ end
+ endcase
+ end
+
+ // Unused signal tieoff
+
+ // wdata / byte enable are not always fully used
+ // add a blanket unused statement to handle lint waivers
+ logic unused_wdata;
+ logic unused_be;
+ assign unused_wdata = ^reg_wdata;
+ assign unused_be = ^reg_be;
+
+ // Assertions for Register Interface
+ `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+endmodule
+
+module hmr_dmr_regs_reg_top_intf
+#(
+ parameter int AW = 4,
+ localparam int DW = 32
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ REG_BUS.in regbus_slave,
+ // To HW
+ output hmr_dmr_regs_reg_pkg::hmr_dmr_regs_reg2hw_t reg2hw, // Write
+ input hmr_dmr_regs_reg_pkg::hmr_dmr_regs_hw2reg_t hw2reg, // Read
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+ localparam int unsigned STRB_WIDTH = DW/8;
+
+`include "register_interface/typedef.svh"
+`include "register_interface/assign.svh"
+
+ // Define structs for reg_bus
+ typedef logic [AW-1:0] addr_t;
+ typedef logic [DW-1:0] data_t;
+ typedef logic [STRB_WIDTH-1:0] strb_t;
+ `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t)
+
+ reg_bus_req_t s_reg_req;
+ reg_bus_rsp_t s_reg_rsp;
+
+ // Assign SV interface to structs
+ `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave)
+ `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp)
+
+
+
+ hmr_dmr_regs_reg_top #(
+ .reg_req_t(reg_bus_req_t),
+ .reg_rsp_t(reg_bus_rsp_t),
+ .AW(AW)
+ ) i_regs (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(s_reg_req),
+ .reg_rsp_o(s_reg_rsp),
+ .reg2hw, // Write
+ .hw2reg, // Read
+ .devmode_i
+ );
+
+endmodule
+
+
diff --git a/rtl/HMR/hmr_rapid_recovery_ctrl.sv b/rtl/HMR/hmr_rapid_recovery_ctrl.sv
new file mode 100644
index 00000000..4f5b9f2f
--- /dev/null
+++ b/rtl/HMR/hmr_rapid_recovery_ctrl.sv
@@ -0,0 +1,143 @@
+// Copyright 2023 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Hybrid modular redundancy Rapid Recovery control unit
+
+module hmr_rapid_recovery_ctrl
+ import rapid_recovery_pkg::*;
+#(
+ parameter int unsigned RFAddrWidth = 6,
+ parameter type regfile_write_t = logic
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ // input logic test_en_i,
+
+ input logic start_recovery_i,
+ output logic recovery_finished_o,
+
+ // Signals to core
+ output logic setback_o,
+ output logic instr_lock_o,
+ output logic debug_req_o,
+ input logic debug_halt_i,
+ output logic debug_resume_o,
+ output regfile_write_t recovery_regfile_waddr_o,
+
+ // Signals to backup state
+ output logic backup_enable_o,
+ output logic recover_csr_enable_o,
+ output logic recover_pc_enable_o,
+ output logic recover_rf_enable_o
+);
+
+ typedef enum logic [1:0] {IDLE, RESET, HALT, RESTORE} recovery_mode_e;
+ recovery_mode_e rec_mode_d, rec_mode_q;
+
+ logic instr_lock_d, instr_lock_q;
+ logic setback_d, setback_q;
+ logic addr_gen_done;
+ logic [RFAddrWidth-1:0] addr_gen_result;
+
+ DMR_address_generator #(
+ .AddrWidth ( RFAddrWidth )
+ ) i_rf_address_generator (
+ .clk_i,
+ .rst_ni,
+ .clear_i ('0),
+ .enable_i ( recover_rf_enable_o ),
+ .done_o ( addr_gen_done ),
+ .fatal_o (),
+ .address_o (addr_gen_result)
+ );
+
+ assign recovery_regfile_waddr_o.we_a = recover_rf_enable_o;
+ assign recovery_regfile_waddr_o.waddr_a = addr_gen_result;
+ assign recovery_regfile_waddr_o.wdata_a = '0;
+ assign recovery_regfile_waddr_o.we_b = recover_rf_enable_o;
+ assign recovery_regfile_waddr_o.waddr_b = 16 + addr_gen_result;
+ assign recovery_regfile_waddr_o.wdata_b = '0;
+
+
+ assign instr_lock_o = instr_lock_q;
+ assign setback_o = setback_q;
+
+ always_comb begin
+ rec_mode_d = rec_mode_q;
+ instr_lock_d = instr_lock_q;
+ backup_enable_o = 1'b0;
+ setback_d = 1'b0;
+ debug_req_o = 1'b0;
+ recover_csr_enable_o = 1'b0;
+ recover_pc_enable_o = 1'b0;
+ recover_rf_enable_o = 1'b0;
+ debug_resume_o = 1'b0;
+ recovery_finished_o = 1'b0;
+
+ case (rec_mode_q)
+ IDLE: begin
+ backup_enable_o = 1'b1;
+ // If requested start the routine in the reset state
+ if (start_recovery_i) begin
+ // Disable all backups
+ backup_enable_o = 1'b0;
+ rec_mode_d = RESET;
+ end
+ end
+
+ RESET: begin
+ // Clear the core state
+ setback_d = 1'b1;
+ // Lock the instruction requests
+ instr_lock_d = 1'b1;
+ // Go to request halt of the core
+ rec_mode_d = HALT;
+ end
+
+ HALT: begin
+ // Requesst a debug halt
+ debug_req_o = 1'b1;
+ // Wait until the core has halted
+ if (debug_halt_i) begin
+ rec_mode_d = RESTORE;
+ end
+ end
+
+ RESTORE: begin
+ // Enable CSR recovery routine
+ recover_csr_enable_o = 1'b1;
+ // Enable the PC recovery routine
+ recover_pc_enable_o = 1'b1;
+ // Enable the RF recovery routine
+ recover_rf_enable_o = 1'b1;
+ // If recovery routine complete, continue
+ if (addr_gen_done) begin
+ instr_lock_d = 1'b0;
+ rec_mode_d = IDLE;
+ debug_resume_o = 1'b1;
+ recovery_finished_o = 1'b1;
+ end
+ end
+ endcase
+ end
+
+ always_ff @(posedge clk_i, negedge rst_ni) begin
+ if (!rst_ni) begin
+ instr_lock_q <= 1'b0;
+ rec_mode_q <= IDLE;
+ setback_q <= 1'b0;
+ end else begin
+ instr_lock_q <= instr_lock_d;
+ rec_mode_q <= rec_mode_d;
+ setback_q <= setback_d;
+ end
+ end
+
+endmodule
diff --git a/rtl/HMR/hmr_registers_reg_pkg.sv b/rtl/HMR/hmr_registers_reg_pkg.sv
new file mode 100644
index 00000000..1c590cce
--- /dev/null
+++ b/rtl/HMR/hmr_registers_reg_pkg.sv
@@ -0,0 +1,180 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package hmr_registers_reg_pkg;
+
+ // Param list
+ parameter int NumCores = 12;
+ parameter int NumDMRGroups = 6;
+ parameter int NumTMRGroups = 4;
+
+ // Address widths within the block
+ parameter int BlockAw = 5;
+
+ ////////////////////////////
+ // Typedefs for registers //
+ ////////////////////////////
+
+ typedef struct packed {
+ logic [5:0] q;
+ logic qe;
+ } hmr_registers_reg2hw_dmr_enable_reg_t;
+
+ typedef struct packed {
+ logic [3:0] q;
+ logic qe;
+ } hmr_registers_reg2hw_tmr_enable_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } rapid_recovery;
+ struct packed {
+ logic q;
+ logic qe;
+ } force_recovery;
+ } hmr_registers_reg2hw_dmr_config_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } delay_resynch;
+ struct packed {
+ logic q;
+ logic qe;
+ } setback;
+ struct packed {
+ logic q;
+ logic qe;
+ } reload_setback;
+ struct packed {
+ logic q;
+ logic qe;
+ } rapid_recovery;
+ struct packed {
+ logic q;
+ logic qe;
+ } force_resynch;
+ } hmr_registers_reg2hw_tmr_config_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ } independent;
+ struct packed {
+ logic d;
+ } dual;
+ struct packed {
+ logic d;
+ } triple;
+ struct packed {
+ logic d;
+ } rapid_recovery;
+ } hmr_registers_hw2reg_avail_config_reg_t;
+
+ typedef struct packed {
+ logic [11:0] d;
+ } hmr_registers_hw2reg_cores_en_reg_t;
+
+ typedef struct packed {
+ logic [5:0] d;
+ } hmr_registers_hw2reg_dmr_enable_reg_t;
+
+ typedef struct packed {
+ logic [3:0] d;
+ } hmr_registers_hw2reg_tmr_enable_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ } rapid_recovery;
+ struct packed {
+ logic d;
+ } force_recovery;
+ } hmr_registers_hw2reg_dmr_config_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ } delay_resynch;
+ struct packed {
+ logic d;
+ } setback;
+ struct packed {
+ logic d;
+ } reload_setback;
+ struct packed {
+ logic d;
+ } rapid_recovery;
+ struct packed {
+ logic d;
+ } force_resynch;
+ } hmr_registers_hw2reg_tmr_config_reg_t;
+
+ // Register -> HW type
+ typedef struct packed {
+ hmr_registers_reg2hw_dmr_enable_reg_t dmr_enable; // [25:19]
+ hmr_registers_reg2hw_tmr_enable_reg_t tmr_enable; // [18:14]
+ hmr_registers_reg2hw_dmr_config_reg_t dmr_config; // [13:10]
+ hmr_registers_reg2hw_tmr_config_reg_t tmr_config; // [9:0]
+ } hmr_registers_reg2hw_t;
+
+ // HW -> register type
+ typedef struct packed {
+ hmr_registers_hw2reg_avail_config_reg_t avail_config; // [32:29]
+ hmr_registers_hw2reg_cores_en_reg_t cores_en; // [28:17]
+ hmr_registers_hw2reg_dmr_enable_reg_t dmr_enable; // [16:11]
+ hmr_registers_hw2reg_tmr_enable_reg_t tmr_enable; // [10:7]
+ hmr_registers_hw2reg_dmr_config_reg_t dmr_config; // [6:5]
+ hmr_registers_hw2reg_tmr_config_reg_t tmr_config; // [4:0]
+ } hmr_registers_hw2reg_t;
+
+ // Register offsets
+ parameter logic [BlockAw-1:0] HMR_REGISTERS_AVAIL_CONFIG_OFFSET = 5'h 0;
+ parameter logic [BlockAw-1:0] HMR_REGISTERS_CORES_EN_OFFSET = 5'h 4;
+ parameter logic [BlockAw-1:0] HMR_REGISTERS_DMR_ENABLE_OFFSET = 5'h 8;
+ parameter logic [BlockAw-1:0] HMR_REGISTERS_TMR_ENABLE_OFFSET = 5'h c;
+ parameter logic [BlockAw-1:0] HMR_REGISTERS_DMR_CONFIG_OFFSET = 5'h 10;
+ parameter logic [BlockAw-1:0] HMR_REGISTERS_TMR_CONFIG_OFFSET = 5'h 14;
+
+ // Reset values for hwext registers and their fields
+ parameter logic [8:0] HMR_REGISTERS_AVAIL_CONFIG_RESVAL = 9'h 0;
+ parameter logic [11:0] HMR_REGISTERS_CORES_EN_RESVAL = 12'h 0;
+ parameter logic [5:0] HMR_REGISTERS_DMR_ENABLE_RESVAL = 6'h 0;
+ parameter logic [5:0] HMR_REGISTERS_DMR_ENABLE_DMR_ENABLE_RESVAL = 6'h 0;
+ parameter logic [3:0] HMR_REGISTERS_TMR_ENABLE_RESVAL = 4'h 0;
+ parameter logic [3:0] HMR_REGISTERS_TMR_ENABLE_TMR_ENABLE_RESVAL = 4'h 0;
+ parameter logic [1:0] HMR_REGISTERS_DMR_CONFIG_RESVAL = 2'h 0;
+ parameter logic [4:0] HMR_REGISTERS_TMR_CONFIG_RESVAL = 5'h 6;
+ parameter logic [0:0] HMR_REGISTERS_TMR_CONFIG_DELAY_RESYNCH_RESVAL = 1'h 0;
+ parameter logic [0:0] HMR_REGISTERS_TMR_CONFIG_SETBACK_RESVAL = 1'h 1;
+ parameter logic [0:0] HMR_REGISTERS_TMR_CONFIG_RELOAD_SETBACK_RESVAL = 1'h 1;
+ parameter logic [0:0] HMR_REGISTERS_TMR_CONFIG_FORCE_RESYNCH_RESVAL = 1'h 0;
+
+ // Register index
+ typedef enum int {
+ HMR_REGISTERS_AVAIL_CONFIG,
+ HMR_REGISTERS_CORES_EN,
+ HMR_REGISTERS_DMR_ENABLE,
+ HMR_REGISTERS_TMR_ENABLE,
+ HMR_REGISTERS_DMR_CONFIG,
+ HMR_REGISTERS_TMR_CONFIG
+ } hmr_registers_id_e;
+
+ // Register width information to check illegal writes
+ parameter logic [3:0] HMR_REGISTERS_PERMIT [6] = '{
+ 4'b 0011, // index[0] HMR_REGISTERS_AVAIL_CONFIG
+ 4'b 0011, // index[1] HMR_REGISTERS_CORES_EN
+ 4'b 0001, // index[2] HMR_REGISTERS_DMR_ENABLE
+ 4'b 0001, // index[3] HMR_REGISTERS_TMR_ENABLE
+ 4'b 0001, // index[4] HMR_REGISTERS_DMR_CONFIG
+ 4'b 0001 // index[5] HMR_REGISTERS_TMR_CONFIG
+ };
+
+endpackage
+
diff --git a/rtl/HMR/hmr_registers_reg_top.sv b/rtl/HMR/hmr_registers_reg_top.sv
new file mode 100644
index 00000000..9769fed7
--- /dev/null
+++ b/rtl/HMR/hmr_registers_reg_top.sv
@@ -0,0 +1,516 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+
+`include "common_cells/assertions.svh"
+
+module hmr_registers_reg_top #(
+ parameter type reg_req_t = logic,
+ parameter type reg_rsp_t = logic,
+ parameter int AW = 5
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ input reg_req_t reg_req_i,
+ output reg_rsp_t reg_rsp_o,
+ // To HW
+ output hmr_registers_reg_pkg::hmr_registers_reg2hw_t reg2hw, // Write
+ input hmr_registers_reg_pkg::hmr_registers_hw2reg_t hw2reg, // Read
+
+
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+ import hmr_registers_reg_pkg::* ;
+
+ localparam int DW = 32;
+ localparam int DBW = DW/8; // Byte Width
+
+ // register signals
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
+
+ logic addrmiss, wr_err;
+
+ logic [DW-1:0] reg_rdata_next;
+
+ // Below register interface can be changed
+ reg_req_t reg_intf_req;
+ reg_rsp_t reg_intf_rsp;
+
+
+ assign reg_intf_req = reg_req_i;
+ assign reg_rsp_o = reg_intf_rsp;
+
+
+ assign reg_we = reg_intf_req.valid & reg_intf_req.write;
+ assign reg_re = reg_intf_req.valid & ~reg_intf_req.write;
+ assign reg_addr = reg_intf_req.addr;
+ assign reg_wdata = reg_intf_req.wdata;
+ assign reg_be = reg_intf_req.wstrb;
+ assign reg_intf_rsp.rdata = reg_rdata;
+ assign reg_intf_rsp.error = reg_error;
+ assign reg_intf_rsp.ready = 1'b1;
+
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = (devmode_i & addrmiss) | wr_err;
+
+
+ // Define SW related signals
+ // Format: __{wd|we|qs}
+ // or _{wd|we|qs} if field == 1 or 0
+ logic avail_config_independent_qs;
+ logic avail_config_independent_re;
+ logic avail_config_dual_qs;
+ logic avail_config_dual_re;
+ logic avail_config_triple_qs;
+ logic avail_config_triple_re;
+ logic avail_config_rapid_recovery_qs;
+ logic avail_config_rapid_recovery_re;
+ logic [11:0] cores_en_qs;
+ logic cores_en_re;
+ logic [5:0] dmr_enable_qs;
+ logic [5:0] dmr_enable_wd;
+ logic dmr_enable_we;
+ logic dmr_enable_re;
+ logic [3:0] tmr_enable_qs;
+ logic [3:0] tmr_enable_wd;
+ logic tmr_enable_we;
+ logic tmr_enable_re;
+ logic dmr_config_rapid_recovery_qs;
+ logic dmr_config_rapid_recovery_wd;
+ logic dmr_config_rapid_recovery_we;
+ logic dmr_config_rapid_recovery_re;
+ logic dmr_config_force_recovery_qs;
+ logic dmr_config_force_recovery_wd;
+ logic dmr_config_force_recovery_we;
+ logic dmr_config_force_recovery_re;
+ logic tmr_config_delay_resynch_qs;
+ logic tmr_config_delay_resynch_wd;
+ logic tmr_config_delay_resynch_we;
+ logic tmr_config_delay_resynch_re;
+ logic tmr_config_setback_qs;
+ logic tmr_config_setback_wd;
+ logic tmr_config_setback_we;
+ logic tmr_config_setback_re;
+ logic tmr_config_reload_setback_qs;
+ logic tmr_config_reload_setback_wd;
+ logic tmr_config_reload_setback_we;
+ logic tmr_config_reload_setback_re;
+ logic tmr_config_rapid_recovery_qs;
+ logic tmr_config_rapid_recovery_wd;
+ logic tmr_config_rapid_recovery_we;
+ logic tmr_config_rapid_recovery_re;
+ logic tmr_config_force_resynch_qs;
+ logic tmr_config_force_resynch_wd;
+ logic tmr_config_force_resynch_we;
+ logic tmr_config_force_resynch_re;
+
+ // Register instances
+ // R[avail_config]: V(True)
+
+ // F[independent]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_avail_config_independent (
+ .re (avail_config_independent_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.avail_config.independent.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (avail_config_independent_qs)
+ );
+
+
+ // F[dual]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_avail_config_dual (
+ .re (avail_config_dual_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.avail_config.dual.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (avail_config_dual_qs)
+ );
+
+
+ // F[triple]: 2:2
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_avail_config_triple (
+ .re (avail_config_triple_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.avail_config.triple.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (avail_config_triple_qs)
+ );
+
+
+ // F[rapid_recovery]: 8:8
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_avail_config_rapid_recovery (
+ .re (avail_config_rapid_recovery_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.avail_config.rapid_recovery.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (avail_config_rapid_recovery_qs)
+ );
+
+
+ // R[cores_en]: V(True)
+
+ prim_subreg_ext #(
+ .DW (12)
+ ) u_cores_en (
+ .re (cores_en_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.cores_en.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .qs (cores_en_qs)
+ );
+
+
+ // R[dmr_enable]: V(True)
+
+ prim_subreg_ext #(
+ .DW (6)
+ ) u_dmr_enable (
+ .re (dmr_enable_re),
+ .we (dmr_enable_we),
+ .wd (dmr_enable_wd),
+ .d (hw2reg.dmr_enable.d),
+ .qre (),
+ .qe (reg2hw.dmr_enable.qe),
+ .q (reg2hw.dmr_enable.q ),
+ .qs (dmr_enable_qs)
+ );
+
+
+ // R[tmr_enable]: V(True)
+
+ prim_subreg_ext #(
+ .DW (4)
+ ) u_tmr_enable (
+ .re (tmr_enable_re),
+ .we (tmr_enable_we),
+ .wd (tmr_enable_wd),
+ .d (hw2reg.tmr_enable.d),
+ .qre (),
+ .qe (reg2hw.tmr_enable.qe),
+ .q (reg2hw.tmr_enable.q ),
+ .qs (tmr_enable_qs)
+ );
+
+
+ // R[dmr_config]: V(True)
+
+ // F[rapid_recovery]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_dmr_config_rapid_recovery (
+ .re (dmr_config_rapid_recovery_re),
+ .we (dmr_config_rapid_recovery_we),
+ .wd (dmr_config_rapid_recovery_wd),
+ .d (hw2reg.dmr_config.rapid_recovery.d),
+ .qre (),
+ .qe (reg2hw.dmr_config.rapid_recovery.qe),
+ .q (reg2hw.dmr_config.rapid_recovery.q ),
+ .qs (dmr_config_rapid_recovery_qs)
+ );
+
+
+ // F[force_recovery]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_dmr_config_force_recovery (
+ .re (dmr_config_force_recovery_re),
+ .we (dmr_config_force_recovery_we),
+ .wd (dmr_config_force_recovery_wd),
+ .d (hw2reg.dmr_config.force_recovery.d),
+ .qre (),
+ .qe (reg2hw.dmr_config.force_recovery.qe),
+ .q (reg2hw.dmr_config.force_recovery.q ),
+ .qs (dmr_config_force_recovery_qs)
+ );
+
+
+ // R[tmr_config]: V(True)
+
+ // F[delay_resynch]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_tmr_config_delay_resynch (
+ .re (tmr_config_delay_resynch_re),
+ .we (tmr_config_delay_resynch_we),
+ .wd (tmr_config_delay_resynch_wd),
+ .d (hw2reg.tmr_config.delay_resynch.d),
+ .qre (),
+ .qe (reg2hw.tmr_config.delay_resynch.qe),
+ .q (reg2hw.tmr_config.delay_resynch.q ),
+ .qs (tmr_config_delay_resynch_qs)
+ );
+
+
+ // F[setback]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_tmr_config_setback (
+ .re (tmr_config_setback_re),
+ .we (tmr_config_setback_we),
+ .wd (tmr_config_setback_wd),
+ .d (hw2reg.tmr_config.setback.d),
+ .qre (),
+ .qe (reg2hw.tmr_config.setback.qe),
+ .q (reg2hw.tmr_config.setback.q ),
+ .qs (tmr_config_setback_qs)
+ );
+
+
+ // F[reload_setback]: 2:2
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_tmr_config_reload_setback (
+ .re (tmr_config_reload_setback_re),
+ .we (tmr_config_reload_setback_we),
+ .wd (tmr_config_reload_setback_wd),
+ .d (hw2reg.tmr_config.reload_setback.d),
+ .qre (),
+ .qe (reg2hw.tmr_config.reload_setback.qe),
+ .q (reg2hw.tmr_config.reload_setback.q ),
+ .qs (tmr_config_reload_setback_qs)
+ );
+
+
+ // F[rapid_recovery]: 3:3
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_tmr_config_rapid_recovery (
+ .re (tmr_config_rapid_recovery_re),
+ .we (tmr_config_rapid_recovery_we),
+ .wd (tmr_config_rapid_recovery_wd),
+ .d (hw2reg.tmr_config.rapid_recovery.d),
+ .qre (),
+ .qe (reg2hw.tmr_config.rapid_recovery.qe),
+ .q (reg2hw.tmr_config.rapid_recovery.q ),
+ .qs (tmr_config_rapid_recovery_qs)
+ );
+
+
+ // F[force_resynch]: 4:4
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_tmr_config_force_resynch (
+ .re (tmr_config_force_resynch_re),
+ .we (tmr_config_force_resynch_we),
+ .wd (tmr_config_force_resynch_wd),
+ .d (hw2reg.tmr_config.force_resynch.d),
+ .qre (),
+ .qe (reg2hw.tmr_config.force_resynch.qe),
+ .q (reg2hw.tmr_config.force_resynch.q ),
+ .qs (tmr_config_force_resynch_qs)
+ );
+
+
+
+
+ logic [5:0] addr_hit;
+ always_comb begin
+ addr_hit = '0;
+ addr_hit[0] = (reg_addr == HMR_REGISTERS_AVAIL_CONFIG_OFFSET);
+ addr_hit[1] = (reg_addr == HMR_REGISTERS_CORES_EN_OFFSET);
+ addr_hit[2] = (reg_addr == HMR_REGISTERS_DMR_ENABLE_OFFSET);
+ addr_hit[3] = (reg_addr == HMR_REGISTERS_TMR_ENABLE_OFFSET);
+ addr_hit[4] = (reg_addr == HMR_REGISTERS_DMR_CONFIG_OFFSET);
+ addr_hit[5] = (reg_addr == HMR_REGISTERS_TMR_CONFIG_OFFSET);
+ end
+
+ assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+ // Check sub-word write is permitted
+ always_comb begin
+ wr_err = (reg_we &
+ ((addr_hit[0] & (|(HMR_REGISTERS_PERMIT[0] & ~reg_be))) |
+ (addr_hit[1] & (|(HMR_REGISTERS_PERMIT[1] & ~reg_be))) |
+ (addr_hit[2] & (|(HMR_REGISTERS_PERMIT[2] & ~reg_be))) |
+ (addr_hit[3] & (|(HMR_REGISTERS_PERMIT[3] & ~reg_be))) |
+ (addr_hit[4] & (|(HMR_REGISTERS_PERMIT[4] & ~reg_be))) |
+ (addr_hit[5] & (|(HMR_REGISTERS_PERMIT[5] & ~reg_be)))));
+ end
+
+ assign avail_config_independent_re = addr_hit[0] & reg_re & !reg_error;
+
+ assign avail_config_dual_re = addr_hit[0] & reg_re & !reg_error;
+
+ assign avail_config_triple_re = addr_hit[0] & reg_re & !reg_error;
+
+ assign avail_config_rapid_recovery_re = addr_hit[0] & reg_re & !reg_error;
+
+ assign cores_en_re = addr_hit[1] & reg_re & !reg_error;
+
+ assign dmr_enable_we = addr_hit[2] & reg_we & !reg_error;
+ assign dmr_enable_wd = reg_wdata[5:0];
+ assign dmr_enable_re = addr_hit[2] & reg_re & !reg_error;
+
+ assign tmr_enable_we = addr_hit[3] & reg_we & !reg_error;
+ assign tmr_enable_wd = reg_wdata[3:0];
+ assign tmr_enable_re = addr_hit[3] & reg_re & !reg_error;
+
+ assign dmr_config_rapid_recovery_we = addr_hit[4] & reg_we & !reg_error;
+ assign dmr_config_rapid_recovery_wd = reg_wdata[0];
+ assign dmr_config_rapid_recovery_re = addr_hit[4] & reg_re & !reg_error;
+
+ assign dmr_config_force_recovery_we = addr_hit[4] & reg_we & !reg_error;
+ assign dmr_config_force_recovery_wd = reg_wdata[1];
+ assign dmr_config_force_recovery_re = addr_hit[4] & reg_re & !reg_error;
+
+ assign tmr_config_delay_resynch_we = addr_hit[5] & reg_we & !reg_error;
+ assign tmr_config_delay_resynch_wd = reg_wdata[0];
+ assign tmr_config_delay_resynch_re = addr_hit[5] & reg_re & !reg_error;
+
+ assign tmr_config_setback_we = addr_hit[5] & reg_we & !reg_error;
+ assign tmr_config_setback_wd = reg_wdata[1];
+ assign tmr_config_setback_re = addr_hit[5] & reg_re & !reg_error;
+
+ assign tmr_config_reload_setback_we = addr_hit[5] & reg_we & !reg_error;
+ assign tmr_config_reload_setback_wd = reg_wdata[2];
+ assign tmr_config_reload_setback_re = addr_hit[5] & reg_re & !reg_error;
+
+ assign tmr_config_rapid_recovery_we = addr_hit[5] & reg_we & !reg_error;
+ assign tmr_config_rapid_recovery_wd = reg_wdata[3];
+ assign tmr_config_rapid_recovery_re = addr_hit[5] & reg_re & !reg_error;
+
+ assign tmr_config_force_resynch_we = addr_hit[5] & reg_we & !reg_error;
+ assign tmr_config_force_resynch_wd = reg_wdata[4];
+ assign tmr_config_force_resynch_re = addr_hit[5] & reg_re & !reg_error;
+
+ // Read data return
+ always_comb begin
+ reg_rdata_next = '0;
+ unique case (1'b1)
+ addr_hit[0]: begin
+ reg_rdata_next[0] = avail_config_independent_qs;
+ reg_rdata_next[1] = avail_config_dual_qs;
+ reg_rdata_next[2] = avail_config_triple_qs;
+ reg_rdata_next[8] = avail_config_rapid_recovery_qs;
+ end
+
+ addr_hit[1]: begin
+ reg_rdata_next[11:0] = cores_en_qs;
+ end
+
+ addr_hit[2]: begin
+ reg_rdata_next[5:0] = dmr_enable_qs;
+ end
+
+ addr_hit[3]: begin
+ reg_rdata_next[3:0] = tmr_enable_qs;
+ end
+
+ addr_hit[4]: begin
+ reg_rdata_next[0] = dmr_config_rapid_recovery_qs;
+ reg_rdata_next[1] = dmr_config_force_recovery_qs;
+ end
+
+ addr_hit[5]: begin
+ reg_rdata_next[0] = tmr_config_delay_resynch_qs;
+ reg_rdata_next[1] = tmr_config_setback_qs;
+ reg_rdata_next[2] = tmr_config_reload_setback_qs;
+ reg_rdata_next[3] = tmr_config_rapid_recovery_qs;
+ reg_rdata_next[4] = tmr_config_force_resynch_qs;
+ end
+
+ default: begin
+ reg_rdata_next = '1;
+ end
+ endcase
+ end
+
+ // Unused signal tieoff
+
+ // wdata / byte enable are not always fully used
+ // add a blanket unused statement to handle lint waivers
+ logic unused_wdata;
+ logic unused_be;
+ assign unused_wdata = ^reg_wdata;
+ assign unused_be = ^reg_be;
+
+ // Assertions for Register Interface
+ `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+endmodule
+
+module hmr_registers_reg_top_intf
+#(
+ parameter int AW = 5,
+ localparam int DW = 32
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ REG_BUS.in regbus_slave,
+ // To HW
+ output hmr_registers_reg_pkg::hmr_registers_reg2hw_t reg2hw, // Write
+ input hmr_registers_reg_pkg::hmr_registers_hw2reg_t hw2reg, // Read
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+ localparam int unsigned STRB_WIDTH = DW/8;
+
+`include "register_interface/typedef.svh"
+`include "register_interface/assign.svh"
+
+ // Define structs for reg_bus
+ typedef logic [AW-1:0] addr_t;
+ typedef logic [DW-1:0] data_t;
+ typedef logic [STRB_WIDTH-1:0] strb_t;
+ `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t)
+
+ reg_bus_req_t s_reg_req;
+ reg_bus_rsp_t s_reg_rsp;
+
+ // Assign SV interface to structs
+ `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave)
+ `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp)
+
+
+
+ hmr_registers_reg_top #(
+ .reg_req_t(reg_bus_req_t),
+ .reg_rsp_t(reg_bus_rsp_t),
+ .AW(AW)
+ ) i_regs (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(s_reg_req),
+ .reg_rsp_o(s_reg_rsp),
+ .reg2hw, // Write
+ .hw2reg, // Read
+ .devmode_i
+ );
+
+endmodule
+
+
diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv
new file mode 100644
index 00000000..6f05db62
--- /dev/null
+++ b/rtl/HMR/hmr_tmr_ctrl.sv
@@ -0,0 +1,238 @@
+// Copyright 2022 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Hybrid modular redundancy TMR control unit
+
+module hmr_tmr_ctrl #(
+ parameter bit InterleaveGrps = 1'b0,
+ parameter bit TMRFixed = 1'b0,
+ parameter bit DefaultInTMR = TMRFixed ? 1'b1 : 1'b0,
+ parameter bit RapidRecovery = 1'b0,
+ parameter type reg_req_t = logic,
+ parameter type reg_resp_t = logic
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ // input logic test_enable_i,
+
+ // Register interface
+ input reg_req_t reg_req_i,
+ output reg_resp_t reg_resp_o,
+
+ // CTRL from external (e.g. HMR ctrl regs)
+ input logic tmr_enable_q_i,
+ input logic tmr_enable_qe_i,
+ input logic delay_resynch_q_i,
+ input logic delay_resynch_qe_i,
+ input logic setback_q_i,
+ input logic setback_qe_i,
+ input logic reload_setback_q_i,
+ input logic reload_setback_qe_i,
+ input logic rapid_recovery_q_i,
+ input logic rapid_recovery_qe_i,
+ input logic force_resynch_q_i,
+ input logic force_resynch_qe_i,
+
+ // TMR control signals
+ output logic [2:0] setback_o,
+ output logic sw_resynch_req_o,
+ output logic sw_synch_req_o,
+ output logic grp_in_independent_o,
+ output logic rapid_recovery_en_o,
+ output logic [2:0] tmr_incr_mismatches_o,
+ input logic tmr_single_mismatch_i,
+ input logic [2:0] tmr_error_i,
+ input logic tmr_failure_i,
+ input logic sp_store_is_zero,
+ input logic sp_store_will_be_zero,
+ input logic fetch_en_i,
+ input logic cores_synch_i,
+ output logic recovery_request_o,
+ input logic recovery_finished_i
+);
+
+ logic synch_req, synch_req_sent_d, synch_req_sent_q;
+ logic resynch_req, resynch_req_sent_d, resynch_req_sent_q;
+ logic cores_synch_q;
+
+ typedef enum logic [2:0] {NON_TMR, TMR_RUN, TMR_UNLOAD, TMR_RELOAD, TMR_RAPID} tmr_mode_e;
+ localparam tmr_mode_e DefaultTMRMode = DefaultInTMR || TMRFixed ? TMR_RUN : NON_TMR;
+
+ hmr_tmr_regs_reg_pkg::hmr_tmr_regs_reg2hw_t tmr_reg2hw;
+ hmr_tmr_regs_reg_pkg::hmr_tmr_regs_hw2reg_t tmr_hw2reg;
+
+ tmr_mode_e tmr_red_mode_d, tmr_red_mode_q;
+
+ assign grp_in_independent_o = tmr_red_mode_q == NON_TMR;
+ assign tmr_resynch_req_o = tmr_red_mode_q == TMR_UNLOAD;
+ assign rapid_recovery_en_o = tmr_reg2hw.tmr_config.rapid_recovery.q & RapidRecovery;
+
+ assign sw_synch_req_o = synch_req & ~synch_req_sent_q;
+ assign synch_req_sent_d = synch_req;
+ assign sw_resynch_req_o = resynch_req & ~resynch_req_sent_q;
+ assign resynch_req_sent_d = resynch_req;
+
+ hmr_tmr_regs_reg_top #(
+ .reg_req_t(reg_req_t),
+ .reg_rsp_t(reg_resp_t)
+ ) i_tmr_regs (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(reg_req_i),
+ .reg_rsp_o(reg_resp_o),
+ .reg2hw (tmr_reg2hw),
+ .hw2reg (tmr_hw2reg),
+ .devmode_i('0)
+ );
+
+ // Global config update
+ assign tmr_hw2reg.tmr_enable.de = tmr_enable_qe_i;
+ assign tmr_hw2reg.tmr_enable.d = tmr_enable_q_i;
+ assign tmr_hw2reg.tmr_config.delay_resynch.de = delay_resynch_qe_i;
+ assign tmr_hw2reg.tmr_config.delay_resynch.d = delay_resynch_q_i;
+ assign tmr_hw2reg.tmr_config.setback.de = setback_qe_i;
+ assign tmr_hw2reg.tmr_config.setback.d = setback_q_i;
+ assign tmr_hw2reg.tmr_config.reload_setback.de = reload_setback_qe_i;
+ assign tmr_hw2reg.tmr_config.reload_setback.d = reload_setback_q_i;
+ assign tmr_hw2reg.tmr_config.rapid_recovery.de = rapid_recovery_qe_i;
+ assign tmr_hw2reg.tmr_config.rapid_recovery.d = rapid_recovery_q_i;
+ assign tmr_hw2reg.tmr_config.force_resynch.d = force_resynch_qe_i ? force_resynch_q_i : 1'b0;
+
+ /**************************
+ * FSM for TMR lockstep *
+ **************************/
+ always_comb begin : proc_fsm
+ setback_o = 3'b000;
+ tmr_red_mode_d = tmr_red_mode_q;
+ tmr_incr_mismatches_o = '0;
+ recovery_request_o = 1'b0;
+ resynch_req = 1'b0;
+ synch_req = 1'b0;
+
+ tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i;
+
+ case (tmr_red_mode_q)
+ TMR_RUN: begin
+ // If forced execute resynchronization
+ if (tmr_reg2hw.tmr_config.force_resynch.q) begin
+ tmr_hw2reg.tmr_config.force_resynch.de = 1'b1;
+ if (tmr_reg2hw.tmr_config.rapid_recovery.q == 1'b1 && RapidRecovery) begin
+ tmr_red_mode_d = TMR_RAPID;
+ end else if (tmr_reg2hw.tmr_config.delay_resynch.q == '0) begin
+ tmr_red_mode_d = TMR_UNLOAD;
+ // TODO: buffer the restoration until delay_resynch is disabled
+ end
+ end
+
+ // If error detected, do resynchronization
+ if (tmr_single_mismatch_i) begin
+ $display("[HMR-triple] %t - mismatch detected", $realtime);
+ if (tmr_error_i[0]) tmr_incr_mismatches_o[0] = 1'b1;
+ if (tmr_error_i[1]) tmr_incr_mismatches_o[1] = 1'b1;
+ if (tmr_error_i[2]) tmr_incr_mismatches_o[2] = 1'b1;
+
+ if (tmr_reg2hw.tmr_config.rapid_recovery.q == 1'b1 && RapidRecovery) begin
+ tmr_red_mode_d = TMR_RAPID;
+ end else if (tmr_reg2hw.tmr_config.delay_resynch.q == '0) begin
+ tmr_red_mode_d = TMR_UNLOAD;
+ // TODO: buffer the restoration until delay_resynch is disabled
+ end
+ end
+ end
+
+ TMR_UNLOAD: begin
+ resynch_req = 1'b1;
+ // If unload complete, go to reload (and reset)
+ if (!sp_store_is_zero) begin
+ tmr_red_mode_d = TMR_RELOAD;
+ if (tmr_reg2hw.tmr_config.setback.q) begin
+ setback_o = 3'b111;
+ end
+ end
+ end
+
+ TMR_RELOAD: begin
+ // If reload complete, finish (or reset if error happens during reload)
+ if (sp_store_is_zero) begin
+ $display("[HMR-triple] %t - mismatch restored", $realtime);
+ tmr_red_mode_d = TMR_RUN;
+ end else begin
+ if ((tmr_single_mismatch_i || tmr_failure_i) && tmr_reg2hw.tmr_config.setback.q &&
+ tmr_reg2hw.tmr_config.reload_setback.q &&
+ !sp_store_will_be_zero) begin
+ setback_o = 3'b111;
+ end
+ end
+ end
+
+ TMR_RAPID: begin
+ recovery_request_o = 1'b1;
+ if (recovery_finished_i) begin
+ $display("[HMR-triple] %t - mismatch restored", $realtime);
+ tmr_red_mode_d = TMR_RUN;
+ end
+ end
+
+ // Default: do nothing
+
+ endcase
+
+ // Logic to switch in and out of TMR
+ if (!TMRFixed) begin
+ // Set TMR mode on external signal that cores are synchronized
+ if (tmr_red_mode_q == NON_TMR && tmr_reg2hw.tmr_enable.q == 1'b1) begin
+ synch_req = 1'b1;
+ if (cores_synch_q == 1'b1) begin
+ if (tmr_reg2hw.tmr_config.rapid_recovery.q == 1'b1 && RapidRecovery) begin
+ tmr_red_mode_d = TMR_RAPID;
+ end else begin
+ tmr_red_mode_d = TMR_RELOAD;
+ if (tmr_reg2hw.tmr_config.setback.q == 1'b1) begin
+ setback_o = 3'b111;
+ end
+ end
+ end
+ end
+ // Before core startup: set TMR mode from reg2hw.tmr_enable
+ if (fetch_en_i == 0) begin
+ if (tmr_reg2hw.tmr_enable.q == 1'b0) begin
+ tmr_red_mode_d = NON_TMR;
+ end else begin
+ tmr_red_mode_d = TMR_RUN;
+ synch_req = 1'b0;
+ end
+ end
+ // split tolerant mode to performance mode anytime (but require correct core state)
+ if (tmr_red_mode_q == TMR_RUN) begin
+ if (tmr_reg2hw.tmr_enable.q == 1'b0) begin
+ if (tmr_reg2hw.tmr_config.setback.q) begin
+ setback_o = 3'b110;
+ end
+ tmr_red_mode_d = NON_TMR;
+ end
+ end
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin : proc_red_mode
+ if(!rst_ni) begin
+ tmr_red_mode_q <= DefaultTMRMode;
+ synch_req_sent_q <= '0;
+ resynch_req_sent_q <= '0;
+ cores_synch_q <= '0;
+ end else begin
+ tmr_red_mode_q <= tmr_red_mode_d;
+ synch_req_sent_q <= synch_req_sent_d;
+ resynch_req_sent_q <= resynch_req_sent_d;
+ cores_synch_q <= cores_synch_i;
+ end
+ end
+
+endmodule
diff --git a/rtl/HMR/hmr_tmr_regs_reg_pkg.sv b/rtl/HMR/hmr_tmr_regs_reg_pkg.sv
new file mode 100644
index 00000000..89eeca99
--- /dev/null
+++ b/rtl/HMR/hmr_tmr_regs_reg_pkg.sv
@@ -0,0 +1,101 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package hmr_tmr_regs_reg_pkg;
+
+ // Address widths within the block
+ parameter int BlockAw = 3;
+
+ ////////////////////////////
+ // Typedefs for registers //
+ ////////////////////////////
+
+ typedef struct packed {
+ logic q;
+ logic qe;
+ } hmr_tmr_regs_reg2hw_tmr_enable_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } delay_resynch;
+ struct packed {
+ logic q;
+ logic qe;
+ } setback;
+ struct packed {
+ logic q;
+ logic qe;
+ } reload_setback;
+ struct packed {
+ logic q;
+ logic qe;
+ } rapid_recovery;
+ struct packed {
+ logic q;
+ logic qe;
+ } force_resynch;
+ } hmr_tmr_regs_reg2hw_tmr_config_reg_t;
+
+ typedef struct packed {
+ logic d;
+ logic de;
+ } hmr_tmr_regs_hw2reg_tmr_enable_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ logic de;
+ } delay_resynch;
+ struct packed {
+ logic d;
+ logic de;
+ } setback;
+ struct packed {
+ logic d;
+ logic de;
+ } reload_setback;
+ struct packed {
+ logic d;
+ logic de;
+ } rapid_recovery;
+ struct packed {
+ logic d;
+ logic de;
+ } force_resynch;
+ } hmr_tmr_regs_hw2reg_tmr_config_reg_t;
+
+ // Register -> HW type
+ typedef struct packed {
+ hmr_tmr_regs_reg2hw_tmr_enable_reg_t tmr_enable; // [11:10]
+ hmr_tmr_regs_reg2hw_tmr_config_reg_t tmr_config; // [9:0]
+ } hmr_tmr_regs_reg2hw_t;
+
+ // HW -> register type
+ typedef struct packed {
+ hmr_tmr_regs_hw2reg_tmr_enable_reg_t tmr_enable; // [11:10]
+ hmr_tmr_regs_hw2reg_tmr_config_reg_t tmr_config; // [9:0]
+ } hmr_tmr_regs_hw2reg_t;
+
+ // Register offsets
+ parameter logic [BlockAw-1:0] HMR_TMR_REGS_TMR_ENABLE_OFFSET = 3'h 0;
+ parameter logic [BlockAw-1:0] HMR_TMR_REGS_TMR_CONFIG_OFFSET = 3'h 4;
+
+ // Register index
+ typedef enum int {
+ HMR_TMR_REGS_TMR_ENABLE,
+ HMR_TMR_REGS_TMR_CONFIG
+ } hmr_tmr_regs_id_e;
+
+ // Register width information to check illegal writes
+ parameter logic [3:0] HMR_TMR_REGS_PERMIT [2] = '{
+ 4'b 0001, // index[0] HMR_TMR_REGS_TMR_ENABLE
+ 4'b 0001 // index[1] HMR_TMR_REGS_TMR_CONFIG
+ };
+
+endpackage
+
diff --git a/rtl/HMR/hmr_tmr_regs_reg_top.sv b/rtl/HMR/hmr_tmr_regs_reg_top.sv
new file mode 100644
index 00000000..1249580e
--- /dev/null
+++ b/rtl/HMR/hmr_tmr_regs_reg_top.sv
@@ -0,0 +1,372 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+
+`include "common_cells/assertions.svh"
+
+module hmr_tmr_regs_reg_top #(
+ parameter type reg_req_t = logic,
+ parameter type reg_rsp_t = logic,
+ parameter int AW = 3
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ input reg_req_t reg_req_i,
+ output reg_rsp_t reg_rsp_o,
+ // To HW
+ output hmr_tmr_regs_reg_pkg::hmr_tmr_regs_reg2hw_t reg2hw, // Write
+ input hmr_tmr_regs_reg_pkg::hmr_tmr_regs_hw2reg_t hw2reg, // Read
+
+
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+ import hmr_tmr_regs_reg_pkg::* ;
+
+ localparam int DW = 32;
+ localparam int DBW = DW/8; // Byte Width
+
+ // register signals
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
+
+ logic addrmiss, wr_err;
+
+ logic [DW-1:0] reg_rdata_next;
+
+ // Below register interface can be changed
+ reg_req_t reg_intf_req;
+ reg_rsp_t reg_intf_rsp;
+
+
+ assign reg_intf_req = reg_req_i;
+ assign reg_rsp_o = reg_intf_rsp;
+
+
+ assign reg_we = reg_intf_req.valid & reg_intf_req.write;
+ assign reg_re = reg_intf_req.valid & ~reg_intf_req.write;
+ assign reg_addr = reg_intf_req.addr;
+ assign reg_wdata = reg_intf_req.wdata;
+ assign reg_be = reg_intf_req.wstrb;
+ assign reg_intf_rsp.rdata = reg_rdata;
+ assign reg_intf_rsp.error = reg_error;
+ assign reg_intf_rsp.ready = 1'b1;
+
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = (devmode_i & addrmiss) | wr_err;
+
+
+ // Define SW related signals
+ // Format: __{wd|we|qs}
+ // or _{wd|we|qs} if field == 1 or 0
+ logic tmr_enable_qs;
+ logic tmr_enable_wd;
+ logic tmr_enable_we;
+ logic tmr_config_delay_resynch_qs;
+ logic tmr_config_delay_resynch_wd;
+ logic tmr_config_delay_resynch_we;
+ logic tmr_config_setback_qs;
+ logic tmr_config_setback_wd;
+ logic tmr_config_setback_we;
+ logic tmr_config_reload_setback_qs;
+ logic tmr_config_reload_setback_wd;
+ logic tmr_config_reload_setback_we;
+ logic tmr_config_rapid_recovery_qs;
+ logic tmr_config_rapid_recovery_wd;
+ logic tmr_config_rapid_recovery_we;
+ logic tmr_config_force_resynch_qs;
+ logic tmr_config_force_resynch_wd;
+ logic tmr_config_force_resynch_we;
+
+ // Register instances
+ // R[tmr_enable]: V(False)
+
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h0)
+ ) u_tmr_enable (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (tmr_enable_we),
+ .wd (tmr_enable_wd),
+
+ // from internal hardware
+ .de (hw2reg.tmr_enable.de),
+ .d (hw2reg.tmr_enable.d ),
+
+ // to internal hardware
+ .qe (reg2hw.tmr_enable.qe),
+ .q (reg2hw.tmr_enable.q ),
+
+ // to register interface (read)
+ .qs (tmr_enable_qs)
+ );
+
+
+ // R[tmr_config]: V(False)
+
+ // F[delay_resynch]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h0)
+ ) u_tmr_config_delay_resynch (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (tmr_config_delay_resynch_we),
+ .wd (tmr_config_delay_resynch_wd),
+
+ // from internal hardware
+ .de (hw2reg.tmr_config.delay_resynch.de),
+ .d (hw2reg.tmr_config.delay_resynch.d ),
+
+ // to internal hardware
+ .qe (reg2hw.tmr_config.delay_resynch.qe),
+ .q (reg2hw.tmr_config.delay_resynch.q ),
+
+ // to register interface (read)
+ .qs (tmr_config_delay_resynch_qs)
+ );
+
+
+ // F[setback]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h1)
+ ) u_tmr_config_setback (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (tmr_config_setback_we),
+ .wd (tmr_config_setback_wd),
+
+ // from internal hardware
+ .de (hw2reg.tmr_config.setback.de),
+ .d (hw2reg.tmr_config.setback.d ),
+
+ // to internal hardware
+ .qe (reg2hw.tmr_config.setback.qe),
+ .q (reg2hw.tmr_config.setback.q ),
+
+ // to register interface (read)
+ .qs (tmr_config_setback_qs)
+ );
+
+
+ // F[reload_setback]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h1)
+ ) u_tmr_config_reload_setback (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (tmr_config_reload_setback_we),
+ .wd (tmr_config_reload_setback_wd),
+
+ // from internal hardware
+ .de (hw2reg.tmr_config.reload_setback.de),
+ .d (hw2reg.tmr_config.reload_setback.d ),
+
+ // to internal hardware
+ .qe (reg2hw.tmr_config.reload_setback.qe),
+ .q (reg2hw.tmr_config.reload_setback.q ),
+
+ // to register interface (read)
+ .qs (tmr_config_reload_setback_qs)
+ );
+
+
+ // F[rapid_recovery]: 3:3
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h0)
+ ) u_tmr_config_rapid_recovery (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (tmr_config_rapid_recovery_we),
+ .wd (tmr_config_rapid_recovery_wd),
+
+ // from internal hardware
+ .de (hw2reg.tmr_config.rapid_recovery.de),
+ .d (hw2reg.tmr_config.rapid_recovery.d ),
+
+ // to internal hardware
+ .qe (reg2hw.tmr_config.rapid_recovery.qe),
+ .q (reg2hw.tmr_config.rapid_recovery.q ),
+
+ // to register interface (read)
+ .qs (tmr_config_rapid_recovery_qs)
+ );
+
+
+ // F[force_resynch]: 4:4
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("RW"),
+ .RESVAL (1'h0)
+ ) u_tmr_config_force_resynch (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (tmr_config_force_resynch_we),
+ .wd (tmr_config_force_resynch_wd),
+
+ // from internal hardware
+ .de (hw2reg.tmr_config.force_resynch.de),
+ .d (hw2reg.tmr_config.force_resynch.d ),
+
+ // to internal hardware
+ .qe (reg2hw.tmr_config.force_resynch.qe),
+ .q (reg2hw.tmr_config.force_resynch.q ),
+
+ // to register interface (read)
+ .qs (tmr_config_force_resynch_qs)
+ );
+
+
+
+
+ logic [1:0] addr_hit;
+ always_comb begin
+ addr_hit = '0;
+ addr_hit[0] = (reg_addr == HMR_TMR_REGS_TMR_ENABLE_OFFSET);
+ addr_hit[1] = (reg_addr == HMR_TMR_REGS_TMR_CONFIG_OFFSET);
+ end
+
+ assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+ // Check sub-word write is permitted
+ always_comb begin
+ wr_err = (reg_we &
+ ((addr_hit[0] & (|(HMR_TMR_REGS_PERMIT[0] & ~reg_be))) |
+ (addr_hit[1] & (|(HMR_TMR_REGS_PERMIT[1] & ~reg_be)))));
+ end
+
+ assign tmr_enable_we = addr_hit[0] & reg_we & !reg_error;
+ assign tmr_enable_wd = reg_wdata[0];
+
+ assign tmr_config_delay_resynch_we = addr_hit[1] & reg_we & !reg_error;
+ assign tmr_config_delay_resynch_wd = reg_wdata[0];
+
+ assign tmr_config_setback_we = addr_hit[1] & reg_we & !reg_error;
+ assign tmr_config_setback_wd = reg_wdata[1];
+
+ assign tmr_config_reload_setback_we = addr_hit[1] & reg_we & !reg_error;
+ assign tmr_config_reload_setback_wd = reg_wdata[2];
+
+ assign tmr_config_rapid_recovery_we = addr_hit[1] & reg_we & !reg_error;
+ assign tmr_config_rapid_recovery_wd = reg_wdata[3];
+
+ assign tmr_config_force_resynch_we = addr_hit[1] & reg_we & !reg_error;
+ assign tmr_config_force_resynch_wd = reg_wdata[4];
+
+ // Read data return
+ always_comb begin
+ reg_rdata_next = '0;
+ unique case (1'b1)
+ addr_hit[0]: begin
+ reg_rdata_next[0] = tmr_enable_qs;
+ end
+
+ addr_hit[1]: begin
+ reg_rdata_next[0] = tmr_config_delay_resynch_qs;
+ reg_rdata_next[1] = tmr_config_setback_qs;
+ reg_rdata_next[2] = tmr_config_reload_setback_qs;
+ reg_rdata_next[3] = tmr_config_rapid_recovery_qs;
+ reg_rdata_next[4] = tmr_config_force_resynch_qs;
+ end
+
+ default: begin
+ reg_rdata_next = '1;
+ end
+ endcase
+ end
+
+ // Unused signal tieoff
+
+ // wdata / byte enable are not always fully used
+ // add a blanket unused statement to handle lint waivers
+ logic unused_wdata;
+ logic unused_be;
+ assign unused_wdata = ^reg_wdata;
+ assign unused_be = ^reg_be;
+
+ // Assertions for Register Interface
+ `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+endmodule
+
+module hmr_tmr_regs_reg_top_intf
+#(
+ parameter int AW = 3,
+ localparam int DW = 32
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ REG_BUS.in regbus_slave,
+ // To HW
+ output hmr_tmr_regs_reg_pkg::hmr_tmr_regs_reg2hw_t reg2hw, // Write
+ input hmr_tmr_regs_reg_pkg::hmr_tmr_regs_hw2reg_t hw2reg, // Read
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+ localparam int unsigned STRB_WIDTH = DW/8;
+
+`include "register_interface/typedef.svh"
+`include "register_interface/assign.svh"
+
+ // Define structs for reg_bus
+ typedef logic [AW-1:0] addr_t;
+ typedef logic [DW-1:0] data_t;
+ typedef logic [STRB_WIDTH-1:0] strb_t;
+ `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t)
+
+ reg_bus_req_t s_reg_req;
+ reg_bus_rsp_t s_reg_rsp;
+
+ // Assign SV interface to structs
+ `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave)
+ `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp)
+
+
+
+ hmr_tmr_regs_reg_top #(
+ .reg_req_t(reg_bus_req_t),
+ .reg_rsp_t(reg_bus_rsp_t),
+ .AW(AW)
+ ) i_regs (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(s_reg_req),
+ .reg_rsp_o(s_reg_rsp),
+ .reg2hw, // Write
+ .hw2reg, // Read
+ .devmode_i
+ );
+
+endmodule
+
+
diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv
new file mode 100644
index 00000000..a03d997f
--- /dev/null
+++ b/rtl/HMR/hmr_unit.sv
@@ -0,0 +1,987 @@
+// Copyright 2023 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Hybrid modular redundancy wrapping unit
+
+module hmr_unit #(
+ // Wrapper parameters
+ /// Number of physical cores
+ parameter int unsigned NumCores = 0,
+ /// Enables support for Dual Modular Redundancy
+ parameter bit DMRSupported = 1'b1,
+ /// Locks HMR into permanent DMR mode
+ parameter bit DMRFixed = 1'b0,
+ /// Enables support for Triple Modular Redundancy
+ parameter bit TMRSupported = 1'b1,
+ /// Locks HMR into permanent TMR mode
+ parameter bit TMRFixed = 1'b0,
+ /// Interleave DMR/TMR cores, alternatively with sequential grouping
+ parameter bit InterleaveGrps = 1'b1,
+ /// rapid recovery - tbd
+ parameter bit RapidRecovery = 1'b0,
+ /// Separates voters and checkers for data, which are then only checked if data request is valid
+ parameter bit SeparateData = 1'b1,
+ /// Separates voters and checkers for AXI buses
+ parameter bit SeparateAxiBus = 1'b0,
+ parameter bit AxiHasAce = 1'b0,
+ /// Number of separate voters/checkers for individual buses
+ parameter int unsigned NumBusVoters = 1,
+ /// Address width of the core register file (in RISC-V it should be always 6)
+ parameter int unsigned RfAddrWidth = 6,
+ parameter int unsigned SysDataWidth = 32,
+ /// General core inputs wrapping struct
+ parameter type all_inputs_t = logic,
+ /// General core outputs wrapping struct
+ parameter type nominal_outputs_t = logic,
+ /// Cores' backup output bus
+ parameter type core_backup_t = logic,
+ /// Bus outputs wrapping struct
+ parameter type bus_outputs_t = logic,
+ /// AXI output wrapping struct
+ parameter type axi_req_t = logic,
+ parameter type reg_req_t = logic,
+ parameter type reg_rsp_t = logic,
+ /// Rapid recovery structure
+ parameter type rapid_recovery_t = logic,
+ // Local parameters depending on the above ones
+ /// Number of TMR groups (virtual TMR cores)
+ localparam int unsigned NumTMRGroups = (TMRFixed || TMRSupported) ? NumCores/3 : 1,
+ /// Number of physical cores used for TMR
+ localparam int unsigned NumTMRCores = NumTMRGroups * 3,
+ /// Number of physical cores NOT used for TMR
+ localparam int unsigned NumTMRLeftover = NumCores - NumTMRCores,
+ /// Number of DMR groups (virtual DMR cores)
+ localparam int unsigned NumDMRGroups = (DMRFixed || DMRSupported) ? NumCores/2 : 1,
+ /// Nubmer of physical cores used for DMR
+ localparam int unsigned NumDMRCores = NumDMRGroups * 2,
+ /// Number of physical cores NOT used for DMR
+ localparam int unsigned NumDMRLeftover = NumCores - NumDMRCores,
+ /// Number of cores visible to the system (Fixed mode removes unneeded system ports)
+ localparam int unsigned NumSysCores = DMRFixed ? NumDMRGroups : TMRFixed ? NumTMRGroups : NumCores
+) (
+ input logic clk_i ,
+ input logic rst_ni,
+
+ // Port to configuration unit
+ input reg_req_t reg_request_i ,
+ output reg_rsp_t reg_response_o,
+
+ // TMR signals
+ output logic [NumTMRGroups-1:0] tmr_failure_o ,
+ output logic [ NumSysCores-1:0] tmr_error_o , // Should this not be NumTMRCores? or NumCores?
+ output logic [NumTMRGroups-1:0] tmr_resynch_req_o,
+ output logic [ NumCores-1:0] tmr_sw_synch_req_o,
+ input logic [NumTMRGroups-1:0] tmr_cores_synch_i,
+
+ // DMR signals
+ output logic [NumDMRGroups-1:0] dmr_failure_o ,
+ output logic [ NumSysCores-1:0] dmr_error_o , // Should this not be NumDMRCores? or NumCores?
+ output logic [NumDMRGroups-1:0] dmr_resynch_req_o,
+ output logic [ NumCores-1:0] dmr_sw_synch_req_o,
+ input logic [NumDMRGroups-1:0] dmr_cores_synch_i,
+ output logic redundancy_enable_o,
+
+ // Rapid recovery buses
+ output rapid_recovery_t [NumSysCores-1:0] rapid_recovery_o,
+ input core_backup_t [NumCores-1:0] core_backup_i,
+
+ // Boot address is handled apart from other signals
+ input logic [SysDataWidth-1:0] sys_bootaddress_i,
+ input all_inputs_t [NumSysCores-1:0] sys_inputs_i,
+ output nominal_outputs_t [NumSysCores-1:0] sys_nominal_outputs_o,
+ output bus_outputs_t [NumSysCores-1:0][NumBusVoters-1:0] sys_bus_outputs_o,
+ output axi_req_t [NumSysCores-1:0] sys_axi_outputs_o,
+ input logic [NumSysCores-1:0] sys_fetch_en_i,
+ input logic [NumSysCores-1:0][NumBusVoters-1:0] enable_bus_vote_i,
+
+ // Boot address is handled apart from other signals
+ output logic [NumCores-1:0][SysDataWidth-1:0] core_bootaddress_o,
+ output logic [NumCores-1:0] core_setback_o,
+ output all_inputs_t [NumCores-1:0] core_inputs_o,
+ input nominal_outputs_t [NumCores-1:0] core_nominal_outputs_i,
+ input bus_outputs_t [NumCores-1:0][NumBusVoters-1:0] core_bus_outputs_i,
+ input axi_req_t [NumCores-1:0] core_axi_outputs_i
+);
+ function int max(int a, int b);
+ return (a > b) ? a : b;
+ endfunction
+
+ localparam int unsigned NumBackupRegs = max(DMRSupported || DMRFixed ? NumDMRGroups : 0, TMRSupported || TMRFixed ? NumTMRGroups : 0);
+
+ function int tmr_group_id (int core_id);
+ if (InterleaveGrps) return core_id % NumTMRGroups;
+ else return (core_id/3);
+ endfunction
+
+ function int tmr_core_id (int group_id, int core_offset);
+ if (InterleaveGrps) return group_id + core_offset * NumTMRGroups;
+ else return (group_id * 3) + core_offset;
+ endfunction
+
+ function int tmr_shared_id (int group_id);
+ if (InterleaveGrps || !(DMRSupported || DMRFixed)) return group_id;
+ else return group_id + group_id/2;
+ endfunction
+
+ function int tmr_offset_id (int core_id);
+ if (InterleaveGrps) return core_id / NumTMRGroups;
+ else return core_id % 3;
+ endfunction
+
+ function int dmr_group_id (int core_id);
+ if (InterleaveGrps) return core_id % NumDMRGroups;
+ else return (core_id/2);
+ endfunction
+
+ function int dmr_core_id (int group_id, int core_offset);
+ if (InterleaveGrps) return group_id + core_offset * NumDMRGroups;
+ else return (group_id * 2) + core_offset;
+ endfunction
+
+ function int dmr_shared_id (int group_id);
+ return group_id;
+ endfunction
+
+ function int dmr_offset_id (int core_id);
+ if (InterleaveGrps) return core_id / NumDMRGroups;
+ else return core_id % 2;
+ endfunction
+
+ if (TMRFixed && DMRFixed) $fatal(1, "Cannot fix both TMR and DMR!");
+
+ nominal_outputs_t [NumTMRGroups-1:0] tmr_nominal_outputs;
+ bus_outputs_t [NumTMRGroups-1:0][NumBusVoters-1:0] tmr_bus_outputs;
+
+ nominal_outputs_t [NumDMRGroups-1:0] dmr_nominal_outputs;
+ bus_outputs_t [NumDMRGroups-1:0][NumBusVoters-1:0] dmr_bus_outputs;
+ axi_req_t [NumDMRGroups-1:0] dmr_axi_outputs;
+ core_backup_t [NumDMRGroups-1:0] dmr_backup_outputs;
+
+ logic [NumTMRGroups-1:0] tmr_failure, tmr_failure_main;
+ logic [NumTMRGroups-1:0][NumBusVoters-1:0] tmr_failure_data;
+ logic [NumTMRGroups-1:0][2:0] tmr_error, tmr_error_main;
+ logic [NumTMRGroups-1:0][NumBusVoters-1:0][2:0] tmr_error_data;
+ logic [NumTMRGroups-1:0] tmr_single_mismatch;
+
+ logic [NumDMRGroups-1:0] dmr_failure, dmr_failure_main, dmr_failure_axi, dmr_failure_backup;
+ logic [NumDMRGroups-1:0][NumBusVoters-1:0] dmr_failure_data;
+ logic [NumDMRGroups-1:0][SysDataWidth-1:0] checkpoint_reg_q;
+
+ /**************************
+ * Rapid Recovery Signals *
+ **************************/
+ logic [ NumDMRGroups-1:0] dmr_recovery_start, dmr_recovery_finished;
+ logic [ NumTMRGroups-1:0] tmr_recovery_start, tmr_recovery_finished;
+ logic [NumBackupRegs-1:0] rapid_recovery_start, rapid_recovery_finished;
+ logic [NumBackupRegs-1:0] rapid_recovery_backup_en_inp, rapid_recovery_backup_en_oup;
+ logic [NumBackupRegs-1:0] rapid_recovery_setback;
+ rapid_recovery_t [NumBackupRegs-1:0] rapid_recovery_bus;
+ core_backup_t [NumBackupRegs-1:0] rapid_recovery_backup_bus, core_backup_q;
+ nominal_outputs_t [NumBackupRegs-1:0] rapid_recovery_nominal;
+
+ /***************************
+ * HMR Control Registers *
+ ***************************/
+
+ logic [NumCores-1:0] core_en_as_master;
+ logic [NumCores-1:0] core_in_independent;
+ logic [NumCores-1:0] core_in_dmr;
+ logic [NumCores-1:0] core_in_tmr;
+ logic [NumCores-1:0] dmr_core_rapid_recovery_en;
+ logic [NumCores-1:0] tmr_core_rapid_recovery_en;
+
+ logic [NumDMRGroups-1:0][1:0] dmr_setback_q;
+ logic [NumDMRGroups-1:0] dmr_grp_in_independent;
+ logic [NumDMRGroups-1:0] dmr_rapid_recovery_en;
+
+ logic [NumTMRGroups-1:0][2:0] tmr_setback_q;
+ logic [NumTMRGroups-1:0] tmr_grp_in_independent;
+ logic [NumTMRGroups-1:0] tmr_rapid_recovery_en;
+
+ logic [NumCores-1:0] sp_store_is_zero;
+ logic [NumCores-1:0] sp_store_will_be_zero;
+
+ assign redundancy_enable_o = (|core_in_dmr) | (|core_in_tmr);
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_global_status
+ assign core_in_independent[i] = ~core_in_dmr[i] & ~core_in_tmr[i];
+ assign core_in_dmr[i] = (DMRSupported || DMRFixed) && i < NumDMRCores ? ~dmr_grp_in_independent[dmr_group_id(i)] : '0;
+ assign core_in_tmr[i] = (TMRSupported || TMRFixed) && i < NumTMRCores ? ~tmr_grp_in_independent[tmr_group_id(i)] : '0;
+ assign core_en_as_master[i] = ((tmr_core_id(tmr_group_id(i), 0) == i || i>=NumTMRCores) ? 1'b1 : ~core_in_tmr[i]) &
+ ((dmr_core_id(dmr_group_id(i), 0) == i || i>=NumDMRCores) ? 1'b1 : ~core_in_dmr[i]);
+ assign dmr_core_rapid_recovery_en[i] = (DMRSupported || DMRFixed) && i < NumDMRCores && RapidRecovery ? dmr_rapid_recovery_en[dmr_group_id(i)] : '0;
+ assign tmr_core_rapid_recovery_en[i] = (TMRSupported || TMRFixed) && i < NumTMRCores && RapidRecovery ? tmr_rapid_recovery_en[tmr_group_id(i)] : '0;
+ end
+
+ reg_req_t [3:0] top_register_reqs;
+ reg_rsp_t [3:0] top_register_resps;
+
+ // 0x000-0x100 -> Top config
+ // 0x100-0x200 -> Core configs
+ // 0x200-0x300 -> DMR configs
+ // 0x300-0x400 -> TMR configs
+
+ reg_demux #(
+ .NoPorts ( 4 ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_rsp_t )
+ ) i_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( reg_request_i.addr[9:8] ),
+ .in_req_i ( reg_request_i ),
+ .in_rsp_o ( reg_response_o ),
+ .out_req_o ( top_register_reqs ),
+ .out_rsp_i ( top_register_resps )
+ );
+
+ // Global config registers
+
+ hmr_registers_reg_pkg::hmr_registers_hw2reg_t hmr_hw2reg;
+ hmr_registers_reg_pkg::hmr_registers_reg2hw_t hmr_reg2hw;
+
+ hmr_registers_reg_top #(
+ .reg_req_t( reg_req_t ),
+ .reg_rsp_t( reg_rsp_t )
+ ) i_hmr_registers (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i(top_register_reqs[0] ),
+ .reg_rsp_o(top_register_resps[0]),
+ .reg2hw (hmr_reg2hw),
+ .hw2reg (hmr_hw2reg),
+ .devmode_i('0)
+ );
+
+ assign hmr_hw2reg.avail_config.independent.d = ~(TMRFixed | DMRFixed);
+ assign hmr_hw2reg.avail_config.dual.d = DMRFixed | DMRSupported;
+ assign hmr_hw2reg.avail_config.triple.d = TMRFixed | TMRSupported;
+ assign hmr_hw2reg.avail_config.rapid_recovery.d = RapidRecovery;
+
+ always_comb begin : proc_reg_status
+ hmr_hw2reg.cores_en.d = '0;
+ hmr_hw2reg.cores_en.d = core_en_as_master;
+
+ hmr_hw2reg.dmr_enable.d = '0;
+ hmr_hw2reg.dmr_enable.d[NumDMRGroups-1:0] = ~dmr_grp_in_independent;
+ hmr_hw2reg.tmr_enable.d = '0;
+ hmr_hw2reg.tmr_enable.d[NumTMRGroups-1:0] = ~tmr_grp_in_independent;
+ end
+
+ assign hmr_hw2reg.tmr_config.delay_resynch.d = '0;
+ assign hmr_hw2reg.tmr_config.setback.d = '0;
+ assign hmr_hw2reg.tmr_config.reload_setback.d = '0;
+ assign hmr_hw2reg.tmr_config.force_resynch.d = '0;
+ assign hmr_hw2reg.tmr_config.rapid_recovery.d = '0;
+
+ assign hmr_hw2reg.dmr_config.rapid_recovery.d = '0;
+ assign hmr_hw2reg.dmr_config.force_recovery.d = '0;
+
+ // Core Config Registers
+
+ reg_req_t [NumCores-1:0] core_register_reqs;
+ reg_rsp_t [NumCores-1:0] core_register_resps;
+
+ // 4 words per core
+
+ reg_demux #(
+ .NoPorts ( NumCores ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_rsp_t )
+ ) i_core_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( top_register_reqs [1].addr[4+$clog2(NumCores)-1:4] ),
+ .in_req_i ( top_register_reqs [1] ),
+ .in_rsp_o ( top_register_resps[1] ),
+ .out_req_o ( core_register_reqs ),
+ .out_rsp_i ( core_register_resps )
+ );
+
+ hmr_core_regs_reg_pkg::hmr_core_regs_reg2hw_t [NumCores-1:0] core_config_reg2hw;
+ hmr_core_regs_reg_pkg::hmr_core_regs_hw2reg_t [NumCores-1:0] core_config_hw2reg;
+
+ logic [NumCores-1:0] tmr_incr_mismatches;
+ logic [NumCores-1:0] dmr_incr_mismatches;
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_registers
+ hmr_core_regs_reg_top #(
+ .reg_req_t(reg_req_t),
+ .reg_rsp_t(reg_rsp_t)
+ ) icore_registers (
+ .clk_i,
+ .rst_ni,
+ .reg_req_i( core_register_reqs [i] ),
+ .reg_rsp_o( core_register_resps[i] ),
+ .reg2hw ( core_config_reg2hw [i] ),
+ .hw2reg ( core_config_hw2reg [i] ),
+ .devmode_i('0)
+ );
+
+ assign core_config_hw2reg[i].mismatches.d = core_config_reg2hw[i].mismatches.q + 1;
+ assign core_config_hw2reg[i].mismatches.de = tmr_incr_mismatches[i] | dmr_incr_mismatches[i];
+ assign core_config_hw2reg[i].current_mode.independent.d = core_in_independent[i];
+ assign core_config_hw2reg[i].current_mode.dual.d = core_in_dmr[i];
+ assign core_config_hw2reg[i].current_mode.triple.d = core_in_tmr[i];
+ assign sp_store_is_zero[i] = core_config_reg2hw[i].sp_store.q == '0;
+ assign sp_store_will_be_zero[i] = core_config_reg2hw[i].sp_store.qe && core_register_reqs[i].wdata == '0;
+ end
+
+ /**********************************************************
+ ******************** TMR Voters & Regs *******************
+ **********************************************************/
+
+ if (TMRSupported || TMRFixed) begin : gen_tmr_logic
+ if (TMRFixed && NumCores % 3 != 0) $warning("Extra cores added not properly handled!");
+
+ reg_req_t [NumTMRGroups-1:0] tmr_register_reqs;
+ reg_rsp_t [NumTMRGroups-1:0] tmr_register_resps;
+ logic [NumTMRGroups-1:0] tmr_sw_synch_req;
+
+ localparam TMRSelWidth = $clog2(NumTMRGroups);
+
+ /***************
+ * Registers *
+ ***************/
+ if (NumTMRGroups == 1) begin
+ assign tmr_register_reqs[0] = top_register_reqs[3];
+ assign top_register_resps[3] = tmr_register_resps[0];
+ end else begin
+ reg_demux #(
+ .NoPorts ( NumTMRGroups ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_rsp_t )
+ ) i_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( top_register_reqs[3].addr[4+$clog2(NumTMRGroups)-1:4] ),
+ .in_req_i ( top_register_reqs[3] ),
+ .in_rsp_o ( top_register_resps[3] ),
+ .out_req_o ( tmr_register_reqs ),
+ .out_rsp_i ( tmr_register_resps )
+ );
+ end
+
+ for (genvar i = NumTMRCores; i < NumCores; i++) begin : gen_extra_core_assigns
+ assign tmr_incr_mismatches[i] = '0;
+ assign tmr_sw_synch_req_o[i] = '0;
+ end
+
+ for (genvar i = 0; i < NumTMRGroups; i++) begin : gen_tmr_groups
+
+ hmr_tmr_ctrl #(
+ .reg_req_t ( reg_req_t ),
+ .reg_resp_t ( reg_rsp_t ),
+ .TMRFixed ( TMRFixed ),
+ .InterleaveGrps ( InterleaveGrps ),
+ .DefaultInTMR ( 1'b0 ),
+ .RapidRecovery ( RapidRecovery )
+ ) i_tmr_ctrl (
+ .clk_i,
+ .rst_ni,
+
+ .reg_req_i ( tmr_register_reqs[i] ),
+ .reg_resp_o ( tmr_register_resps[i] ),
+
+ .tmr_enable_q_i ( hmr_reg2hw.tmr_enable.q[i] ),
+ .tmr_enable_qe_i ( hmr_reg2hw.tmr_enable.qe ),
+ .delay_resynch_q_i ( hmr_reg2hw.tmr_config.delay_resynch.q ),
+ .delay_resynch_qe_i ( hmr_reg2hw.tmr_config.delay_resynch.qe ),
+ .setback_q_i ( hmr_reg2hw.tmr_config.setback.q ),
+ .setback_qe_i ( hmr_reg2hw.tmr_config.setback.qe ),
+ .reload_setback_q_i ( hmr_reg2hw.tmr_config.reload_setback.q ),
+ .reload_setback_qe_i ( hmr_reg2hw.tmr_config.reload_setback.qe ),
+ .rapid_recovery_q_i ( hmr_reg2hw.tmr_config.rapid_recovery.q ),
+ .rapid_recovery_qe_i ( hmr_reg2hw.tmr_config.rapid_recovery.qe ),
+ .force_resynch_q_i ( hmr_reg2hw.tmr_config.force_resynch.q ),
+ .force_resynch_qe_i ( hmr_reg2hw.tmr_config.force_resynch.qe ),
+
+ .setback_o ( tmr_setback_q[i] ),
+ .sw_resynch_req_o ( tmr_resynch_req_o[i] ),
+ .sw_synch_req_o ( tmr_sw_synch_req[i] ),
+ .grp_in_independent_o ( tmr_grp_in_independent[i] ),
+ .rapid_recovery_en_o ( tmr_rapid_recovery_en[i] ),
+ .tmr_incr_mismatches_o( {tmr_incr_mismatches[tmr_core_id(i,2)], tmr_incr_mismatches[tmr_core_id(i,1)], tmr_incr_mismatches[tmr_core_id(i,0)]} ),
+ .tmr_single_mismatch_i( tmr_single_mismatch[i] ),
+ .tmr_error_i ( tmr_error[i] ),
+ .tmr_failure_i ( tmr_failure[i] ),
+ .sp_store_is_zero ( sp_store_is_zero[tmr_core_id(i, 0)] ),
+ .sp_store_will_be_zero( sp_store_will_be_zero[tmr_core_id(i, 0)] ),
+
+ .fetch_en_i ( sys_fetch_en_i[tmr_core_id(i, 0)] ),
+ .cores_synch_i ( tmr_cores_synch_i[i] ),
+
+ .recovery_request_o ( tmr_recovery_start [i] ),
+ .recovery_finished_i ( tmr_recovery_finished [i] )
+ );
+
+ assign tmr_sw_synch_req_o[tmr_core_id(i, 0)] = tmr_sw_synch_req[i];
+ assign tmr_sw_synch_req_o[tmr_core_id(i, 1)] = tmr_sw_synch_req[i];
+ assign tmr_sw_synch_req_o[tmr_core_id(i, 2)] = tmr_sw_synch_req[i];
+
+ always_comb begin
+ tmr_failure[i] = tmr_failure_main[i];
+ tmr_error [i] = tmr_error_main [i];
+ for (int j = 0; j < NumBusVoters; j++) begin
+ if (enable_bus_vote_i[tmr_core_id(i, 0)][j]) begin
+ tmr_failure[i] = tmr_failure[i] | tmr_failure_data[i][j];
+ tmr_error [i] = tmr_error [i] | tmr_error_data [i][j];
+ end
+ end
+ end
+ assign tmr_single_mismatch[i] = tmr_error[i] != 3'b000;
+
+ bitwise_TMR_voter #(
+ .DataWidth( $bits(nominal_outputs_t) ),
+ .VoterType( 0 )
+ ) i_main_voter (
+ .a_i ( core_nominal_outputs_i[tmr_core_id(i, 0)] ),
+ .b_i ( core_nominal_outputs_i[tmr_core_id(i, 1)] ),
+ .c_i ( core_nominal_outputs_i[tmr_core_id(i, 2)] ),
+ .majority_o ( tmr_nominal_outputs [ i ] ),
+ .error_o ( tmr_failure_main [ i ] ),
+ .error_cba_o( tmr_error_main [ i ] )
+ );
+ if (SeparateData) begin : gen_data_voter
+ for (genvar j = 0; j < NumBusVoters; j++) begin
+ bitwise_TMR_voter #(
+ .DataWidth( $bits(bus_outputs_t) ),
+ .VoterType( 0 )
+ ) i_data_voter (
+ .a_i ( core_bus_outputs_i[tmr_core_id(i, 0)][j] ),
+ .b_i ( core_bus_outputs_i[tmr_core_id(i, 1)][j] ),
+ .c_i ( core_bus_outputs_i[tmr_core_id(i, 2)][j] ),
+ .majority_o ( tmr_bus_outputs [ i ][j] ),
+ .error_o ( tmr_failure_data [ i ][j] ),
+ .error_cba_o( tmr_error_data [ i ][j] )
+ );
+ end
+ end
+ end
+ end else begin : gen_no_tmr_voted
+ assign tmr_error_main = '0;
+ assign tmr_error_data = '0;
+ assign tmr_error = '0;
+ assign tmr_failure_main = '0;
+ assign tmr_failure_data = '0;
+ assign tmr_failure = '0;
+ assign tmr_nominal_outputs = '0;
+ assign tmr_bus_outputs = '0;
+ assign top_register_resps[3].rdata = '0;
+ assign top_register_resps[3].error = 1'b1;
+ assign top_register_resps[3].ready = 1'b1;
+ assign tmr_incr_mismatches = '0;
+ assign tmr_grp_in_independent = '1;
+ assign tmr_setback_q = '0;
+ assign tmr_resynch_req_o = '0;
+ assign tmr_sw_synch_req_o = '0;
+ end
+
+ /************************************************************
+ ******************** DMR Voters and Regs *******************
+ ************************************************************/
+
+ if (DMRSupported || DMRFixed) begin: gen_dmr_logic
+
+ hmr_dmr_regs_reg_pkg::hmr_dmr_regs_reg2hw_t [NumDMRGroups-1:0] dmr_reg2hw;
+ hmr_dmr_regs_reg_pkg::hmr_dmr_regs_hw2reg_t [NumDMRGroups-1:0] dmr_hw2reg;
+
+ reg_req_t [NumDMRGroups-1:0] dmr_register_reqs;
+ reg_rsp_t [NumDMRGroups-1:0] dmr_register_resps;
+ logic [NumDMRGroups-1:0] dmr_sw_synch_req;
+
+ localparam DMRSelWidth = $clog2(NumDMRGroups);
+
+ /***************
+ * Registers *
+ ***************/
+ if (NumDMRGroups == 1) begin
+ assign dmr_register_reqs[0] = top_register_reqs[2];
+ assign top_register_resps[2] = dmr_register_resps[0];
+ end else begin
+ reg_demux #(
+ .NoPorts ( NumDMRGroups ),
+ .req_t ( reg_req_t ),
+ .rsp_t ( reg_rsp_t )
+ ) i_reg_demux (
+ .clk_i,
+ .rst_ni,
+ .in_select_i( top_register_reqs[2].addr[4+$clog2(NumDMRGroups)-1:4] ),
+ .in_req_i ( top_register_reqs[2] ),
+ .in_rsp_o ( top_register_resps[2] ),
+ .out_req_o ( dmr_register_reqs ),
+ .out_rsp_i ( dmr_register_resps )
+ );
+ end
+
+ for (genvar i = NumDMRCores; i < NumCores; i++) begin : gen_extra_core_assigns
+ assign dmr_incr_mismatches[i] = '0;
+ assign dmr_sw_synch_req_o[i] = '0;
+ end
+
+ for (genvar i = 0; i < NumDMRGroups; i++) begin : gen_dmr_groups
+
+ hmr_dmr_ctrl #(
+ .reg_req_t ( reg_req_t ),
+ .reg_resp_t ( reg_rsp_t ),
+ .DataWidth ( SysDataWidth ),
+ .InterleaveGrps( InterleaveGrps ),
+ .DMRFixed ( DMRFixed ),
+ .RapidRecovery ( RapidRecovery ),
+ .DefaultInDMR ( 1'b0 )
+ ) i_dmr_ctrl (
+ .clk_i,
+ .rst_ni,
+
+ .reg_req_i ( dmr_register_reqs [i] ),
+ .reg_resp_o ( dmr_register_resps[i] ),
+
+ .dmr_enable_q_i ( hmr_reg2hw.dmr_enable.q[i] ),
+ .dmr_enable_qe_i ( hmr_reg2hw.dmr_enable.qe ),
+ .rapid_recovery_q_i ( hmr_reg2hw.dmr_config.rapid_recovery.q ),
+ .rapid_recovery_qe_i ( hmr_reg2hw.dmr_config.rapid_recovery.qe ),
+ .force_recovery_q_i ( hmr_reg2hw.dmr_config.force_recovery.q ),
+ .force_recovery_qe_i ( hmr_reg2hw.dmr_config.force_recovery.qe ),
+
+ .setback_o ( dmr_setback_q [i] ),
+ .sw_resynch_req_o ( dmr_resynch_req_o [i] ),
+ .sw_synch_req_o ( dmr_sw_synch_req [i] ),
+ .checkpoint_o ( checkpoint_reg_q [i] ),
+ .grp_in_independent_o ( dmr_grp_in_independent[i] ),
+ .rapid_recovery_en_o ( dmr_rapid_recovery_en [i] ),
+ .dmr_incr_mismatches_o ( {dmr_incr_mismatches[dmr_core_id(i, 1)], dmr_incr_mismatches[dmr_core_id(i, 0)]} ),
+ .dmr_error_i ( dmr_failure [i] ),
+
+ .fetch_en_i ( sys_fetch_en_i[dmr_core_id(i, 0)] ),
+ .cores_synch_i ( dmr_cores_synch_i[i] ),
+
+ .recovery_request_o ( dmr_recovery_start [i] ),
+ .recovery_finished_i ( dmr_recovery_finished [i] )
+ );
+
+ assign dmr_sw_synch_req_o[dmr_core_id(i, 0)] = dmr_sw_synch_req[i];
+ assign dmr_sw_synch_req_o[dmr_core_id(i, 1)] = dmr_sw_synch_req[i];
+
+ /*********************
+ * DMR Core Checkers *
+ *********************/
+ DMR_checker #(
+ .check_bus_t ( nominal_outputs_t )
+ ) dmr_core_checker_main (
+ .clk_i ( ),
+ .rst_ni ( ),
+ .inp_a_i ( core_nominal_outputs_i[dmr_core_id(i, 0)] ),
+ .inp_b_i ( core_nominal_outputs_i[dmr_core_id(i, 1)] ),
+ .check_o ( dmr_nominal_outputs [ i ] ),
+ .error_o ( dmr_failure_main [ i ] )
+ );
+ if (SeparateAxiBus) begin: gen_axi_checker
+ DMR_checker #(
+ .AxiBus ( SeparateAxiBus ),
+ .AxiHasAce ( AxiHasAce ),
+ .check_bus_t ( axi_req_t )
+ ) dmr_core_checker_axi (
+ .clk_i ( ),
+ .rst_ni ( ),
+ .inp_a_i ( core_axi_outputs_i[dmr_core_id(i, 0)] ),
+ .inp_b_i ( core_axi_outputs_i[dmr_core_id(i, 1)] ),
+ .check_o ( dmr_axi_outputs [ i ] ),
+ .error_o ( dmr_failure_axi [ i ] )
+ );
+ end else begin: gen_no_axi_checker
+ assign dmr_axi_outputs[i] = '0;
+ assign dmr_failure_axi[i] = '0;
+ end
+ if (SeparateData) begin : gen_data_checker
+ for (genvar j = 0; j < NumBusVoters; j++) begin
+ DMR_checker # (
+ .check_bus_t ( bus_outputs_t )
+ ) dmr_core_checker_data (
+ .clk_i ( ),
+ .rst_ni ( ),
+ .inp_a_i ( core_bus_outputs_i[dmr_core_id(i, 0)][j] ),
+ .inp_b_i ( core_bus_outputs_i[dmr_core_id(i, 1)][j] ),
+ .check_o ( dmr_bus_outputs [ i ][j] ),
+ .error_o ( dmr_failure_data [ i ][j] )
+ );
+ end
+ end else begin: gen_no_data_checker
+ assign dmr_bus_outputs [i] = '0;
+ assign dmr_failure_data [i] = '0;
+ end
+
+ if (RapidRecovery) begin : gen_rapid_recovery_unit
+
+ DMR_checker #(
+ .check_bus_t ( core_backup_t ),
+ .Pipeline ( 1 )
+ ) dmr_core_checker_backup (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .inp_a_i ( core_backup_i [dmr_core_id(i, 0)] ),
+ .inp_b_i ( core_backup_i [dmr_core_id(i, 1)] ),
+ .check_o ( dmr_backup_outputs [ i ] ),
+ .error_o ( dmr_failure_backup [ i ] )
+ );
+
+ assign rapid_recovery_backup_en_inp[i] = core_in_tmr[i] ? (i < NumTMRGroups ? rapid_recovery_backup_en_oup[i] : 1'b0) // TMR mode
+ : core_in_dmr[i] ? (rapid_recovery_backup_en_oup[i] & ~dmr_failure[i] ) // DMR mode
+ : 1'b1; // Independent
+ rapid_recovery_unit #(
+ .RfAddrWidth ( RfAddrWidth ),
+ .DataWidth ( SysDataWidth ),
+ .regfile_write_t ( rapid_recovery_pkg::regfile_write_t ),
+ .regfile_raddr_t ( rapid_recovery_pkg::regfile_raddr_t ),
+ .regfile_rdata_t ( rapid_recovery_pkg::regfile_rdata_t ),
+ .csr_intf_t ( rapid_recovery_pkg::csrs_intf_t ),
+ .pc_intf_t ( rapid_recovery_pkg::pc_intf_t )
+ ) i_rapid_recovery_unit (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .core_in_independent_i ( core_in_independent[i] ),
+ .regfile_write_i ( rapid_recovery_backup_bus[i].regfile_backup ),
+ .backup_csr_i ( rapid_recovery_backup_bus[i].csr_backup ),
+ .recovery_csr_o ( rapid_recovery_bus[i].csr_recovery ),
+ .backup_pc_i ( rapid_recovery_backup_bus[i].pc_backup ),
+ .recovery_pc_o ( rapid_recovery_bus[i].pc_recovery ),
+ .backup_enable_i ( rapid_recovery_backup_en_inp[i] ),
+ .start_recovery_i ( rapid_recovery_start[i] ),
+ .backup_enable_o ( rapid_recovery_backup_en_oup[i] ),
+ .recovery_finished_o ( rapid_recovery_finished[i] ),
+ .setback_o ( rapid_recovery_setback[i] ),
+ .instr_lock_o ( rapid_recovery_bus[i].instr_lock ),
+ .enable_pc_recovery_o ( rapid_recovery_bus[i].pc_recovery_en ),
+ .enable_rf_recovery_o ( rapid_recovery_bus[i].rf_recovery_en ),
+ .regfile_recovery_wdata_o ( rapid_recovery_bus[i].rf_recovery_wdata ),
+ .regfile_recovery_rdata_o ( rapid_recovery_bus[i].rf_recovery_rdata ),
+ .debug_halt_i ( rapid_recovery_nominal[i].debug_halted ),
+ .debug_req_o ( rapid_recovery_bus[i].debug_req ),
+ .debug_resume_o ( rapid_recovery_bus[i].debug_resume )
+ );
+
+ always_comb begin
+ dmr_failure[i] = dmr_failure_main[i] | dmr_failure_backup[i] | dmr_failure_axi[i];
+ for (int j = 0; j < NumBusVoters; j++) begin
+ if (enable_bus_vote_i[dmr_core_id(i, 0)][j]) begin
+ dmr_failure[i] = dmr_failure[i] | dmr_failure_backup[i] | dmr_failure_data[i][j];
+ end
+ end
+ end
+ end else begin : gen_standard_failure
+ always_comb begin
+ dmr_failure[i] = dmr_failure_main[i] | dmr_failure_axi[i];
+ for (int j = 0; j < NumBusVoters; j++) begin
+ if (enable_bus_vote_i[dmr_core_id(i, 0)][j]) begin
+ dmr_failure[i] = dmr_failure[i] | dmr_failure_data[i][j];
+ end
+ end
+ end
+ end
+ end
+ end else begin: no_dmr_checkers
+ assign dmr_failure_main = '0;
+ assign dmr_failure_data = '0;
+ assign dmr_failure_axi = '0;
+ assign dmr_failure = '0;
+ assign dmr_incr_mismatches = '0;
+ assign dmr_nominal_outputs = '0;
+ assign dmr_bus_outputs = '0;
+ assign dmr_axi_outputs = '0;
+ assign top_register_resps[2].rdata = '0;
+ assign top_register_resps[2].error = 1'b1;
+ assign top_register_resps[2].ready = 1'b1;
+ assign dmr_sw_synch_req_o = '0;
+ assign dmr_grp_in_independent = '1;
+ end
+
+ if (RapidRecovery) begin: gen_rapid_recovery_connection
+
+ for (genvar i = 0; i < NumBackupRegs; i++) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin
+ if (~rst_ni) begin
+ core_backup_q[i] <= '0;
+ end else begin
+ core_backup_q[i] <= core_backup_i[i];
+ end
+ end
+ end
+
+ always_comb begin
+ rapid_recovery_nominal = '0;
+ rapid_recovery_backup_bus = '0;
+ rapid_recovery_start = '0;
+ dmr_recovery_finished = '0;
+ tmr_recovery_finished = '0;
+ if (InterleaveGrps) begin
+ for (int i = 0; i < NumBackupRegs; i++) begin
+ rapid_recovery_nominal[i] = dmr_nominal_outputs[i];
+ rapid_recovery_backup_bus[i] = core_backup_q[i];
+ rapid_recovery_start[i] = dmr_recovery_start[i];
+ dmr_recovery_finished[i] = rapid_recovery_finished[i];
+ end
+ end
+ for (int i = 0; i < NumDMRGroups; i++) begin
+ if ((DMRFixed || (DMRSupported && ~dmr_grp_in_independent[i])) && dmr_core_rapid_recovery_en[dmr_core_id(i, 0)]) begin
+ rapid_recovery_nominal[dmr_shared_id(i)] = dmr_nominal_outputs[i];
+ rapid_recovery_backup_bus[dmr_shared_id(i)] = dmr_backup_outputs[i];
+ rapid_recovery_start[dmr_shared_id(i)] = dmr_recovery_start[i];
+ dmr_recovery_finished[i] = rapid_recovery_finished[dmr_shared_id(i)];
+ end
+ end
+ for (int i = 0; i < NumTMRGroups; i++) begin
+ if ((TMRFixed || (TMRSupported && ~tmr_grp_in_independent[i])) && tmr_core_rapid_recovery_en[tmr_core_id(i, 0)]) begin
+ rapid_recovery_nominal[tmr_shared_id(i)] = tmr_nominal_outputs[i];
+ rapid_recovery_start[tmr_shared_id(i)] = tmr_recovery_start[i];
+ tmr_recovery_finished[i] = rapid_recovery_finished[tmr_shared_id(i)];
+ end
+ end
+ end
+ end else begin
+ assign core_backup_q = '0;
+ assign rapid_recovery_nominal = '0;
+ assign rapid_recovery_start = '0;
+ assign tmr_recovery_finished = '1;
+ assign dmr_recovery_finished = '1;
+ end
+
+ // Assign output signals
+ if (DMRSupported && TMRSupported) begin : gen_full_HMR
+ /*****************
+ *** TMR & DMR ***
+ *****************/
+ if (TMRFixed || DMRFixed) $fatal(1, "Cannot support both TMR and DMR and fix one!");
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs
+ localparam TMRCoreIndex = tmr_core_id(tmr_group_id(i), 0);
+ localparam DMRCoreIndex = dmr_core_id(dmr_group_id(i), 0);
+
+ always_comb begin
+ // Special signals
+ core_bootaddress_o[i] = (checkpoint_reg_q[dmr_shared_id(dmr_group_id(i))] != '0) ?
+ checkpoint_reg_q[dmr_shared_id(dmr_group_id(i))] : sys_bootaddress_i;
+ if (RapidRecovery) begin
+ // $error("UNIMPLEMENTED");
+ rapid_recovery_o [i] = (core_in_dmr[i] ? rapid_recovery_bus [dmr_shared_id(dmr_group_id(i))] :
+ (core_in_tmr[i] ? rapid_recovery_bus [tmr_shared_id(tmr_group_id(i))] : '0));
+
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]
+ | dmr_setback_q [dmr_group_id(i)][dmr_offset_id(i)]
+ | (core_in_dmr[i] ? rapid_recovery_setback [dmr_shared_id(dmr_group_id(i))] :
+ (core_in_tmr[i] ? rapid_recovery_setback [tmr_shared_id(tmr_group_id(i))] : '0));
+ end else begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]
+ | dmr_setback_q [dmr_group_id(i)][dmr_offset_id(i)];
+ end
+ if (i >= NumTMRCores && i >= NumDMRCores) begin
+ core_setback_o [i] = '0;
+ end else if (i < NumTMRCores && i >= NumDMRCores) begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]
+ | (RapidRecovery ? (core_in_tmr[i] ? rapid_recovery_setback [tmr_shared_id(tmr_group_id(i))] : '0) : '0);
+ end else if (i >= NumTMRCores && i < NumDMRCores) begin
+ core_setback_o [i] = dmr_setback_q [dmr_group_id(i)][dmr_offset_id(i)]
+ | (RapidRecovery ? (core_in_dmr[i] ? rapid_recovery_setback [dmr_shared_id(dmr_group_id(i))] : '0) : '0);
+ end
+ if (i < NumTMRCores && core_in_tmr[i]) begin : tmr_mode
+ core_inputs_o[i] = sys_inputs_i[TMRCoreIndex];
+ end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode
+ core_inputs_o[i] = sys_inputs_i[DMRCoreIndex];
+ end else begin : independent_mode
+ core_inputs_o[i] = sys_inputs_i[i];
+ end
+ end
+ end
+
+ for (genvar i = 0; i < NumSysCores/*==NumCores*/; i++) begin : gen_core_outputs
+ localparam TMRCoreIndex = tmr_group_id(i);
+ localparam DMRCoreIndex = dmr_group_id(i);
+ always_comb begin
+ if (i < NumTMRCores && core_in_tmr[i]) begin : tmr_mode
+ if (tmr_core_id(tmr_group_id(i), 0) == i) begin : is_tmr_main_core
+ sys_nominal_outputs_o[i] = tmr_nominal_outputs[TMRCoreIndex];
+ sys_bus_outputs_o[i] = tmr_bus_outputs[TMRCoreIndex];
+ sys_axi_outputs_o[i] = '0;
+ end else begin : disable_core // Assign disable
+ sys_nominal_outputs_o[i] = '0;
+ sys_bus_outputs_o[i] = '0;
+ sys_axi_outputs_o[i] = '0;
+ sys_axi_outputs_o[i].r_ready = 1'b1;
+ sys_axi_outputs_o[i].b_ready = 1'b1;
+ end
+ end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode
+ if (dmr_core_id(dmr_group_id(i), 0) == i) begin : is_dmr_main_core
+ sys_nominal_outputs_o[i] = dmr_nominal_outputs[DMRCoreIndex];
+ sys_axi_outputs_o[i] = dmr_axi_outputs[DMRCoreIndex];
+ for (int j = 0; j < NumBusVoters; j++) begin
+ sys_bus_outputs_o[i][j] = dmr_bus_outputs[DMRCoreIndex][j];
+ end
+ end else begin : disable_core // Assign disable
+ sys_nominal_outputs_o[i] = '0;
+ sys_bus_outputs_o[i] = '0;
+ sys_axi_outputs_o[i] = '0;
+ sys_axi_outputs_o[i].r_ready = 1'b1;
+ sys_axi_outputs_o[i].b_ready = 1'b1;
+ end
+ end else begin : independent_mode
+ sys_nominal_outputs_o[i] = core_nominal_outputs_i[i];
+ sys_bus_outputs_o[i] = core_bus_outputs_i[i];
+ sys_axi_outputs_o[i] = core_axi_outputs_i[i];
+ end
+ end
+ end
+
+ end else if (TMRSupported || TMRFixed) begin : gen_TMR_only
+ /*****************
+ *** TMR only ***
+ *****************/
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs
+ localparam SysCoreIndex = TMRFixed ? i/3 : tmr_core_id(tmr_group_id(i), 0);
+ always_comb begin
+ // Special signals
+ core_bootaddress_o[i] = (checkpoint_reg_q[dmr_shared_id(dmr_group_id(i))] != '0) ?
+ checkpoint_reg_q[dmr_shared_id(dmr_group_id(i))] : sys_bootaddress_i;
+ // Setback
+ if (RapidRecovery) begin
+ // $error("UNIMPLEMENTED");
+ rapid_recovery_o [i] = core_in_tmr[i] ? rapid_recovery_bus [tmr_shared_id(tmr_group_id(i))] : '0;
+
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]
+ | rapid_recovery_setback [tmr_shared_id(tmr_group_id(i))];
+ end else begin
+ core_setback_o [i] = tmr_setback_q [tmr_group_id(i)];
+ end
+ if (i >= NumTMRCores) begin
+ core_setback_o [i] = '0;
+ end
+ if (i < NumTMRCores && (TMRFixed || core_in_tmr[i])) begin : tmr_mode
+ core_inputs_o[i] = sys_inputs_i[SysCoreIndex];
+ end else begin : independent_mode
+ core_inputs_o[i] = sys_inputs_i[i];
+ end
+ end
+ end
+
+ for (genvar i = 0; i < NumSysCores; i++) begin : gen_core_outputs
+ localparam CoreCoreIndex = TMRFixed ? i : tmr_group_id(i);
+ if (TMRFixed && i < NumTMRGroups) begin : fixed_tmr
+ assign sys_nominal_outputs_o[i] = tmr_nominal_outputs[CoreCoreIndex];
+ assign sys_bus_outputs_o [i] = tmr_bus_outputs [CoreCoreIndex];
+ assign sys_axi_outputs_o [i] = '0;
+ end else begin
+ if (i >= NumTMRCores) begin : independent_stragglers
+ assign sys_nominal_outputs_o[i] = core_nominal_outputs_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign sys_bus_outputs_o [i] = core_bus_outputs_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i];
+ assign sys_axi_outputs_o [i] = '0;
+ end else begin
+ always_comb begin
+ sys_axi_outputs_o [i] = '0;
+ if (core_in_tmr[i]) begin : tmr_mode
+ if (tmr_core_id(tmr_group_id(i), 0) == i) begin : is_tmr_main_core
+ sys_nominal_outputs_o[i] = tmr_nominal_outputs[CoreCoreIndex];
+ sys_bus_outputs_o [i] = tmr_bus_outputs [CoreCoreIndex];
+ end else begin : disable_core // Assign disable
+ sys_nominal_outputs_o[i] = '0;
+ sys_bus_outputs_o [i] = '0;
+ sys_axi_outputs_o[i].r_ready = 1'b1;
+ sys_axi_outputs_o[i].b_ready = 1'b1;
+ end
+ end else begin : independent_mode
+ sys_nominal_outputs_o[i] = core_nominal_outputs_i[i];
+ sys_bus_outputs_o [i] = core_bus_outputs_i [i];
+ end
+ end
+ end
+ end
+ end
+
+ end else if (DMRSupported || DMRFixed) begin : gen_DMR_only
+ /*****************
+ *** DMR only ***
+ *****************/
+ if (DMRFixed && NumCores % 2 != 0) $warning("Extra cores added not properly handled! :)");
+ // Binding DMR outputs to zero for now
+ assign dmr_failure_o = '0;
+ assign dmr_error_o = '0;
+ // assign dmr_resynch_req_o = '0;
+
+ for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs
+ localparam SysCoreIndex = DMRFixed ? i/2 : dmr_core_id(dmr_group_id(i), 0);
+ always_comb begin
+ core_bootaddress_o[i] = (checkpoint_reg_q[SysCoreIndex] != '0) ?
+ checkpoint_reg_q[SysCoreIndex] : sys_bootaddress_i;
+ // Setback
+ if (RapidRecovery) begin
+ // $error("UNIMPLEMENTED");
+ rapid_recovery_o [i] = core_in_dmr[i] ? rapid_recovery_bus [dmr_shared_id(dmr_group_id(i))] : '0;
+
+ core_setback_o [i] = dmr_setback_q[dmr_group_id(i)][dmr_offset_id(i)]
+ | rapid_recovery_setback [dmr_shared_id(dmr_group_id(i))];
+ end else begin
+ core_setback_o [i] = dmr_setback_q[dmr_group_id(i)][dmr_offset_id(i)];
+ end
+ if (i >= NumDMRCores) begin
+ core_setback_o [i] = '0;
+ end
+ if (i < NumDMRCores && (DMRFixed || core_in_dmr[i])) begin : dmr_mode
+ core_inputs_o[i] = sys_inputs_i[SysCoreIndex];
+ end else begin : gen_independent_mode
+ core_inputs_o[i] = sys_inputs_i[i];
+ end
+ end
+ end // gen_core_inputs
+
+ for (genvar i = 0; i < NumSysCores; i++) begin : gen_core_outputs
+ localparam CoreCoreIndex = DMRFixed ? i : dmr_group_id(i);
+ if (DMRFixed && i < NumDMRGroups) begin : fixed_dmr
+ assign sys_nominal_outputs_o[i] = dmr_nominal_outputs[CoreCoreIndex];
+ assign sys_bus_outputs_o [i] = dmr_bus_outputs [CoreCoreIndex];
+ assign sys_axi_outputs_o [i] = dmr_axi_outputs [CoreCoreIndex];
+ end else begin
+ if (i >= NumDMRCores) begin : independent_stragglers
+ assign sys_nominal_outputs_o[i] = core_nominal_outputs_i[DMRFixed ? i-NumDMRGroups+NumDMRCores : i];
+ assign sys_bus_outputs_o [i] = core_bus_outputs_i [DMRFixed ? i-NumDMRGroups+NumDMRCores : i];
+ assign sys_axi_outputs_o [i] = core_axi_outputs_i [DMRFixed ? i-NumDMRGroups+NumDMRCores : i];
+ end else begin
+ always_comb begin
+ if (core_in_dmr[i]) begin : dmr_mode
+ if (dmr_core_id(dmr_group_id(i), 0) == i) begin : is_dmr_main_core
+ sys_nominal_outputs_o[i] = dmr_nominal_outputs[CoreCoreIndex];
+ sys_bus_outputs_o [i] = dmr_bus_outputs [CoreCoreIndex];
+ sys_axi_outputs_o [i] = dmr_axi_outputs [CoreCoreIndex];
+ end else begin : disable_core // Assign disable
+ sys_nominal_outputs_o[i] = '0;
+ sys_bus_outputs_o [i] = '0;
+ sys_axi_outputs_o [i] = '0;
+ sys_axi_outputs_o[i].r_ready = 1'b1;
+ sys_axi_outputs_o[i].b_ready = 1'b1;
+ end
+ end else begin : independent_mode
+ sys_nominal_outputs_o[i] = core_nominal_outputs_i[i];
+ sys_bus_outputs_o [i] = core_bus_outputs_i [i];
+ sys_axi_outputs_o [i] = core_axi_outputs_i [i];
+ end
+ end
+ end
+ end
+ end
+
+ end else begin : gen_no_redundancy
+ /*****************
+ *** none ***
+ *****************/
+ // Direct assignment, disable all
+ assign core_setback_o = '0;
+ assign core_bootaddress_o = sys_bootaddress_i;
+ assign core_inputs_o = sys_inputs_i;
+ assign sys_nominal_outputs_o = core_nominal_outputs_i;
+ assign sys_bus_outputs_o = core_bus_outputs_i;
+ assign sys_axi_outputs_o = core_axi_outputs_i;
+ end
+
+endmodule
diff --git a/rtl/HMR/hmr_v1.h b/rtl/HMR/hmr_v1.h
new file mode 100644
index 00000000..7a4e0bfa
--- /dev/null
+++ b/rtl/HMR/hmr_v1.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2023 ETH Zurich and University of Bologna
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ARCHI_HMR_HMR_V1_H__
+#define __ARCHI_HMR_HMR_V1_H__
+
+#define HMR_IN_INTERLEAVED 1
+
+#define HMR_TOP_OFFSET 0x000
+#define HMR_CORE_OFFSET 0x100
+#define HMR_DMR_OFFSET 0x200
+#define HMR_TMR_OFFSET 0x300
+
+#define HMR_CORE_INCREMENT 0x010
+#define HMR_CORE_SLL 0x004
+#define HMR_DMR_INCREMENT 0x010
+#define HMR_DMR_SLL 0x004
+#define HMR_TMR_INCREMENT 0x010
+#define HMR_TMR_SLL 0x004
+
+// Generated register defines for HMR_registers
+
+#ifndef _HMR_REGISTERS_REG_DEFS_
+#define _HMR_REGISTERS_REG_DEFS_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define HMR_REGISTERS_PARAM_NUM_CORES 12
+
+#define HMR_REGISTERS_PARAM_NUM_D_M_R_GROUPS 6
+
+#define HMR_REGISTERS_PARAM_NUM_T_M_R_GROUPS 4
+
+// Register width
+#define HMR_REGISTERS_PARAM_REG_WIDTH 32
+
+// Available Configurations from implemented hardware.
+#define HMR_REGISTERS_AVAIL_CONFIG_REG_OFFSET 0x0
+#define HMR_REGISTERS_AVAIL_CONFIG_INDEPENDENT_BIT 0
+#define HMR_REGISTERS_AVAIL_CONFIG_DUAL_BIT 1
+#define HMR_REGISTERS_AVAIL_CONFIG_TRIPLE_BIT 2
+#define HMR_REGISTERS_AVAIL_CONFIG_RAPID_RECOVERY_BIT 8
+
+// Enabled cores, based on the configuration. Can be used for barriers.
+#define HMR_REGISTERS_CORES_EN_REG_OFFSET 0x4
+#define HMR_REGISTERS_CORES_EN_CORES_EN_MASK 0xfff
+#define HMR_REGISTERS_CORES_EN_CORES_EN_OFFSET 0
+#define HMR_REGISTERS_CORES_EN_CORES_EN_FIELD \
+ ((bitfield_field32_t) { .mask = HMR_REGISTERS_CORES_EN_CORES_EN_MASK, .index = HMR_REGISTERS_CORES_EN_CORES_EN_OFFSET })
+
+// DMR configuration enable, on bit per DMR group.
+#define HMR_REGISTERS_DMR_ENABLE_REG_OFFSET 0x8
+#define HMR_REGISTERS_DMR_ENABLE_DMR_ENABLE_MASK 0x3f
+#define HMR_REGISTERS_DMR_ENABLE_DMR_ENABLE_OFFSET 0
+#define HMR_REGISTERS_DMR_ENABLE_DMR_ENABLE_FIELD \
+ ((bitfield_field32_t) { .mask = HMR_REGISTERS_DMR_ENABLE_DMR_ENABLE_MASK, .index = HMR_REGISTERS_DMR_ENABLE_DMR_ENABLE_OFFSET })
+
+// TMR configuration enable, one bit per TMR group.
+#define HMR_REGISTERS_TMR_ENABLE_REG_OFFSET 0xc
+#define HMR_REGISTERS_TMR_ENABLE_TMR_ENABLE_MASK 0xf
+#define HMR_REGISTERS_TMR_ENABLE_TMR_ENABLE_OFFSET 0
+#define HMR_REGISTERS_TMR_ENABLE_TMR_ENABLE_FIELD \
+ ((bitfield_field32_t) { .mask = HMR_REGISTERS_TMR_ENABLE_TMR_ENABLE_MASK, .index = HMR_REGISTERS_TMR_ENABLE_TMR_ENABLE_OFFSET })
+
+// DMR configuration bits.
+#define HMR_REGISTERS_DMR_CONFIG_REG_OFFSET 0x10
+#define HMR_REGISTERS_DMR_CONFIG_RAPID_RECOVERY_BIT 0
+#define HMR_REGISTERS_DMR_CONFIG_FORCE_RECOVERY_BIT 1
+
+// TMR configuration bits.
+#define HMR_REGISTERS_TMR_CONFIG_REG_OFFSET 0x14
+#define HMR_REGISTERS_TMR_CONFIG_DELAY_RESYNCH_BIT 0
+#define HMR_REGISTERS_TMR_CONFIG_SETBACK_BIT 1
+#define HMR_REGISTERS_TMR_CONFIG_RELOAD_SETBACK_BIT 2
+#define HMR_REGISTERS_TMR_CONFIG_RAPID_RECOVERY_BIT 3
+#define HMR_REGISTERS_TMR_CONFIG_FORCE_RESYNCH_BIT 4
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif // _HMR_REGISTERS_REG_DEFS_
+// End generated register defines for HMR_registers
+
+// Generated register defines for HMR_core_regs
+
+#ifndef _HMR_CORE_REGS_REG_DEFS_
+#define _HMR_CORE_REGS_REG_DEFS_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Register width
+#define HMR_CORE_REGS_PARAM_REG_WIDTH 32
+
+// Value to determine wich redundancy mode the core with that ID is in.
+#define HMR_CORE_REGS_CURRENT_MODE_REG_OFFSET 0x0
+#define HMR_CORE_REGS_CURRENT_MODE_INDEPENDENT_BIT 0
+#define HMR_CORE_REGS_CURRENT_MODE_DUAL_BIT 1
+#define HMR_CORE_REGS_CURRENT_MODE_TRIPLE_BIT 2
+
+// Mismatches of the core
+#define HMR_CORE_REGS_MISMATCHES_REG_OFFSET 0x4
+
+// Stack Pointer storage register
+#define HMR_CORE_REGS_SP_STORE_REG_OFFSET 0x8
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif // _HMR_CORE_REGS_REG_DEFS_
+// End generated register defines for HMR_core_regs
+
+// Generated register defines for HMR_dmr_regs
+
+#ifndef _HMR_DMR_REGS_REG_DEFS_
+#define _HMR_DMR_REGS_REG_DEFS_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Register width
+#define HMR_DMR_REGS_PARAM_REG_WIDTH 32
+
+// DMR configuration enable.
+#define HMR_DMR_REGS_DMR_ENABLE_REG_OFFSET 0x0
+#define HMR_DMR_REGS_DMR_ENABLE_DMR_ENABLE_BIT 0
+
+// DMR configuration bits.
+#define HMR_DMR_REGS_DMR_CONFIG_REG_OFFSET 0x4
+#define HMR_DMR_REGS_DMR_CONFIG_RAPID_RECOVERY_BIT 0
+#define HMR_DMR_REGS_DMR_CONFIG_FORCE_RECOVERY_BIT 1
+
+// Address for the last checkpoint.
+#define HMR_DMR_REGS_CHECKPOINT_ADDR_REG_OFFSET 0x8
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif // _HMR_DMR_REGS_REG_DEFS_
+// End generated register defines for HMR_dmr_regs
+
+// Generated register defines for HMR_tmr_regs
+
+#ifndef _HMR_TMR_REGS_REG_DEFS_
+#define _HMR_TMR_REGS_REG_DEFS_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Register width
+#define HMR_TMR_REGS_PARAM_REG_WIDTH 32
+
+// TMR configuration enable.
+#define HMR_TMR_REGS_TMR_ENABLE_REG_OFFSET 0x0
+#define HMR_TMR_REGS_TMR_ENABLE_TMR_ENABLE_BIT 0
+
+// TMR configuration bits.
+#define HMR_TMR_REGS_TMR_CONFIG_REG_OFFSET 0x4
+#define HMR_TMR_REGS_TMR_CONFIG_DELAY_RESYNCH_BIT 0
+#define HMR_TMR_REGS_TMR_CONFIG_SETBACK_BIT 1
+#define HMR_TMR_REGS_TMR_CONFIG_RELOAD_SETBACK_BIT 2
+#define HMR_TMR_REGS_TMR_CONFIG_RAPID_RECOVERY_BIT 3
+#define HMR_TMR_REGS_TMR_CONFIG_FORCE_RESYNCH_BIT 4
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif // _HMR_TMR_REGS_REG_DEFS_
+// End generated register defines for HMR_tmr_regs
+
+
+#endif // __ARCHI_HMR_HMR_V1_H__
diff --git a/rtl/HMR/rapid_recovery_pkg.sv b/rtl/HMR/rapid_recovery_pkg.sv
new file mode 100644
index 00000000..6a1e1044
--- /dev/null
+++ b/rtl/HMR/rapid_recovery_pkg.sv
@@ -0,0 +1,86 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * Recovery Region Package
+ *
+ */
+
+package rapid_recovery_pkg;
+
+localparam int unsigned DataWidth = 32;
+localparam int unsigned ProtectedWidth = 39;
+localparam int unsigned RegfileAddr = 6;
+localparam int unsigned RecoveryStateBits = 3;
+/* CSRs */
+localparam int unsigned MstatusWidth = 7;
+localparam int unsigned MtvecWidth = 24;
+localparam int unsigned McauseWidth = 6;
+
+typedef struct packed {
+ // Write Port A
+ logic we_a;
+ logic [RegfileAddr-1:0] waddr_a;
+ logic [ DataWidth-1:0] wdata_a;
+ // Write Port B
+ logic we_b;
+ logic [RegfileAddr-1:0] waddr_b;
+ logic [ DataWidth-1:0] wdata_b;
+} regfile_write_t;
+
+typedef struct packed {
+ logic [RegfileAddr-1:0] raddr_a;
+ logic [RegfileAddr-1:0] raddr_b;
+} regfile_raddr_t;
+
+typedef struct packed {
+ logic [DataWidth-1:0] rdata_a;
+ logic [DataWidth-1:0] rdata_b;
+} regfile_rdata_t;
+
+typedef struct packed {
+ logic [MstatusWidth-1:0] csr_mstatus;
+ logic [ DataWidth-1:0] csr_mie;
+ logic [ MtvecWidth-1:0] csr_mtvec;
+ logic [ DataWidth-1:0] csr_mscratch;
+ logic [ DataWidth-1:0] csr_mip;
+ logic [ DataWidth-1:0] csr_mepc;
+ logic [ McauseWidth-1:0] csr_mcause;
+} csrs_intf_t;
+
+typedef struct packed {
+ logic [ProtectedWidth-1:0] csr_mstatus;
+ logic [ProtectedWidth-1:0] csr_mie;
+ logic [ProtectedWidth-1:0] csr_mtvec;
+ logic [ProtectedWidth-1:0] csr_mscratch;
+ logic [ProtectedWidth-1:0] csr_mip;
+ logic [ProtectedWidth-1:0] csr_mepc;
+ logic [ProtectedWidth-1:0] csr_mcause;
+} ecc_csrs_intf_t;
+
+typedef struct packed {
+ logic [DataWidth-1:0] program_counter_if;
+ logic [DataWidth-1:0] program_counter;
+ logic is_branch;
+ logic [DataWidth-1:0] branch_addr;
+} pc_intf_t;
+
+typedef struct packed {
+ logic instr_lock;
+ logic pc_recovery_en;
+ logic rf_recovery_en;
+ logic debug_req;
+ logic debug_resume;
+ rapid_recovery_pkg::regfile_write_t rf_recovery_wdata;
+ rapid_recovery_pkg::regfile_rdata_t rf_recovery_rdata;
+ rapid_recovery_pkg::csrs_intf_t csr_recovery;
+ rapid_recovery_pkg::pc_intf_t pc_recovery;
+} rapid_recovery_t;
+
+endpackage
diff --git a/rtl/HMR/rapid_recovery_unit.sv b/rtl/HMR/rapid_recovery_unit.sv
new file mode 100644
index 00000000..77bcf453
--- /dev/null
+++ b/rtl/HMR/rapid_recovery_unit.sv
@@ -0,0 +1,165 @@
+// Copyright 2023 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Rapid Recovery unit with backup status registers
+
+module rapid_recovery_unit
+ import rapid_recovery_pkg::*;
+#(
+ parameter int unsigned RfAddrWidth = 5,
+ parameter int unsigned DataWidth = 32,
+ parameter int unsigned EccEnabled = 1,
+ parameter type regfile_write_t = logic,
+ parameter type regfile_raddr_t = logic,
+ parameter type regfile_rdata_t = logic,
+ parameter type csr_intf_t = logic,
+ parameter type pc_intf_t = logic
+)(
+ input logic clk_i,
+ input logic rst_ni,
+ /* Signals that cores are not grouped */
+ input logic core_in_independent_i,
+ /* Recovery Register File interface */
+ input regfile_write_t regfile_write_i,
+ /* Recovery Control and Status Registers interface */
+ input csr_intf_t backup_csr_i,
+ output csr_intf_t recovery_csr_o,
+ /* Recovery Program Counter interface */
+ input pc_intf_t backup_pc_i,
+ output pc_intf_t recovery_pc_o,
+ /* Rapid Recovery Controller interface */
+ /* backup_enable_i: result of comparison between backup_enable_o
+ (generated by the rapid_recovery_ctrl) and
+ the DMR/TMR selection mode */
+ input logic backup_enable_i,
+ /* start_recovery_i: software-requested recovery */
+ input logic start_recovery_i,
+ /* backup_enable_o: generated by rapid_recovery_ctrl, asserts that
+ the core can do the backup of its state */
+ output logic backup_enable_o,
+ /* recovery_finished_o: recovery routine completion */
+ output logic recovery_finished_o,
+ /* setback_o: synchronous clear for the core */
+ output logic setback_o,
+ /* instr_lock_o: blocks the requests toward the instruction cache
+ during the recovery routine */
+ output logic instr_lock_o,
+ /* enable_pc_recovery_o: allows the program counter to be reloaded
+ into the core */
+ output logic enable_pc_recovery_o,
+ /* enable_rf_recovery_o: allows the register file to be reloaded
+ into the core */
+ output logic enable_rf_recovery_o,
+ /* regfile_recovery_wdata_o: used by the address generator in the
+ rapid_recovery_ctrl to propagate the RF
+ addresses to the core during the recovery
+ routine */
+ output regfile_write_t regfile_recovery_wdata_o, // To cores RF interface
+ /* regfile_recovery_rdata_o: propagates the content from the backup RF to
+ the core RF during the recovery routine */
+ output regfile_rdata_t regfile_recovery_rdata_o,
+ /* debug_halt_i: signals that the cores in recovery are halted */
+ input logic debug_halt_i,
+ /* debug_req_o: sends the cores in debug mode during the recovery routine */
+ output logic debug_req_o,
+ /* debug_resume_o: resumes the cores in recovery from the debug mode */
+ output logic debug_resume_o
+);
+
+logic csr_renable;
+
+hmr_rapid_recovery_ctrl #(
+ .RFAddrWidth ( RfAddrWidth ),
+ .regfile_write_t ( regfile_write_t )
+) i_rapid_recovery_ctrl (
+ .clk_i,
+ .rst_ni,
+ .start_recovery_i,
+ .recovery_finished_o,
+ .setback_o,
+ .instr_lock_o,
+ .debug_req_o,
+ .debug_halt_i,
+ .debug_resume_o,
+ .recovery_regfile_waddr_o ( regfile_recovery_wdata_o ),
+ .backup_enable_o ( backup_enable_o ),
+ .recover_csr_enable_o ( csr_renable ),
+ .recover_pc_enable_o ( enable_pc_recovery_o ),
+ .recover_rf_enable_o ( enable_rf_recovery_o )
+);
+
+recovery_csr #(
+ .ECCEnabled ( EccEnabled ),
+ .csr_intf_t ( csr_intf_t )
+) i_recovery_csr (
+ .clk_i,
+ .rst_ni,
+ .read_enable_i ( csr_renable ),
+ .write_enable_i ( backup_enable_i ),
+ .backup_csr_i ( backup_csr_i ),
+ .recovery_csr_o ( recovery_csr_o )
+);
+
+/* When cores are not grouped, we store as a recovery program counter the instruction
+ that just eneterd the fetch stage. The reason is that if we switch from independent
+ to redundant, we do it after a barrier, and if we restart from a barrier instruction
+ without setting it up properly first, we never continue the execution. */
+logic [DataWidth-1:0] backup_program_counter;
+assign backup_program_counter = core_in_independent_i ? backup_pc_i.program_counter_if
+ : backup_pc_i.program_counter;
+recovery_pc #(
+ .ECCEnabled ( EccEnabled ),
+ .pc_intf_t ( pc_intf_t )
+) i_recovery_pc (
+ // Control Ports
+ .clk_i,
+ .rst_ni,
+ .clear_i ( '0 ),
+ .read_enable_i ( enable_pc_recovery_o ),
+ .write_enable_i ( backup_enable_i ),
+ // Backup Ports
+ .backup_program_counter_i ( backup_program_counter ),
+ .backup_branch_i ( backup_pc_i.is_branch ),
+ .backup_branch_addr_i ( backup_pc_i.branch_addr ),
+ // Recovery Pors
+ .recovery_program_counter_o ( recovery_pc_o.program_counter ),
+ .recovery_branch_o ( recovery_pc_o.is_branch ),
+ .recovery_branch_addr_o ( recovery_pc_o.branch_addr )
+);
+
+recovery_rf #(
+ .ECCEnabled ( EccEnabled ),
+ .ADDR_WIDTH ( RfAddrWidth ),
+ .regfile_write_t ( regfile_write_t ),
+ .regfile_raddr_t ( regfile_raddr_t ),
+ .regfile_rdata_t ( regfile_rdata_t )
+) i_recovery_rf (
+ .clk_i,
+ .rst_ni,
+ //Read port A
+ .raddr_a_i ( regfile_recovery_wdata_o.waddr_a ),
+ .rdata_a_o ( regfile_recovery_rdata_o.rdata_a ),
+ //Read port B
+ .raddr_b_i ( regfile_recovery_wdata_o.waddr_b ),
+ .rdata_b_o ( regfile_recovery_rdata_o.rdata_b ),
+ //Read port C
+ .raddr_c_i ( '0 ),
+ .rdata_c_o ( ),
+ // Write Port A
+ .waddr_a_i ( regfile_write_i.waddr_a ),
+ .wdata_a_i ( regfile_write_i.wdata_a ),
+ .we_a_i ( regfile_write_i.we_a & backup_enable_i ),
+ // Write Port B
+ .waddr_b_i ( regfile_write_i.waddr_b ),
+ .wdata_b_i ( regfile_write_i.wdata_b ),
+ .we_b_i ( regfile_write_i.we_b & backup_enable_i )
+);
+
+endmodule: rapid_recovery_unit
diff --git a/rtl/HMR/recovery_csr.sv b/rtl/HMR/recovery_csr.sv
new file mode 100644
index 00000000..6cf78126
--- /dev/null
+++ b/rtl/HMR/recovery_csr.sv
@@ -0,0 +1,152 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * Recovery Control Status Registers
+ * ECC-protected register that stores the CSRs values from the cores
+ *
+ */
+
+module recovery_csr
+ import rapid_recovery_pkg::*;
+#(
+ parameter int unsigned ECCEnabled = 0,
+ parameter int unsigned NonProtectedWidth = 32,
+ parameter int unsigned ProtectedWidth = 39,
+ parameter type csr_intf_t = logic,
+ localparam int unsigned DataWidth = ( ECCEnabled ) ? ProtectedWidth
+ : NonProtectedWidth
+) (
+ input logic clk_i ,
+ input logic rst_ni,
+ input logic read_enable_i,
+ input logic write_enable_i,
+ input csrs_intf_t backup_csr_i,
+ output csrs_intf_t recovery_csr_o
+);
+
+csrs_intf_t csr_inp,
+ csr_out;
+
+logic [31:0] csr_dec_mstatus,
+ csr_dec_mie,
+ csr_dec_mtvec,
+ csr_dec_mscratch,
+ csr_dec_mip,
+ csr_dec_mepc,
+ csr_dec_mcause;
+
+assign csr_inp = backup_csr_i;
+assign recovery_csr_o = (read_enable_i) ? csr_out : '0;
+
+if (ECCEnabled) begin : gen_ecc_csrs
+
+ ecc_csrs_intf_t csr_d, csr_q;
+
+ prim_secded_39_32_enc csr_mstatus_ecc_encoder (
+ .in ( {25'd0,csr_inp.csr_mstatus} ), // mtvec is a 7-bit value
+ .out ( csr_d.csr_mstatus )
+ );
+ prim_secded_39_32_enc csr_mie_ecc_encoder (
+ .in ( csr_inp.csr_mie ),
+ .out ( csr_d.csr_mie )
+ );
+ prim_secded_39_32_enc csr_mtvec_ecc_encoder (
+ .in ( {8'd0, csr_inp.csr_mtvec} ), // mtvec is a 24-bit value
+ .out ( csr_d.csr_mtvec )
+ );
+ prim_secded_39_32_enc csr_mscratch_ecc_encoder (
+ .in ( csr_inp.csr_mscratch ),
+ .out ( csr_d.csr_mscratch )
+ );
+ prim_secded_39_32_enc csr_mip_ecc_encoder (
+ .in ( csr_inp.csr_mip ),
+ .out ( csr_d.csr_mip )
+ );
+ prim_secded_39_32_enc csr_mepc_ecc_encoder (
+ .in ( csr_inp.csr_mepc),
+ .out ( csr_d.csr_mepc )
+ );
+ prim_secded_39_32_enc csr_mcause_ecc_encoder (
+ .in ( {26'd0, csr_inp.csr_mcause} ), // mcause is a 6-bit value
+ .out ( csr_d.csr_mcause )
+ );
+
+ always_ff @(posedge clk_i, negedge rst_ni) begin : ecc_csr_backup
+ if (~rst_ni)
+ csr_q <= '0;
+ else if (write_enable_i)
+ csr_q <= csr_d;
+ end
+
+ prim_secded_39_32_dec csr_mstatus_ecc_decoder (
+ .in ( csr_q.csr_mstatus ),
+ .d_o ( csr_dec_mstatus ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ prim_secded_39_32_dec csr_mie_ecc_decoder (
+ .in ( csr_q.csr_mie ),
+ .d_o ( csr_dec_mie ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ prim_secded_39_32_dec csr_mtvec_ecc_decoder (
+ .in ( csr_q.csr_mtvec ),
+ .d_o ( csr_dec_mtvec ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ prim_secded_39_32_dec csr_mscratch_ecc_decoder (
+ .in ( csr_q.csr_mscratch ),
+ .d_o ( csr_dec_mscratch ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ prim_secded_39_32_dec csr_mip_ecc_decoder (
+ .in ( csr_q.csr_mip ),
+ .d_o ( csr_dec_mip ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ prim_secded_39_32_dec csr_mepc_ecc_decoder (
+ .in ( csr_q.csr_mepc ),
+ .d_o ( csr_dec_mepc ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ prim_secded_39_32_dec csr_mcause_ecc_decoder (
+ .in ( csr_q.csr_mcause ),
+ .d_o ( csr_dec_mcause ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ assign csr_out.csr_mstatus = csr_dec_mstatus[6:0];
+ assign csr_out.csr_mie = csr_dec_mie;
+ assign csr_out.csr_mtvec = csr_dec_mtvec[23:0];
+ assign csr_out.csr_mscratch = csr_dec_mscratch;
+ assign csr_out.csr_mip = csr_dec_mip;
+ assign csr_out.csr_mepc = csr_dec_mepc;
+ assign csr_out.csr_mcause = csr_dec_mcause[5:0];
+end else begin : gen_no_ecc_csrs
+ csrs_intf_t csr_d, csr_q;
+
+ assign csr_d = csr_inp;
+
+ always_ff @(posedge clk_i, negedge rst_ni) begin : csr_backup
+ if (~rst_ni)
+ csr_q <= '0;
+ else if (write_enable_i)
+ csr_q <= csr_d;
+ end
+ assign csr_out = csr_q;
+
+end
+
+endmodule : recovery_csr
diff --git a/rtl/HMR/recovery_pc.sv b/rtl/HMR/recovery_pc.sv
new file mode 100644
index 00000000..51f62347
--- /dev/null
+++ b/rtl/HMR/recovery_pc.sv
@@ -0,0 +1,191 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * Recovery Program Counter
+ * ECC-protected register that stores the Program Counter value from the cores
+ *
+ */
+
+module recovery_pc #(
+ parameter int unsigned ECCEnabled = 0,
+ parameter int unsigned NonProtectedWidth = 32,
+ parameter int unsigned ProtectedWidth = 39,
+ parameter type pc_intf_t = logic,
+ localparam int unsigned DataWidth = ( ECCEnabled ) ? ProtectedWidth
+ : NonProtectedWidth
+) (
+ // Control Ports
+ input logic clk_i,
+ input logic rst_ni,
+ input logic clear_i,
+ input logic read_enable_i,
+ input logic write_enable_i,
+ // Backup Ports
+ input logic [NonProtectedWidth-1:0] backup_program_counter_i,
+ input logic backup_branch_i,
+ input logic [NonProtectedWidth-1:0] backup_branch_addr_i,
+ // Recovery Pors
+ output logic [NonProtectedWidth-1:0] recovery_program_counter_o,
+ output logic recovery_branch_o,
+ output logic [NonProtectedWidth-1:0] recovery_branch_addr_o
+);
+
+logic branch_q;
+
+logic [DataWidth-1:0] pc_d,
+ pc_q,
+ branch_addr_d,
+ branch_addr_q;
+logic [NonProtectedWidth-1:0] pc_out,
+ branch_addr_out;
+
+generate
+ if (ECCEnabled) begin : gen_ecc_region
+ /**************************
+ * Program Counter Backup *
+ **************************/
+ prim_secded_39_32_enc pc_ecc_encoder (
+ .in ( backup_program_counter_i ),
+ .out ( pc_d )
+ );
+
+ always_ff @(posedge clk_i, negedge rst_ni) begin : pc_value_sampler
+ if (~rst_ni)
+ pc_q <= '0;
+ else begin
+ if (clear_i)
+ pc_q <= '0;
+ else if (write_enable_i && pc_d != '0)
+ pc_q <= pc_d;
+ else
+ pc_q <= pc_q;
+ end
+ end
+
+ prim_secded_39_32_dec pc_ecc_decoder (
+ .in ( pc_q ),
+ .d_o ( pc_out ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+
+ /**********************
+ * Branch Addr Backup *
+ **********************/
+ prim_secded_39_32_enc branch_addr_ecc_encoder (
+ .in ( backup_branch_addr_i ),
+ .out ( branch_addr_d )
+ );
+
+ always_ff @(posedge clk_i, negedge rst_ni) begin : branch_addr_sampler
+ if (~rst_ni)
+ branch_addr_q <= '0;
+ else begin
+ if (clear_i)
+ branch_addr_q <= '0;
+ else if (backup_branch_i && write_enable_i)
+ branch_addr_q <= branch_addr_d;
+ else
+ branch_addr_q <= branch_addr_q;
+ end
+ end
+
+ prim_secded_39_32_dec branch_addr_ecc_decoder (
+ .in ( branch_addr_q ),
+ .d_o ( branch_addr_out ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+
+ /************************
+ * Branch Signal Backup *
+ ************************/
+ always_ff @(posedge clk_i, negedge rst_ni) begin : branch_sampler
+ if (~rst_ni)
+ branch_q <= '0;
+ else begin
+ if (clear_i)
+ branch_q <= '0;
+ else if (write_enable_i)
+ branch_q <= backup_branch_i;
+ else
+ branch_q <= branch_q;
+ end
+ end
+
+ /*****************
+ * Output Assign *
+ *****************/
+ assign recovery_program_counter_o = (read_enable_i) ? pc_out : '0;
+ assign recovery_branch_addr_o = (read_enable_i && branch_q) ? branch_addr_out : '0;
+ assign recovery_branch_o = (read_enable_i) ? branch_q : '0;
+ end else begin : gen_no_ecc_region
+ /**************************
+ * Program Counter Backup *
+ **************************/
+ assign pc_d = backup_program_counter_i;
+ always_ff @(posedge clk_i, negedge rst_ni) begin : pc_value_sampler
+ if (~rst_ni)
+ pc_q <= '0;
+ else begin
+ if (clear_i)
+ pc_q <= '0;
+ else if (write_enable_i)
+ pc_q <= pc_d;
+ else
+ pc_q <= pc_d;
+ end
+ end
+ assign pc_out = pc_q;
+
+ /**********************
+ * Branch Addr Backup *
+ **********************/
+ assign branch_addr_d = backup_branch_addr_i;
+ always_ff @(posedge clk_i, negedge rst_ni) begin : branch_addr_sampler
+ if (~rst_ni)
+ branch_addr_q <= '0;
+ else begin
+ if (clear_i)
+ branch_addr_q <= '0;
+ else if (backup_branch_i && write_enable_i)
+ branch_addr_q <= branch_addr_d;
+ else
+ branch_addr_q <= branch_addr_q;
+ end
+ end
+ assign branch_addr_out = branch_addr_q;
+
+ /************************
+ * Branch Signal Backup *
+ ************************/
+ always_ff @(posedge clk_i, negedge rst_ni) begin : branch_sampler
+ if (~rst_ni)
+ branch_q <= '0;
+ else begin
+ if (clear_i)
+ branch_q <= '0;
+ else if (write_enable_i)
+ branch_q <= backup_branch_i;
+ else
+ branch_q <= branch_q;
+ end
+ end
+
+ /*****************
+ * Output Assign *
+ *****************/
+ assign recovery_program_counter_o = (read_enable_i) ? pc_out : '0;
+ assign recovery_branch_addr_o = (read_enable_i) ? branch_addr_out : '0;
+ assign recovery_branch_o = (read_enable_i) ? branch_q : '0;
+ end
+endgenerate
+
+endmodule : recovery_pc
diff --git a/rtl/HMR/recovery_rf.sv b/rtl/HMR/recovery_rf.sv
new file mode 100644
index 00000000..b546087c
--- /dev/null
+++ b/rtl/HMR/recovery_rf.sv
@@ -0,0 +1,216 @@
+// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// Engineer: Francesco Conti - f.conti@unibo.it //
+// //
+// Additional contributions by: //
+// Michael Gautschi - gautschi@iis.ee.ethz.ch //
+// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
+// //
+// Design Name: RISC-V register file //
+// Project Name: RI5CY //
+// Language: SystemVerilog //
+// //
+// Description: Register file with 31x 32 bit wide registers. Register 0 //
+// is fixed to 0. This register file is based on flip-flops. //
+// Also supports the fp-register file now if FPU=1 //
+// If PULP_ZFINX is 1, floating point operations take values //
+// from the X register file //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+module recovery_rf #(
+ parameter int unsigned ECCEnabled = 0,
+ parameter int unsigned ADDR_WIDTH = 5,
+ parameter int unsigned NonProtectedWidth = 32,
+ parameter int unsigned ProtectedWidth = 39,
+ parameter int unsigned FPU = 0,
+ parameter int unsigned PULP_ZFINX = 0,
+ parameter type regfile_write_t = logic,
+ parameter type regfile_raddr_t = logic,
+ parameter type regfile_rdata_t = logic,
+ localparam int unsigned DataWidth = ( ECCEnabled ) ? ProtectedWidth
+ : NonProtectedWidth
+)(
+ // Clock and Reset
+ input logic clk_i,
+ input logic rst_ni,
+
+ //Read port R1
+ input logic [ADDR_WIDTH-1:0] raddr_a_i,
+ output logic [NonProtectedWidth-1:0] rdata_a_o,
+
+ //Read port R2
+ input logic [ADDR_WIDTH-1:0] raddr_b_i,
+ output logic [NonProtectedWidth-1:0] rdata_b_o,
+
+ //Read port R3
+ input logic [ADDR_WIDTH-1:0] raddr_c_i,
+ output logic [NonProtectedWidth:0] rdata_c_o,
+
+ // Write port W1
+ input logic [ADDR_WIDTH-1:0] waddr_a_i,
+ input logic [NonProtectedWidth-1:0] wdata_a_i,
+ input logic we_a_i,
+
+ // Write port W2
+ input logic [ADDR_WIDTH-1:0] waddr_b_i,
+ input logic [NonProtectedWidth-1:0] wdata_b_i,
+ input logic we_b_i
+);
+
+ // number of integer registers
+ localparam NUM_WORDS = 2 ** (ADDR_WIDTH - 1);
+ // number of floating point registers
+ localparam NUM_FP_WORDS = 2 ** (ADDR_WIDTH - 1);
+ localparam NUM_TOT_WORDS = FPU ? (PULP_ZFINX ? NUM_WORDS : NUM_WORDS + NUM_FP_WORDS) : NUM_WORDS;
+
+ // integer register file
+ logic [NUM_WORDS-1:0][NonProtectedWidth-1:0] mem;
+ logic [NUM_WORDS-1:0][ DataWidth-1:0] ecc_mem;
+ // fp register file
+ logic [NUM_FP_WORDS-1:0][NonProtectedWidth-1:0] mem_fp;
+ logic [NUM_FP_WORDS-1:0][ DataWidth-1:0] ecc_mem_fp;
+
+ logic [DataWidth-1:0] wdata_a,
+ wdata_b;
+
+ // masked write addresses
+ logic [ADDR_WIDTH-1:0] waddr_a;
+ logic [ADDR_WIDTH-1:0] waddr_b;
+
+ // write enable signals for all registers
+ logic [NUM_TOT_WORDS-1:0] we_a_dec;
+ logic [NUM_TOT_WORDS-1:0] we_b_dec;
+
+ generate
+ if (ECCEnabled) begin : gen_ecc_region
+
+ prim_secded_39_32_enc a_port_ecc_encoder (
+ .in ( wdata_a_i ),
+ .out ( wdata_a )
+ );
+
+ prim_secded_39_32_enc b_port_ecc_encoder (
+ .in ( wdata_b_i ),
+ .out ( wdata_b )
+ );
+
+ for (genvar index = 0; index < NUM_WORDS; index++) begin
+ prim_secded_39_32_dec internal_memory_decoder (
+ .in ( ecc_mem [index] ),
+ .d_o ( mem [index] ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ end
+
+ if (FPU == 1 && PULP_ZFINX == 0) begin
+ for (genvar index = 0; index < NUM_FP_WORDS; index++) begin
+ prim_secded_39_32_dec internal_fp_memory_decoder (
+ .in ( ecc_mem_fp [index] ),
+ .d_o ( mem_fp [index] ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ end
+ end
+ end else begin : no_ecc_region
+ assign wdata_a = wdata_a_i;
+ assign wdata_b = wdata_b_i;
+
+ for (genvar index = 0; index < NUM_WORDS; index++)
+ assign mem [index] = ecc_mem [index];
+
+ for (genvar index = 0; index < NUM_FP_WORDS; index++)
+ assign mem_fp [index] = ecc_mem_fp [index];
+ end
+ endgenerate
+
+ //-----------------------------------------------------------------------------
+ //-- READ : Read address decoder RAD
+ //-----------------------------------------------------------------------------
+ generate
+ if (FPU == 1 && PULP_ZFINX == 0) begin : gen_mem_fp_read
+ assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]];
+ assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]];
+ assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]];
+ end else begin : gen_mem_read
+ assign rdata_a_o = mem[raddr_a_i[4:0]];
+ assign rdata_b_o = mem[raddr_b_i[4:0]];
+ assign rdata_c_o = mem[raddr_c_i[4:0]];
+ end
+ endgenerate
+
+ //-----------------------------------------------------------------------------
+ //-- WRITE : Write Address Decoder (WAD), combinatorial process
+ //-----------------------------------------------------------------------------
+
+ // Mask top bit of write address to disable fp regfile
+ assign waddr_a = waddr_a_i;
+ assign waddr_b = waddr_b_i;
+
+ genvar gidx;
+ generate
+ for (gidx = 0; gidx < NUM_TOT_WORDS; gidx++) begin : gen_we_decoder
+ assign we_a_dec[gidx] = (waddr_a == gidx) ? we_a_i : 1'b0;
+ assign we_b_dec[gidx] = (waddr_b == gidx) ? we_b_i : 1'b0;
+ end
+ endgenerate
+
+ genvar i, l;
+ generate
+
+ //-----------------------------------------------------------------------------
+ //-- WRITE : Write operation
+ //-----------------------------------------------------------------------------
+ // R0 is nil
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (~rst_ni) begin
+ // R0 is nil
+ ecc_mem[0] <= 32'b0;
+ end else begin
+ // R0 is nil
+ ecc_mem[0] <= 32'b0;
+ end
+ end
+
+ // loop from 1 to NUM_WORDS-1 as R0 is nil
+ for (i = 1; i < NUM_WORDS; i++) begin : gen_rf
+ always_ff @(posedge clk_i, negedge rst_ni) begin : register_write_behavioral
+ if (rst_ni == 1'b0) begin
+ ecc_mem[i] <= 32'b0;
+ end else begin
+ if (we_b_dec[i] == 1'b1) ecc_mem[i] <= wdata_b;
+ else if (we_a_dec[i] == 1'b1) ecc_mem[i] <= wdata_a;
+ end
+ end
+ end
+
+ if (FPU == 1 && PULP_ZFINX == 0) begin : gen_mem_fp_write
+ // Floating point registers
+ for (l = 0; l < NUM_FP_WORDS; l++) begin
+ always_ff @(posedge clk_i, negedge rst_ni) begin : fp_regs
+ if (rst_ni == 1'b0) begin
+ ecc_mem_fp[l] <= '0;
+ end else begin
+ if (we_b_dec[l+NUM_WORDS] == 1'b1) ecc_mem_fp[l] <= wdata_b;
+ else if (we_a_dec[l+NUM_WORDS] == 1'b1) ecc_mem_fp[l] <= wdata_a;
+ end
+ end
+ end
+ end else begin : gen_no_mem_fp_write
+ assign ecc_mem_fp = 'b0;
+ end
+
+ endgenerate
+
+endmodule
diff --git a/rtl/HMR/recovery_rf_latch.sv b/rtl/HMR/recovery_rf_latch.sv
new file mode 100644
index 00000000..3bc572a7
--- /dev/null
+++ b/rtl/HMR/recovery_rf_latch.sv
@@ -0,0 +1,260 @@
+// Copyright 2018 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// Engineer: Antonio Pullini - pullinia@iis.ee.ethz.ch //
+// //
+// Additional contributions by: //
+// Sven Stucki - svstucki@student.ethz.ch //
+// Michael Gautschi - gautschi@iis.ee.ethz.ch //
+// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
+// //
+// Design Name: RISC-V register file //
+// Project Name: RI5CY //
+// Language: SystemVerilog //
+// //
+// Description: Register file with 31x 32 bit wide registers. Register 0 //
+// is fixed to 0. This register file is based on latches and //
+// is thus smaller than the flip-flop based register file. //
+// Also supports the fp-register file now if FPU=1 //
+// If PULP_ZFINX is 1, floating point operations take values //
+// from the X register file //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+module recovery_rf #(
+ parameter int unsigned ECCEnabled = 0,
+ parameter int unsigned ADDR_WIDTH = 5,
+ parameter int unsigned NonProtectedWidth = 32,
+ parameter int unsigned ProtectedWidth = 39,
+ parameter int unsigned FPU = 0,
+ parameter int unsigned PULP_ZFINX = 0,
+ parameter type regfile_write_t = logic,
+ parameter type regfile_raddr_t = logic,
+ parameter type regfile_rdata_t = logic,
+ localparam int unsigned DataWidth = ( ECCEnabled ) ? ProtectedWidth
+ : NonProtectedWidth
+) (
+ // Clock and Reset
+ input logic clk_i,
+ input logic rst_ni,
+
+ input logic test_en_i,
+
+ //Read port R1
+ input logic [ADDR_WIDTH-1:0] raddr_a_i,
+ output logic [NonProtectedWidth-1:0] rdata_a_o,
+
+ //Read port R2
+ input logic [ADDR_WIDTH-1:0] raddr_b_i,
+ output logic [NonProtectedWidth-1:0] rdata_b_o,
+
+ //Read port R3
+ input logic [ADDR_WIDTH-1:0] raddr_c_i,
+ output logic [NonProtectedWidth-1:0] rdata_c_o,
+
+ // Write port W1
+ input logic [ADDR_WIDTH-1:0] waddr_a_i,
+ input logic [NonProtectedWidth-1:0] wdata_a_i,
+ input logic we_a_i,
+
+ // Write port W2
+ input logic [ADDR_WIDTH-1:0] waddr_b_i,
+ input logic [NonProtectedWidth-1:0] wdata_b_i,
+ input logic we_b_i
+);
+
+ // number of integer registers
+ localparam NUM_WORDS = 2 ** (ADDR_WIDTH - 1);
+ // number of floating point registers
+ localparam NUM_FP_WORDS = 2 ** (ADDR_WIDTH - 1);
+ localparam NUM_TOT_WORDS = FPU ? (PULP_ZFINX ? NUM_WORDS : NUM_WORDS + NUM_FP_WORDS) : NUM_WORDS;
+
+ // integer register file
+ logic [NonProtectedWidth-1:0] mem [NUM_WORDS];
+ logic [ DataWidth-1:0] ecc_mem [NUM_WORDS];
+ logic [NUM_TOT_WORDS-1:1] waddr_onehot_a;
+ logic [NUM_TOT_WORDS-1:1] waddr_onehot_b ,
+ waddr_onehot_b_q;
+ logic [NUM_TOT_WORDS-1:1] mem_clocks;
+ logic [DataWidth-1:0] wdata_a ,
+ wdata_a_q ,
+ wdata_a_ecc;
+ logic [DataWidth-1:0] wdata_b ,
+ wdata_b_q ,
+ wdata_b_ecc;
+
+ // masked write addresses
+ logic [ADDR_WIDTH-1:0] waddr_a;
+ logic [ADDR_WIDTH-1:0] waddr_b;
+
+ logic clk_int;
+
+ // fp register file
+ logic [NonProtectedWidth-1:0] mem_fp [NUM_FP_WORDS];
+ logic [ DataWidth-1:0] ecc_mem_fp [NUM_FP_WORDS];
+
+ int unsigned i;
+ int unsigned j;
+ int unsigned k;
+ int unsigned l;
+
+ genvar x;
+ genvar y;
+
+ generate
+ if (ECCEnabled) begin : gen_ecc_region
+
+ prim_secded_39_32_enc a_port_ecc_encoder (
+ .in ( wdata_a_i ),
+ .out ( wdata_a_ecc)
+ );
+ assign wdata_a = wdata_a_ecc;
+
+ prim_secded_39_32_enc b_port_ecc_encoder (
+ .in ( wdata_b_i ),
+ .out ( wdata_b_ecc)
+ );
+ assign wdata_b = wdata_b_ecc;
+
+ for (genvar index = 0; index < NUM_WORDS; index++) begin
+ prim_secded_39_32_dec internal_memory_decoder (
+ .in ( ecc_mem [index] ),
+ .d_o ( mem [index] ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ end
+
+ if (FPU == 1 && PULP_ZFINX == 0) begin
+ for (genvar index = 0; index < NUM_FP_WORDS; index++) begin
+ prim_secded_39_32_dec internal_fp_memory_decoder (
+ .in ( ecc_mem_fp [index] ),
+ .d_o ( mem_fp [index] ),
+ .syndrome_o ( ),
+ .err_o ( )
+ );
+ end
+ end
+ end else begin : no_ecc_region
+ assign wdata_a = wdata_a_i;
+ assign wdata_a_ecc = '0;
+ assign wdata_b = wdata_b_i;
+ assign wdata_b_ecc = '0;
+
+ for (genvar index = 0; index < NUM_WORDS; index++)
+ assign mem [index] = ecc_mem [index];
+
+ for (genvar index = 0; index < NUM_FP_WORDS; index++)
+ assign mem_fp [index] = ecc_mem_fp [index];
+ end
+ endgenerate
+
+ //-----------------------------------------------------------------------------
+ //-- READ : Read address decoder RAD
+ //-----------------------------------------------------------------------------
+ if (FPU == 1 && PULP_ZFINX == 0) begin
+ assign rdata_a_o = raddr_a_i[5] ? mem_fp[raddr_a_i[4:0]] : mem[raddr_a_i[4:0]];
+ assign rdata_b_o = raddr_b_i[5] ? mem_fp[raddr_b_i[4:0]] : mem[raddr_b_i[4:0]];
+ assign rdata_c_o = raddr_c_i[5] ? mem_fp[raddr_c_i[4:0]] : mem[raddr_c_i[4:0]];
+ end else begin
+ assign rdata_a_o = mem[raddr_a_i[4:0]];
+ assign rdata_b_o = mem[raddr_b_i[4:0]];
+ assign rdata_c_o = mem[raddr_c_i[4:0]];
+ end
+
+ //-----------------------------------------------------------------------------
+ // WRITE : SAMPLE INPUT DATA
+ //---------------------------------------------------------------------------
+
+ tc_clk_gating CG_WE_GLOBAL (
+ .clk_i ( clk_i ),
+ .en_i ( we_a_i | we_b_i ),
+ .test_en_i ( test_en_i ),
+ .clk_o ( clk_int )
+ );
+
+ // use clk_int here, since otherwise we don't want to write anything anyway
+ always_ff @(posedge clk_int, negedge rst_ni) begin : sample_waddr
+ if (~rst_ni) begin
+ wdata_a_q <= '0;
+ wdata_b_q <= '0;
+ waddr_onehot_b_q <= '0;
+ end else begin
+ if (we_a_i) wdata_a_q <= wdata_a;
+
+ if (we_b_i) wdata_b_q <= wdata_b;
+
+ waddr_onehot_b_q <= waddr_onehot_b;
+ end
+ end
+
+ //-----------------------------------------------------------------------------
+ //-- WRITE : Write Address Decoder (WAD), combinatorial process
+ //-----------------------------------------------------------------------------
+
+ assign waddr_a = waddr_a_i;
+ assign waddr_b = waddr_b_i;
+
+ genvar gidx;
+ generate
+ for (gidx = 1; gidx < NUM_TOT_WORDS; gidx++) begin : gen_we_decoder
+ assign waddr_onehot_a[gidx] = (we_a_i == 1'b1) && (waddr_a == gidx);
+ assign waddr_onehot_b[gidx] = (we_b_i == 1'b1) && (waddr_b == gidx);
+ end
+ endgenerate
+
+ //-----------------------------------------------------------------------------
+ //-- WRITE : Clock gating (if integrated clock-gating cells are available)
+ //-----------------------------------------------------------------------------
+ generate
+ for (x = 1; x < NUM_TOT_WORDS; x++) begin : gen_clock_gate
+ tc_clk_gating clock_gate_i (
+ .clk_i ( clk_int ),
+ .en_i ( waddr_onehot_a[x] | waddr_onehot_b[x] ),
+ .test_en_i ( test_en_i ),
+ .clk_o ( mem_clocks[x] )
+ );
+ end
+ endgenerate
+
+ //-----------------------------------------------------------------------------
+ //-- WRITE : Write operation
+ //-----------------------------------------------------------------------------
+ //-- Generate M = WORDS sequential processes, each of which describes one
+ //-- word of the memory. The processes are synchronized with the clocks
+ //-- ClocksxC(i), i = 0, 1, ..., M-1
+ //-- Use active low, i.e. transparent on low latches as storage elements
+ //-- Data is sampled on rising clock edge
+
+ // Integer registers
+ always_latch begin : latch_wdata
+ // Note: The assignment has to be done inside this process or Modelsim complains about it
+ ecc_mem[0] = '0;
+
+ for (k = 1; k < NUM_WORDS; k++) begin : w_WordIter
+ if (~rst_ni) ecc_mem[k] = '0;
+ else if (mem_clocks[k] == 1'b1) ecc_mem[k] = waddr_onehot_b_q[k] ? wdata_b_q : wdata_a_q;
+ end
+ end
+
+ if (FPU == 1 && PULP_ZFINX == 0) begin
+ // Floating point registers
+ always_latch begin : latch_wdata_fp
+ if (FPU == 1) begin
+ for (l = 0; l < NUM_FP_WORDS; l++) begin : w_WordIter
+ if (~rst_ni) ecc_mem_fp[l] = '0;
+ else if (mem_clocks[l+NUM_WORDS] == 1'b1)
+ ecc_mem_fp[l] = waddr_onehot_b_q[l+NUM_WORDS] ? wdata_b_q : wdata_a_q;
+ end
+ end
+ end
+ end
+endmodule
diff --git a/rtl/HMR/resp_suppress.sv b/rtl/HMR/resp_suppress.sv
new file mode 100644
index 00000000..fa1b8f28
--- /dev/null
+++ b/rtl/HMR/resp_suppress.sv
@@ -0,0 +1,98 @@
+// Copyright 2023 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Suppress the r_valid if set back
+
+module resp_suppress #(
+ parameter int unsigned NumOutstanding = 2,
+ parameter int unsigned AW = 32,
+ parameter int unsigned DW = 32
+) (
+ input logic clk_i,
+ input logic rst_ni,
+
+ input logic ctrl_setback_i,
+
+ input logic req_i,
+ output logic gnt_o,
+ output logic r_valid_o,
+ input logic we_i,
+ input logic [AW -1:0] addr_i,
+ input logic [DW -1:0] data_i,
+ input logic [DW/8-1:0] be_i,
+
+ output logic req_o,
+ input logic gnt_i,
+ input logic r_valid_i,
+ output logic we_o,
+ output logic [AW -1:0] addr_o,
+ output logic [DW -1:0] data_o,
+ output logic [DW/8-1:0] be_o
+);
+
+ logic [$clog2(NumOutstanding)-1:0] outstanding_d, outstanding_q;
+ logic block_d, block_q;
+ logic latent_req_d, latent_req_q;
+ logic we_d, we_q;
+ logic [AW -1:0] addr_d, addr_q;
+ logic [DW -1:0] data_d, data_q;
+ logic [DW/8-1:0] be_d, be_q;
+
+ assign outstanding_d = outstanding_q + (req_o & gnt_i ? 1 : 0) - (r_valid_i ? 1 : 0);
+
+ assign r_valid_o = block_q || latent_req_q ? 1'b0 : r_valid_i;
+ assign gnt_o = latent_req_q ? 1'b0 : gnt_i;
+
+ assign req_o = req_i | latent_req_q;
+ assign we_o = latent_req_q ? we_q : we_i;
+ assign addr_o = latent_req_q ? addr_q : addr_i;
+ assign data_o = latent_req_q ? data_q : data_i;
+ assign be_o = latent_req_q ? be_q : be_i;
+
+ always_comb begin
+ block_d = block_q;
+ latent_req_d = latent_req_q & ~gnt_i;
+ we_d = we_q;
+ addr_d = addr_q;
+ data_d = data_q;
+ be_d = be_q;
+ if (ctrl_setback_i) begin
+ block_d = 1'b1;
+ latent_req_d = req_i & ~gnt_i;
+ we_d = we_i;
+ addr_d = addr_i;
+ data_d = data_i;
+ be_d = be_i;
+ end else if (outstanding_q == 0 && !latent_req_q) begin
+ block_d = 1'b0;
+ end
+ end
+
+ always_ff @( posedge clk_i or negedge rst_ni ) begin : proc_ff
+ if (!rst_ni) begin
+ outstanding_q <= '0;
+ block_q <= '0;
+ latent_req_q <= '0;
+ we_q <= '0;
+ addr_q <= '0;
+ data_q <= '0;
+ be_q <= '0;
+ end else begin
+ outstanding_q <= outstanding_d;
+ block_q <= block_d;
+ latent_req_q <= latent_req_d;
+ we_q <= we_d;
+ addr_q <= addr_d;
+ data_q <= data_d;
+ be_q <= be_d;
+ end
+ end
+
+endmodule
diff --git a/rtl/ecc_wrap/ecc_manager_reg_pkg.sv b/rtl/ecc_wrap/ecc_manager_reg_pkg.sv
index 6c6b88df..cb741759 100644
--- a/rtl/ecc_wrap/ecc_manager_reg_pkg.sv
+++ b/rtl/ecc_wrap/ecc_manager_reg_pkg.sv
@@ -6,6 +6,9 @@
package ecc_manager_reg_pkg;
+ // Param list
+ parameter OffsetStart = 'h100;
+
// Address widths within the block
parameter int BlockAw = 5;
diff --git a/rtl/ecc_wrap/ecc_manager_reg_top.sv b/rtl/ecc_wrap/ecc_manager_reg_top.sv
index eea5ba55..2caf7204 100644
--- a/rtl/ecc_wrap/ecc_manager_reg_top.sv
+++ b/rtl/ecc_wrap/ecc_manager_reg_top.sv
@@ -8,12 +8,12 @@
`include "common_cells/assertions.svh"
module ecc_manager_reg_top #(
- parameter type reg_req_t = logic,
- parameter type reg_rsp_t = logic,
- parameter int AW = 5
+ parameter type reg_req_t = logic,
+ parameter type reg_rsp_t = logic,
+ parameter int AW = 5
) (
- input logic clk_i,
- input logic rst_ni,
+ input clk_i,
+ input rst_ni,
input reg_req_t reg_req_i,
output reg_rsp_t reg_rsp_o,
// To HW
@@ -33,7 +33,7 @@ module ecc_manager_reg_top #(
// register signals
logic reg_we;
logic reg_re;
- logic [BlockAw-1:0] reg_addr;
+ logic [AW-1:0] reg_addr;
logic [DW-1:0] reg_wdata;
logic [DBW-1:0] reg_be;
logic [DW-1:0] reg_rdata;
@@ -54,7 +54,7 @@ module ecc_manager_reg_top #(
assign reg_we = reg_intf_req.valid & reg_intf_req.write;
assign reg_re = reg_intf_req.valid & ~reg_intf_req.write;
- assign reg_addr = reg_intf_req.addr[BlockAw-1:0];
+ assign reg_addr = reg_intf_req.addr;
assign reg_wdata = reg_intf_req.wdata;
assign reg_be = reg_intf_req.wstrb;
assign reg_intf_rsp.rdata = reg_rdata;
@@ -341,55 +341,3 @@ module ecc_manager_reg_top #(
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
endmodule
-
-module ecc_manager_reg_top_intf
-#(
- parameter int AW = 5,
- localparam int DW = 32
-) (
- input logic clk_i,
- input logic rst_ni,
- REG_BUS.in regbus_slave,
- // To HW
- output ecc_manager_reg_pkg::ecc_manager_reg2hw_t reg2hw, // Write
- input ecc_manager_reg_pkg::ecc_manager_hw2reg_t hw2reg, // Read
- // Config
- input devmode_i // If 1, explicit error return for unmapped register access
-);
- localparam int unsigned STRB_WIDTH = DW/8;
-
-`include "register_interface/typedef.svh"
-`include "register_interface/assign.svh"
-
- // Define structs for reg_bus
- typedef logic [AW-1:0] addr_t;
- typedef logic [DW-1:0] data_t;
- typedef logic [STRB_WIDTH-1:0] strb_t;
- `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t)
-
- reg_bus_req_t s_reg_req;
- reg_bus_rsp_t s_reg_rsp;
-
- // Assign SV interface to structs
- `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave)
- `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp)
-
-
-
- ecc_manager_reg_top #(
- .reg_req_t(reg_bus_req_t),
- .reg_rsp_t(reg_bus_rsp_t),
- .AW(AW)
- ) i_regs (
- .clk_i,
- .rst_ni,
- .reg_req_i(s_reg_req),
- .reg_rsp_o(s_reg_rsp),
- .reg2hw, // Write
- .hw2reg, // Read
- .devmode_i
- );
-
-endmodule
-
-
diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv
new file mode 100644
index 00000000..513d378d
--- /dev/null
+++ b/rtl/ecc_wrap/ecc_scrubber_out.sv
@@ -0,0 +1,382 @@
+// Copyright 2021 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Scrubber for ecc
+// - iteratively steps through memory bank
+// - the out scrubber itself does't correct data, the ecc_sram_wrap itself will write the corrected read data back to sram
+
+module ecc_scrubber_out #(
+ parameter type data_be_t = logic,
+ parameter int unsigned TagSramWidth = 32,
+ parameter int unsigned TagDataWidth = 32,
+ parameter int unsigned DataWidth = 128,
+ parameter int unsigned TagDepth = 256,
+ parameter int unsigned DataDepth = 2048,
+ parameter int unsigned TagReadLatency = 1,
+ parameter int unsigned DataReadLatency= 1,
+ parameter type error_info_per_way_t = logic,
+ // Dependency parameters:
+ parameter int unsigned DataTagDepthFactor = DataDepth/TagDepth // should equal to the block number for each index
+
+
+) (
+ input logic clk_i,
+ input logic rst_ni,
+
+ input logic scrub_trigger_i, // Set to 1'b0 to disable
+ output logic scrub_tag_bit_corrected_o,
+ output logic scrub_tag_uncorrectable_o,
+ output logic scrub_data_bit_corrected_o,
+ output logic scrub_data_uncorrectable_o,
+
+ output logic tag_single_error_o,
+ output logic tag_multi_error_o,
+ output logic data_single_error_o,
+ output logic data_multi_error_o,
+
+ output logic tag_valid_bit_o,
+ output logic tag_dirty_bit_o,
+
+ // Input signals from others accessing tag memory bank
+ input logic tag_intc_req_i,
+ output logic tag_intc_gnt_o,
+ input logic tag_intc_we_i,
+ input logic tag_intc_be_i,
+ input logic [$clog2(TagDepth)-1:0] tag_intc_add_i,
+ input logic [ TagSramWidth-1:0] tag_intc_wdata_i,
+ output logic [ TagSramWidth-1:0] tag_intc_rdata_o,
+ output logic tag_intc_multi_err_o,
+
+ // Input signals from others accessing data memory bank
+ input logic data_intc_req_i,
+ output logic data_intc_gnt_o,
+ input logic data_intc_we_i,
+ input data_be_t data_intc_be_i,
+ input logic [$clog2(DataDepth)-1:0]data_intc_add_i,
+ input logic [ DataWidth-1:0] data_intc_wdata_i,
+ output logic [ DataWidth-1:0] data_intc_rdata_o,
+ output logic data_intc_multi_err_o,
+
+ // Output directly to tag bank
+ output logic tag_bank_req_o,
+ input logic tag_bank_gnt_i,
+ output logic tag_bank_we_o,
+ output logic tag_bank_be_o,
+ output logic [$clog2(TagDepth)-1:0] tag_bank_add_o,
+ output logic [$clog2(TagDepth)-1:0] tag_bank_add_q_o,
+ output logic [ TagSramWidth-1:0] tag_bank_wdata_o,
+ input logic [ TagSramWidth-1:0] tag_bank_rdata_i,
+
+ // Output directly to data bank
+ output logic data_bank_req_o,
+ input logic data_bank_gnt_i,
+ output logic data_bank_we_o,
+ output data_be_t data_bank_be_o,
+ output logic [$clog2(DataDepth)-1:0]data_bank_add_o,
+ output logic [$clog2(DataDepth)-1:0]data_bank_add_q_o,
+ output logic [ DataWidth-1:0] data_bank_wdata_o,
+ input logic [ DataWidth-1:0] data_bank_rdata_i,
+
+ // Input external ECC result
+ input error_info_per_way_t ecc_err_i
+);
+
+ logic scrub_req;
+ logic scrub_taginv;
+ logic scrub_we;
+ logic [$clog2(DataDepth)-1:0]scrub_add;
+ // logic [ DataWidth-1:0] scrub_wdata;
+ logic [ TagSramWidth-1:0] scrub_tag_rdata;
+ logic [ DataWidth-1:0] scrub_data_rdata;
+
+ typedef enum logic [1:0] {Idle, Read, Check, TagInv} scrub_state_e;
+
+ scrub_state_e state_d, state_q;
+
+ logic [$clog2(DataDepth)-1:0] working_add_d, working_add_q, working_add_plus1; // use data addr as it should be >= tag addr size, because the block number per index
+
+ logic tag_rwdata_en, data_rwdata_en;
+ logic tag_rdata_en, tag_rdata_en_q;
+ logic data_rdata_en, data_rdata_en_q;
+ logic data_wdata_en, data_wdata_en_q;
+ logic data_en_q;
+ logic [TagSramWidth-1:0] tag_rdata_q;
+ logic [DataWidth-1:0] data_rdata_q;
+ logic tag_intc_multi_err_q;
+ logic data_intc_multi_err_q;
+ logic [$clog2(TagDepth)-1:0] tag_bank_add_q;
+ logic [$clog2(DataDepth)-1:0] data_bank_add_q;
+
+ assign tag_rwdata_en = tag_intc_req_i & tag_bank_gnt_i;
+ assign data_rwdata_en = data_intc_req_i & data_bank_gnt_i;
+
+ assign tag_rdata_en = tag_rwdata_en & ~tag_intc_we_i;
+ assign data_rdata_en = data_rwdata_en & ~data_intc_we_i;
+ assign data_wdata_en = data_rwdata_en & data_intc_we_i;
+ assign data_en_q = data_rdata_en_q | data_wdata_en_q;
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if(~rst_ni) begin
+ tag_rdata_q <= '0;
+ tag_intc_multi_err_q <= '0;
+ end else if (tag_rdata_en_q) begin
+ tag_rdata_q <= tag_bank_rdata_i;
+ tag_intc_multi_err_q <= ecc_err_i.tag_sram_multi_error;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if(~rst_ni) begin
+ data_rdata_q <= '0;
+ end else if (data_rdata_en_q) begin
+ data_rdata_q <= data_bank_rdata_i;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if(~rst_ni) begin
+ data_intc_multi_err_q <= '0;
+ end else if (data_en_q) begin
+ data_intc_multi_err_q <= ecc_err_i.data_sram_multi_error;
+ end
+ end
+
+
+ // always_ff @(posedge clk_i or negedge rst_ni) begin
+ // if(~rst_ni) begin
+ // tag_rdata_en_q <= 1'b0;
+ // data_rdata_en_q <= 1'b0;
+ // data_wdata_en_q <= 1'b0;
+ // end else begin
+ // tag_rdata_en_q <= tag_rdata_en;
+ // data_rdata_en_q <= data_rdata_en;
+ // data_wdata_en_q <= data_wdata_en;
+ // end
+ // end
+
+ shift_reg #(
+ .dtype ( logic ),
+ .Depth ( TagReadLatency )
+ ) i_shift_reg_tag_rdata_en_q (
+ .clk_i,
+ .rst_ni,
+ .d_i ( tag_rdata_en ),
+ .d_o ( tag_rdata_en_q )
+ );
+
+ shift_reg #(
+ .dtype ( logic ),
+ .Depth ( DataReadLatency)
+ ) i_shift_reg_data_rdata_en_q (
+ .clk_i,
+ .rst_ni,
+ .d_i ( data_rdata_en ),
+ .d_o ( data_rdata_en_q )
+ );
+
+ shift_reg #(
+ .dtype ( logic ),
+ .Depth ( DataReadLatency)
+ ) i_shift_reg_data_wdata_en_q (
+ .clk_i,
+ .rst_ni,
+ .d_i ( data_wdata_en ),
+ .d_o ( data_wdata_en_q )
+ );
+
+ assign scrub_add = working_add_q;
+
+ assign tag_bank_req_o = tag_intc_req_i || scrub_req || scrub_taginv;
+ assign tag_intc_gnt_o = tag_bank_gnt_i & ~scrub_taginv; // if scrubbr finds a valid clean data with uncorrectable error, need to invalidate the cache line, block tag for a while
+ assign tag_intc_rdata_o = tag_rdata_en_q ? tag_bank_rdata_i : tag_rdata_q;
+ assign tag_intc_multi_err_o = tag_rdata_en_q ? ecc_err_i.tag_sram_multi_error : tag_intc_multi_err_q;
+
+ assign data_bank_req_o = data_intc_req_i || scrub_req;
+ assign data_intc_gnt_o = data_bank_gnt_i;
+ assign data_intc_rdata_o = data_rdata_en_q ? data_bank_rdata_i : data_rdata_q;
+ // for data sram write, because the read modify wrtie for partial block write exist, may have error respones the next cycle of the write gnt
+ assign data_intc_multi_err_o = data_en_q ? ecc_err_i.data_sram_multi_error : data_intc_multi_err_q;
+
+ assign scrub_tag_rdata = tag_bank_rdata_i;
+ assign scrub_data_rdata = data_bank_rdata_i;
+
+ always_comb begin : proc_tag_bank_assign
+ // By default, bank is connected to outside
+ tag_bank_we_o = tag_intc_we_i;
+ tag_bank_be_o = tag_intc_be_i;
+ tag_bank_add_o = tag_intc_add_i;
+ tag_bank_wdata_o = tag_intc_wdata_i;
+
+ // If scrubber active and outside is not, do scrub
+ if(scrub_taginv || (state_q == TagInv)) begin
+ tag_bank_we_o = 1'b1;
+ tag_bank_be_o = '1;
+ tag_bank_add_o = scrub_add[$clog2(DataDepth)-1:$clog2(DataTagDepthFactor)];
+ tag_bank_wdata_o = '0;
+ end else if ( (state_q == Read || state_q == Check) && (tag_intc_req_i == 1'b0) && (data_intc_req_i == 1'b0)) begin
+ tag_bank_we_o = 1'b0;
+ tag_bank_be_o = '0;
+ tag_bank_add_o = scrub_add[$clog2(DataDepth)-1:$clog2(DataTagDepthFactor)];
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if(~rst_ni) begin
+ tag_bank_add_q <= '0;
+ end else begin
+ if(tag_rwdata_en) begin
+ tag_bank_add_q <= tag_bank_add_o;
+ end
+ end
+ end
+
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if(~rst_ni) begin
+ data_bank_add_q <= '0;
+ end else begin
+ if(data_rwdata_en) begin
+ data_bank_add_q <= data_bank_add_o;
+ end
+ end
+ end
+
+ assign tag_bank_add_q_o = tag_bank_add_q;
+ assign data_bank_add_q_o = data_bank_add_q;
+
+ always_comb begin : proc_data_bank_assign
+ // By default, bank is connected to outside
+ data_bank_we_o = data_intc_we_i;
+ data_bank_be_o = data_intc_be_i;
+ data_bank_add_o = data_intc_add_i;
+ data_bank_wdata_o = data_intc_wdata_i;
+
+ // If scrubber active and outside is not, do scrub
+ if ( (state_q == Read || state_q == Check) && (tag_intc_req_i == 1'b0) && (data_intc_req_i == 1'b0)) begin
+ data_bank_we_o = 1'b0;
+ data_bank_be_o = '0;
+ data_bank_add_o = scrub_add;
+ end
+ end
+
+ always_comb begin : proc_FSM_logic
+ state_d = state_q;
+ scrub_req = 1'b0;
+ scrub_taginv = 1'b0;
+ working_add_d = working_add_q;
+ scrub_tag_bit_corrected_o = 1'b0;
+ scrub_tag_uncorrectable_o = 1'b0;
+ scrub_data_bit_corrected_o = 1'b0;
+ scrub_data_uncorrectable_o = 1'b0;
+
+ case (state_q)
+ Idle: begin
+ // Switch to read state if triggered to scrub
+ if (scrub_trigger_i) begin
+ state_d = Read;
+ end
+ end
+ Read: begin
+ // Request only active if outside is inactive, and the ecc_sram is ready
+ if ((tag_intc_req_i == 1'b0) &&
+ (tag_bank_gnt_i == 1'b1) &&
+ (data_intc_req_i == 1'b0) &&
+ (data_bank_gnt_i == 1'b1)
+ ) begin
+ // Request read to scrub
+ scrub_req = 1'b1;
+ state_d = Check;
+ end
+ end
+ Check: begin
+ // Find uncorrectable error in a valid clean data line, invalidate the line
+ if(data_multi_error_o) begin
+ if(~tag_multi_error_o) begin
+ if(tag_valid_bit_o & ~tag_dirty_bit_o) begin
+ scrub_taginv = 1'b1;
+ if(tag_bank_gnt_i) begin
+ state_d = Idle;
+ working_add_d = working_add_plus1; // increment address
+ end else begin
+ state_d = TagInv;
+ working_add_d = working_add_q; // don't increment address
+ end
+ end
+ end
+ end else begin
+ // Return to idle state
+ state_d = Idle;
+ working_add_d = working_add_plus1; // increment address
+ end
+
+ scrub_tag_bit_corrected_o = tag_single_error_o;
+ scrub_tag_uncorrectable_o = tag_multi_error_o;
+ scrub_data_bit_corrected_o = data_single_error_o;
+ scrub_data_uncorrectable_o = data_multi_error_o;
+ end
+ TagInv: begin
+ scrub_taginv = 1'b1;
+ if(tag_bank_gnt_i) begin
+ state_d = Idle;
+ working_add_d = working_add_plus1; // increment address
+ end else begin
+ state_d = TagInv;
+ working_add_d = working_add_q; // don't increment address
+ end
+ end
+ default: /* do nothing */;
+ endcase
+ end
+
+ // TODO: tag sram has uncorrectable error, interrupt
+ // TODO: data sram has uncorrectable error, interrupt, has addr info
+
+
+ assign tag_single_error_o = ecc_err_i.tag_sram_single_error;
+ assign tag_multi_error_o = ecc_err_i.tag_sram_multi_error;
+ assign data_single_error_o = ecc_err_i.data_sram_single_error;
+ assign data_multi_error_o = ecc_err_i.data_sram_multi_error;
+
+ // typedef to have consistent tag data (that what gets written into the sram)
+ assign tag_valid_bit_o = tag_bank_rdata_i[TagDataWidth-1];
+ assign tag_dirty_bit_o = tag_bank_rdata_i[TagDataWidth-2];
+
+ assign working_add_plus1 = (working_add_q + 1) % DataDepth; // increment address
+ always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bank_add
+ if(!rst_ni) begin
+ working_add_q <= '0;
+ end else begin
+ working_add_q <= working_add_d;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin : proc_FSM
+ if(!rst_ni) begin
+ state_q <= Idle;
+ end else begin
+ state_q <= state_d;
+ end
+ end
+
+
+`ifndef TARGET_SYNTHESIS
+ always @(posedge clk_i) begin
+ if ((scrub_tag_bit_corrected_o) == 1)
+ $display("[ECC SCRUB] %t - tag single error detected", $realtime);
+ if ((scrub_data_bit_corrected_o) == 1)
+ $display("[ECC SCRUB] %t - data single error detected", $realtime);
+ if ((scrub_tag_uncorrectable_o) == 1)
+ $display("[ECC SCRUB] %t - tag multi error detected", $realtime);
+ if ((scrub_data_uncorrectable_o) == 1)
+ $display("[ECC SCRUB] %t - data multi error detected", $realtime);
+ end
+`endif
+
+endmodule
diff --git a/rtl/ecc_wrap/ecc_sram.sv b/rtl/ecc_wrap/ecc_sram.sv
index 15df7b02..836eca63 100644
--- a/rtl/ecc_wrap/ecc_sram.sv
+++ b/rtl/ecc_wrap/ecc_sram.sv
@@ -17,6 +17,7 @@ module ecc_sram #(
parameter bit InputECC = 0, // 0: no ECC on input
// 1: SECDED on input
parameter int unsigned NumRMWCuts = 0, // Number of cuts in the read-modify-write path
+ parameter int unsigned NumOutputCuts = 0, // Number of cuts in the data output path
parameter SimInit = "random", // ("zeros", "ones", "random", "none")
parameter int unsigned ByteWidth = 8,
// Set params
@@ -43,19 +44,55 @@ module ecc_sram #(
output logic multi_error_o
);
+ typedef struct packed {
+ logic [ DataInWidth-1:0] corrected_data;
+ logic [BankAddrWidth-1:0] bank_addr;
+ } correct_info_t;
+
logic [1:0] ecc_error;
logic valid_read_d, valid_read_q;
+ logic valid_load_d, valid_load_q;
+ correct_info_t corrected_data_raw_d, corrected_data_raw_q;
+ logic corrected_data_raw_en;
+ logic corrected_data_raw_valid_d, corrected_data_raw_valid_q;
+ logic corrected_data_raw_valid_en;
+ logic corrected_data_raw_valid_set, corrected_data_raw_valid_clr;
+ logic in_update_corrected_data_mode;
+
+ logic [ DataInWidth-1:0] rdata;
+
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_valid_read
if(~rst_ni) begin
valid_read_q <= '0;
+ valid_load_q <= '0;
end else begin
valid_read_q <= valid_read_d;
+ valid_load_q <= valid_load_d;
+ end
+ end
+
+ always_ff @(posedge clk_i) begin : proc_corrected_data_update
+ if(corrected_data_raw_valid_set) begin
+ corrected_data_raw_q <= corrected_data_raw_d;
+ end
+ end
+
+ assign corrected_data_raw_valid_set = corrected_data_raw_en;
+ assign corrected_data_raw_valid_clr = in_update_corrected_data_mode;
+ assign corrected_data_raw_valid_en = corrected_data_raw_valid_set | corrected_data_raw_valid_clr;
+ assign corrected_data_raw_valid_d = corrected_data_raw_valid_set | (~corrected_data_raw_valid_clr);
+ always_ff @(posedge clk_i or negedge rst_ni) begin : proc_corrected_data_raw_valid
+ if(~rst_ni) begin
+ corrected_data_raw_valid_q <= '0;
+ end else if(corrected_data_raw_valid_en) begin
+ corrected_data_raw_valid_q <= corrected_data_raw_valid_d;
end
end
assign valid_read_d = req_i && gnt_o &&
(~we_i || (be_i != {ByteEnWidth{1'b1}}));
+ assign valid_load_d = req_i && gnt_o && ~we_i;
assign single_error_o = ecc_error[0] && valid_read_q;
assign multi_error_o = ecc_error[1] && valid_read_q;
@@ -74,13 +111,13 @@ module ecc_sram #(
logic [ProtectedWidth-1:0] bank_wdata;
logic [ProtectedWidth-1:0] bank_rdata;
- logic bank_scrub_req;
- logic bank_scrub_we;
+ logic bank_scrub_req, bank_scrub_req_q;
+ logic bank_scrub_we, bank_scrub_we_q;
logic [ BankAddrWidth-1:0] bank_scrub_addr;
logic [ProtectedWidth-1:0] bank_scrub_wdata;
logic [ProtectedWidth-1:0] bank_scrub_rdata;
- typedef enum logic { NORMAL, READ_MODIFY_WRITE } store_state_e;
+ typedef enum logic[1:0] { NORMAL, READ_MODIFY_WRITE, UPDATE_CORRECTED_DATA } store_state_e;
store_state_e store_state_d, store_state_q;
typedef logic [cf_math_pkg::idx_width(NumRMWCuts)-1:0] rmw_count_t;
@@ -140,11 +177,21 @@ module ecc_sram #(
.out ( bank_wdata )
);
- assign rdata_o = loaded;
+ assign rdata = loaded;
assign to_store = store_state_q == NORMAL ?
wdata_i :
- (be_selector & input_buffer_q) | (~be_selector & loaded);
+ store_state_q == READ_MODIFY_WRITE ?
+ (be_selector & input_buffer_q) | (~be_selector & loaded) :
+ corrected_data_raw_q.corrected_data;
+
+ // for read transaction, update the sram content after a single-error was corrected
+ assign corrected_data_raw_en = valid_load_q && single_error_o;
+ assign corrected_data_raw_d = correct_info_t'{
+ corrected_data: rdata,
+ bank_addr : addr_buffer_q
+ };
+
end else begin : gen_ecc_input
@@ -152,7 +199,7 @@ module ecc_sram #(
logic [UnprotectedWidth-1:0] intermediate_data_ld, intermediate_data_st;
assign bank_wdata = store_state_q == NORMAL ? wdata_i : lns_wdata;
- assign rdata_o = bank_rdata;
+ assign rdata = bank_rdata;
hsiao_ecc_dec #(
.DataWidth (UnprotectedWidth),
@@ -194,27 +241,43 @@ module ecc_sram #(
be_buffer_d = be_i;
bank_req = req_i;
rmw_count_d = rmw_count_q;
- if (store_state_q == NORMAL) begin
- if (req_i & (be_i != {ByteEnWidth{1'b1}}) & we_i) begin
- store_state_d = READ_MODIFY_WRITE;
- bank_we = 1'b0;
- rmw_count_d = rmw_count_t'(NumRMWCuts);
+ in_update_corrected_data_mode = 1'b0;
+ case (store_state_q)
+ NORMAL: begin
+ if (req_i & (be_i != {ByteEnWidth{1'b1}}) & we_i) begin
+ store_state_d = READ_MODIFY_WRITE;
+ bank_we = 1'b0;
+ rmw_count_d = rmw_count_t'(NumRMWCuts);
+ end
+ if(~req_i & corrected_data_raw_valid_q) begin
+ store_state_d = UPDATE_CORRECTED_DATA;
+ end
end
- end else begin
- gnt_o = 1'b0;
- bank_addr = addr_buffer_q;
- bank_we = 1'b1;
- input_buffer_d = input_buffer_q;
- addr_buffer_d = addr_buffer_q;
- be_buffer_d = be_buffer_q;
- if (rmw_count_q == '0) begin
- bank_req = 1'b1;
- end else begin
- bank_req = 1'b0;
- rmw_count_d = rmw_count_q - 1;
- store_state_d = READ_MODIFY_WRITE;
+ READ_MODIFY_WRITE: begin
+ gnt_o = 1'b0;
+ bank_addr = addr_buffer_q;
+ bank_we = 1'b1;
+ input_buffer_d = input_buffer_q;
+ addr_buffer_d = addr_buffer_q;
+ be_buffer_d = be_buffer_q;
+ if (rmw_count_q == '0) begin
+ bank_req = 1'b1;
+ end else begin
+ bank_req = 1'b0;
+ rmw_count_d = rmw_count_q - 1;
+ store_state_d = READ_MODIFY_WRITE;
+ end
end
- end
+ UPDATE_CORRECTED_DATA: begin
+ gnt_o = 1'b0;
+ bank_addr = corrected_data_raw_q.bank_addr;
+ bank_we = 1'b1;
+ bank_req = 1'b1;
+ in_update_corrected_data_mode = 1'b1;
+ store_state_d = NORMAL;
+ end
+ default: /* do nothing */;
+ endcase
end
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_read_modify_write_ff
@@ -284,4 +347,15 @@ module ecc_sram #(
.rdata_o ( bank_scrub_rdata ) // read data
);
+
+ // Output spill register for breaking timing path
+ shift_reg #(
+ .dtype(logic[DataInWidth-1:0]),
+ .Depth(NumOutputCuts)
+ ) i_output_buffer (
+ .clk_i,
+ .rst_ni,
+ .d_i (rdata),
+ .d_o (rdata_o)
+ );
endmodule
diff --git a/rtl/ecc_wrap/ecc_sram_wrap.sv b/rtl/ecc_wrap/ecc_sram_wrap.sv
index d053c11c..f33e3d7d 100644
--- a/rtl/ecc_wrap/ecc_sram_wrap.sv
+++ b/rtl/ecc_wrap/ecc_sram_wrap.sv
@@ -20,8 +20,8 @@ module ecc_sram_wrap #(
// Requries bitwise byte enable in SRAM
parameter int unsigned NumRMWCuts = 0, // Number of cuts in the read-modify-write path
// Set params
- parameter int unsigned UnprotectedWidth = 32, // This currently only works for 32bit
- parameter int unsigned ProtectedWidth = 39, // This currently only works for 39bit
+ parameter int unsigned UnprotectedWidth = 32,
+ parameter int unsigned ProtectedWidth = 39,
localparam int unsigned DataInWidth = InputECC ? ProtectedWidth : UnprotectedWidth,
localparam int unsigned BEInWidth = UnprotectedWidth/8,
localparam int unsigned BankAddWidth = $clog2(BankSize)
@@ -51,17 +51,29 @@ module ecc_sram_wrap #(
logic [1:0] ecc_error;
logic valid_read_d, valid_read_q;
+ logic valid_load_d, valid_load_q;
+ logic [DataInWidth-1:0] corrected_data_raw_d, corrected_data_raw_q;
+ logic corrected_data_raw_en;
+ logic in_update_corrected_data_mode;
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_valid_read
if(~rst_ni) begin
valid_read_q <= '0;
end else begin
valid_read_q <= valid_read_d;
+ valid_load_q <= valid_load_d;
+ end
+ end
+
+ always_ff @(posedge clk_i) begin : proc_corrected_data_update
+ if(corrected_data_raw_en) begin
+ corrected_data_raw_q <= corrected_data_raw_d;
end
end
assign valid_read_d = tcdm_req_i && tcdm_gnt_o &&
(tcdm_wen_i || (tcdm_be_i != {BEInWidth{1'b1}}));
+ assign valid_load_d = tcdm_req_i && tcdm_gnt_o && tcdm_wen_i;
assign single_error_o = ecc_error[0] && valid_read_q;
assign multi_error_o = ecc_error[1] && valid_read_q;
@@ -93,7 +105,7 @@ module ecc_sram_wrap #(
logic bank_final_we;
logic [ BankAddWidth-1:0] bank_final_add;
- typedef enum logic { NORMAL, LOAD_AND_STORE } store_state_e;
+ typedef enum logic[1:0] { NORMAL, LOAD_AND_STORE, UPDATE_CORRECTED_DATA } store_state_e;
store_state_e store_state_d, store_state_q;
logic [cf_math_pkg::idx_width(NumRMWCuts)-1:0] rmw_count_d, rmw_count_q;
@@ -102,8 +114,11 @@ module ecc_sram_wrap #(
logic [ BEInWidth-1:0] be_buffer_d, be_buffer_q;
logic [UnprotectedWidth-1:0] be_selector;
- assign be_selector = {{8{be_buffer_q[3]}},{8{be_buffer_q[2]}},
- {8{be_buffer_q[1]}},{8{be_buffer_q[0]}}};
+ generate
+ for(genvar i = 0; i < UnprotectedWidth / 8; i++) begin: gen_be_selector
+ assign be_selector[i*8 +: 8] = {8{be_buffer_q[i]}};
+ end
+ endgenerate
logic [ProtectedWidth-1:0] rmw_buffer_end;
logic [ProtectedWidth-1:0] rmw_buffer_0;
@@ -132,14 +147,11 @@ module ecc_sram_wrap #(
assign decoder_in = store_state_q == NORMAL ? bank_rdata : rmw_buffer_end;
- hsiao_ecc_dec #(
- .DataWidth (UnprotectedWidth),
- .ProtWidth (ProtectedWidth - UnprotectedWidth)
- ) ecc_decode (
- .in ( decoder_in ),
- .out ( loaded ),
- .syndrome_o(),
- .err_o ( ecc_error )
+ prim_secded_39_32_dec ecc_decode (
+ .in ( decoder_in ),
+ .d_o ( loaded ),
+ .syndrome_o (),
+ .err_o (ecc_error)
);
hsiao_ecc_enc #(
@@ -154,8 +166,15 @@ module ecc_sram_wrap #(
assign to_store = store_state_q == NORMAL ?
tcdm_wdata_i :
+ in_update_corrected_data_mode ?
+ corrected_data_raw_q :
(be_selector & input_buffer_q) | (~be_selector & loaded);
+ // for read transaction, update the sram content after a single-error was corrected
+ assign corrected_data_raw_en = valid_load_q && single_error_o;
+ assign corrected_data_raw_d = tcdm_rdata_o;
+
+
end else begin : gen_ecc_input
logic [ ProtectedWidth-1:0] lns_wdata;
@@ -164,12 +183,9 @@ module ecc_sram_wrap #(
assign bank_wdata = store_state_q == NORMAL ? tcdm_wdata_i : lns_wdata;
assign tcdm_rdata_o = bank_rdata;
- hsiao_ecc_dec #(
- .DataWidth (UnprotectedWidth),
- .ProtWidth (ProtectedWidth - UnprotectedWidth)
- ) ld_decode (
- .in ( rmw_buffer_end ),
- .out ( intermediate_data_ld ),
+ prim_secded_39_32_dec ld_decode (
+ .in (rmw_buffer_end),
+ .d_o (intermediate_data_ld),
.syndrome_o(),
.err_o ()
);
@@ -191,7 +207,6 @@ module ecc_sram_wrap #(
.in ( (be_selector & intermediate_data_st) | (~be_selector & intermediate_data_ld) ),
.out ( lns_wdata )
);
-
end
always_comb begin
@@ -204,27 +219,46 @@ module ecc_sram_wrap #(
be_buffer_d = tcdm_be_i;
bank_req = tcdm_req_i;
rmw_count_d = rmw_count_q;
- if (store_state_q == NORMAL) begin
- if (tcdm_req_i & (tcdm_be_i != 4'b1111) & ~tcdm_wen_i) begin
- store_state_d = LOAD_AND_STORE;
- bank_we = 1'b0;
- rmw_count_d = NumRMWCuts;
+ in_update_corrected_data_mode = 1'b0;
+ case (store_state_q)
+ NORMAL: begin
+ if (tcdm_req_i & (&tcdm_be_i != 1'b1) & ~tcdm_wen_i) begin
+ store_state_d = LOAD_AND_STORE;
+ bank_we = 1'b0;
+ rmw_count_d = NumRMWCuts;
+ end
+ if(valid_load_q && single_error_o) begin
+ store_state_d = UPDATE_CORRECTED_DATA;
+ tcdm_gnt_o = 1'b0;
+ add_buffer_d = add_buffer_q;
+ bank_req = 1'b0;
+ end
end
- end else begin
- tcdm_gnt_o = 1'b0;
- bank_add = add_buffer_q;
- bank_we = 1'b1;
- input_buffer_d = input_buffer_q;
- add_buffer_d = add_buffer_q;
- be_buffer_d = be_buffer_q;
- if (rmw_count_q == '0) begin
- bank_req = 1'b1;
- end else begin
- bank_req = 1'b0;
- rmw_count_d = rmw_count_q - 1;
- store_state_d = LOAD_AND_STORE;
+ LOAD_AND_STORE: begin
+ tcdm_gnt_o = 1'b0;
+ bank_add = add_buffer_q;
+ bank_we = 1'b1;
+ input_buffer_d = input_buffer_q;
+ add_buffer_d = add_buffer_q;
+ be_buffer_d = be_buffer_q;
+ if (rmw_count_q == '0) begin
+ bank_req = 1'b1;
+ end else begin
+ bank_req = 1'b0;
+ rmw_count_d = rmw_count_q - 1;
+ store_state_d = LOAD_AND_STORE;
+ end
end
- end
+ UPDATE_CORRECTED_DATA: begin
+ tcdm_gnt_o = 1'b0;
+ bank_req = 1'b1;
+ bank_we = 1'b1;
+ bank_add = add_buffer_q;
+ in_update_corrected_data_mode = 1'b1;
+ store_state_d = NORMAL;
+ end
+ default: /* do nothing */;
+ endcase
end
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_load_and_store_ff
@@ -246,7 +280,8 @@ module ecc_sram_wrap #(
ecc_scrubber #(
.BankSize ( BankSize ),
.UseExternalECC ( 0 ),
- .DataWidth ( ProtectedWidth )
+ .DataWidth ( ProtectedWidth ),
+ .ProtWidth (ProtectedWidth - UnprotectedWidth)
) i_scrubber (
.clk_i,
.rst_ni,
diff --git a/rtl/ecc_wrap/ecc_sram_wrapper.hjson b/rtl/ecc_wrap/ecc_sram_wrapper.hjson
index b635caf2..b7026c45 100644
--- a/rtl/ecc_wrap/ecc_sram_wrapper.hjson
+++ b/rtl/ecc_wrap/ecc_sram_wrapper.hjson
@@ -9,6 +9,14 @@
],
regwidth: "32",
+ param_list: [
+ { name: "OffsetStart",
+ desc: "Starting offset of this reg set",
+ type: "",
+ default: "'h100",
+ local: "true"
+ },
+ ],
registers: [
{ name: "mismatch_count",
diff --git a/rtl/lowrisc_ecc/prim_secded_13_8_cor.sv b/rtl/lowrisc_ecc/prim_secded_13_8_cor.sv
index 644fa91e..b1ba2ff0 100644
--- a/rtl/lowrisc_ecc/prim_secded_13_8_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_13_8_cor.sv
@@ -16,20 +16,20 @@ module prim_secded_13_8_cor (
// Syndrome calculation
assign syndrome_o[0] = ^(d_i & 13'h016B);
- assign syndrome_o[1] = ^(d_i & 13'h02AD);
+ assign syndrome_o[1] = ^(d_i & 13'h02F8);
assign syndrome_o[2] = ^(d_i & 13'h04D5);
- assign syndrome_o[3] = ^(d_i & 13'h0836);
- assign syndrome_o[4] = ^(d_i & 13'h10DA);
+ assign syndrome_o[3] = ^(d_i & 13'h08A7);
+ assign syndrome_o[4] = ^(d_i & 13'h101E);
// Corrected output calculation
- assign d_o[0] = (syndrome_o == 5'h7) ^ d_i[0];
+ assign d_o[0] = (syndrome_o == 5'hd) ^ d_i[0];
assign d_o[1] = (syndrome_o == 5'h19) ^ d_i[1];
- assign d_o[2] = (syndrome_o == 5'he) ^ d_i[2];
+ assign d_o[2] = (syndrome_o == 5'h1c) ^ d_i[2];
assign d_o[3] = (syndrome_o == 5'h13) ^ d_i[3];
- assign d_o[4] = (syndrome_o == 5'h1c) ^ d_i[4];
+ assign d_o[4] = (syndrome_o == 5'h16) ^ d_i[4];
assign d_o[5] = (syndrome_o == 5'hb) ^ d_i[5];
- assign d_o[6] = (syndrome_o == 5'h15) ^ d_i[6];
- assign d_o[7] = (syndrome_o == 5'h16) ^ d_i[7];
+ assign d_o[6] = (syndrome_o == 5'h7) ^ d_i[6];
+ assign d_o[7] = (syndrome_o == 5'he) ^ d_i[7];
assign d_o[8] = (syndrome_o == 5'h1) ^ d_i[8];
assign d_o[9] = (syndrome_o == 5'h2) ^ d_i[9];
assign d_o[10] = (syndrome_o == 5'h4) ^ d_i[10];
diff --git a/rtl/lowrisc_ecc/prim_secded_22_16_cor.sv b/rtl/lowrisc_ecc/prim_secded_22_16_cor.sv
index 96851a5e..b3fd2e4e 100644
--- a/rtl/lowrisc_ecc/prim_secded_22_16_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_22_16_cor.sv
@@ -15,30 +15,30 @@ module prim_secded_22_16_cor (
logic single_error;
// Syndrome calculation
- assign syndrome_o[0] = ^(d_i & 22'h015555);
- assign syndrome_o[1] = ^(d_i & 22'h02AA55);
- assign syndrome_o[2] = ^(d_i & 22'h0495A9);
- assign syndrome_o[3] = ^(d_i & 22'h0869A6);
- assign syndrome_o[4] = ^(d_i & 22'h10669A);
- assign syndrome_o[5] = ^(d_i & 22'h209A6A);
+ assign syndrome_o[0] = ^(d_i & 22'h017B48);
+ assign syndrome_o[1] = ^(d_i & 22'h0291AB);
+ assign syndrome_o[2] = ^(d_i & 22'h040E3D);
+ assign syndrome_o[3] = ^(d_i & 22'h087692);
+ assign syndrome_o[4] = ^(d_i & 22'h10A547);
+ assign syndrome_o[5] = ^(d_i & 22'h20C8F4);
// Corrected output calculation
- assign d_o[0] = (syndrome_o == 6'h7) ^ d_i[0];
- assign d_o[1] = (syndrome_o == 6'h38) ^ d_i[1];
- assign d_o[2] = (syndrome_o == 6'hb) ^ d_i[2];
- assign d_o[3] = (syndrome_o == 6'h34) ^ d_i[3];
- assign d_o[4] = (syndrome_o == 6'h13) ^ d_i[4];
- assign d_o[5] = (syndrome_o == 6'h2c) ^ d_i[5];
- assign d_o[6] = (syndrome_o == 6'h23) ^ d_i[6];
- assign d_o[7] = (syndrome_o == 6'h1c) ^ d_i[7];
- assign d_o[8] = (syndrome_o == 6'hd) ^ d_i[8];
- assign d_o[9] = (syndrome_o == 6'h32) ^ d_i[9];
- assign d_o[10] = (syndrome_o == 6'h15) ^ d_i[10];
- assign d_o[11] = (syndrome_o == 6'h2a) ^ d_i[11];
- assign d_o[12] = (syndrome_o == 6'h25) ^ d_i[12];
- assign d_o[13] = (syndrome_o == 6'h1a) ^ d_i[13];
- assign d_o[14] = (syndrome_o == 6'h19) ^ d_i[14];
- assign d_o[15] = (syndrome_o == 6'h26) ^ d_i[15];
+ assign d_o[0] = (syndrome_o == 6'h16) ^ d_i[0];
+ assign d_o[1] = (syndrome_o == 6'h1a) ^ d_i[1];
+ assign d_o[2] = (syndrome_o == 6'h34) ^ d_i[2];
+ assign d_o[3] = (syndrome_o == 6'h7) ^ d_i[3];
+ assign d_o[4] = (syndrome_o == 6'h2c) ^ d_i[4];
+ assign d_o[5] = (syndrome_o == 6'h26) ^ d_i[5];
+ assign d_o[6] = (syndrome_o == 6'h31) ^ d_i[6];
+ assign d_o[7] = (syndrome_o == 6'h2a) ^ d_i[7];
+ assign d_o[8] = (syndrome_o == 6'h13) ^ d_i[8];
+ assign d_o[9] = (syndrome_o == 6'hd) ^ d_i[9];
+ assign d_o[10] = (syndrome_o == 6'h1c) ^ d_i[10];
+ assign d_o[11] = (syndrome_o == 6'h25) ^ d_i[11];
+ assign d_o[12] = (syndrome_o == 6'hb) ^ d_i[12];
+ assign d_o[13] = (syndrome_o == 6'h19) ^ d_i[13];
+ assign d_o[14] = (syndrome_o == 6'h29) ^ d_i[14];
+ assign d_o[15] = (syndrome_o == 6'h32) ^ d_i[15];
assign d_o[16] = (syndrome_o == 6'h1) ^ d_i[16];
assign d_o[17] = (syndrome_o == 6'h2) ^ d_i[17];
assign d_o[18] = (syndrome_o == 6'h4) ^ d_i[18];
diff --git a/rtl/lowrisc_ecc/prim_secded_28_22_cor.sv b/rtl/lowrisc_ecc/prim_secded_28_22_cor.sv
index d279c716..12908105 100644
--- a/rtl/lowrisc_ecc/prim_secded_28_22_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_28_22_cor.sv
@@ -16,11 +16,11 @@ module prim_secded_28_22_cor (
// Syndrome calculation
assign syndrome_o[0] = ^(d_i & 28'h07003FF);
- assign syndrome_o[1] = ^(d_i & 28'h0B0FC0F);
- assign syndrome_o[2] = ^(d_i & 28'h1371C71);
+ assign syndrome_o[1] = ^(d_i & 28'h0A0FC0F);
+ assign syndrome_o[2] = ^(d_i & 28'h1171C71);
assign syndrome_o[3] = ^(d_i & 28'h23B6592);
- assign syndrome_o[4] = ^(d_i & 28'h41DAAA4);
- assign syndrome_o[5] = ^(d_i & 28'h82ED348);
+ assign syndrome_o[4] = ^(d_i & 28'h43DAAA4);
+ assign syndrome_o[5] = ^(d_i & 28'h83ED348);
// Corrected output calculation
assign d_o[0] = (syndrome_o == 6'h7) ^ d_i[0];
@@ -43,8 +43,8 @@ module prim_secded_28_22_cor (
assign d_o[17] = (syndrome_o == 6'h2c) ^ d_i[17];
assign d_o[18] = (syndrome_o == 6'h34) ^ d_i[18];
assign d_o[19] = (syndrome_o == 6'h38) ^ d_i[19];
- assign d_o[20] = (syndrome_o == 6'h1f) ^ d_i[20];
- assign d_o[21] = (syndrome_o == 6'h2f) ^ d_i[21];
+ assign d_o[20] = (syndrome_o == 6'h3d) ^ d_i[20];
+ assign d_o[21] = (syndrome_o == 6'h3b) ^ d_i[21];
assign d_o[22] = (syndrome_o == 6'h1) ^ d_i[22];
assign d_o[23] = (syndrome_o == 6'h2) ^ d_i[23];
assign d_o[24] = (syndrome_o == 6'h4) ^ d_i[24];
diff --git a/rtl/lowrisc_ecc/prim_secded_39_32_cor.sv b/rtl/lowrisc_ecc/prim_secded_39_32_cor.sv
index 40e6b005..725b8b61 100644
--- a/rtl/lowrisc_ecc/prim_secded_39_32_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_39_32_cor.sv
@@ -15,47 +15,47 @@ module prim_secded_39_32_cor (
logic single_error;
// Syndrome calculation
- assign syndrome_o[0] = ^(d_i & 39'h012CA53295);
- assign syndrome_o[1] = ^(d_i & 39'h0293492CA5);
- assign syndrome_o[2] = ^(d_i & 39'h04552A5329);
- assign syndrome_o[3] = ^(d_i & 39'h08A8D294AA);
- assign syndrome_o[4] = ^(d_i & 39'h104A2CA54A);
- assign syndrome_o[5] = ^(d_i & 39'h2025534952);
- assign syndrome_o[6] = ^(d_i & 39'h40D294CA54);
+ assign syndrome_o[0] = ^(d_i & 39'h013800CDBC);
+ assign syndrome_o[1] = ^(d_i & 39'h02C439C325);
+ assign syndrome_o[2] = ^(d_i & 39'h0452D82C63);
+ assign syndrome_o[3] = ^(d_i & 39'h08A4363856);
+ assign syndrome_o[4] = ^(d_i & 39'h109B833109);
+ assign syndrome_o[5] = ^(d_i & 39'h202DCF42C0);
+ assign syndrome_o[6] = ^(d_i & 39'h404364969A);
// Corrected output calculation
- assign d_o[0] = (syndrome_o == 7'h7) ^ d_i[0];
- assign d_o[1] = (syndrome_o == 7'h38) ^ d_i[1];
- assign d_o[2] = (syndrome_o == 7'h43) ^ d_i[2];
- assign d_o[3] = (syndrome_o == 7'h1c) ^ d_i[3];
- assign d_o[4] = (syndrome_o == 7'h61) ^ d_i[4];
- assign d_o[5] = (syndrome_o == 7'he) ^ d_i[5];
- assign d_o[6] = (syndrome_o == 7'h70) ^ d_i[6];
- assign d_o[7] = (syndrome_o == 7'hb) ^ d_i[7];
- assign d_o[8] = (syndrome_o == 7'h34) ^ d_i[8];
- assign d_o[9] = (syndrome_o == 7'h45) ^ d_i[9];
- assign d_o[10] = (syndrome_o == 7'h1a) ^ d_i[10];
- assign d_o[11] = (syndrome_o == 7'h62) ^ d_i[11];
- assign d_o[12] = (syndrome_o == 7'hd) ^ d_i[12];
- assign d_o[13] = (syndrome_o == 7'h13) ^ d_i[13];
- assign d_o[14] = (syndrome_o == 7'h64) ^ d_i[14];
- assign d_o[15] = (syndrome_o == 7'h58) ^ d_i[15];
- assign d_o[16] = (syndrome_o == 7'h23) ^ d_i[16];
- assign d_o[17] = (syndrome_o == 7'h2c) ^ d_i[17];
- assign d_o[18] = (syndrome_o == 7'h51) ^ d_i[18];
- assign d_o[19] = (syndrome_o == 7'h16) ^ d_i[19];
- assign d_o[20] = (syndrome_o == 7'h68) ^ d_i[20];
- assign d_o[21] = (syndrome_o == 7'h15) ^ d_i[21];
- assign d_o[22] = (syndrome_o == 7'h2a) ^ d_i[22];
- assign d_o[23] = (syndrome_o == 7'h49) ^ d_i[23];
- assign d_o[24] = (syndrome_o == 7'h26) ^ d_i[24];
- assign d_o[25] = (syndrome_o == 7'h52) ^ d_i[25];
- assign d_o[26] = (syndrome_o == 7'h25) ^ d_i[26];
- assign d_o[27] = (syndrome_o == 7'h19) ^ d_i[27];
- assign d_o[28] = (syndrome_o == 7'h46) ^ d_i[28];
+ assign d_o[0] = (syndrome_o == 7'h16) ^ d_i[0];
+ assign d_o[1] = (syndrome_o == 7'h4c) ^ d_i[1];
+ assign d_o[2] = (syndrome_o == 7'hb) ^ d_i[2];
+ assign d_o[3] = (syndrome_o == 7'h51) ^ d_i[3];
+ assign d_o[4] = (syndrome_o == 7'h49) ^ d_i[4];
+ assign d_o[5] = (syndrome_o == 7'h7) ^ d_i[5];
+ assign d_o[6] = (syndrome_o == 7'h2c) ^ d_i[6];
+ assign d_o[7] = (syndrome_o == 7'h61) ^ d_i[7];
+ assign d_o[8] = (syndrome_o == 7'h13) ^ d_i[8];
+ assign d_o[9] = (syndrome_o == 7'h62) ^ d_i[9];
+ assign d_o[10] = (syndrome_o == 7'h45) ^ d_i[10];
+ assign d_o[11] = (syndrome_o == 7'hd) ^ d_i[11];
+ assign d_o[12] = (syndrome_o == 7'h58) ^ d_i[12];
+ assign d_o[13] = (syndrome_o == 7'h1c) ^ d_i[13];
+ assign d_o[14] = (syndrome_o == 7'h23) ^ d_i[14];
+ assign d_o[15] = (syndrome_o == 7'h43) ^ d_i[15];
+ assign d_o[16] = (syndrome_o == 7'h32) ^ d_i[16];
+ assign d_o[17] = (syndrome_o == 7'h38) ^ d_i[17];
+ assign d_o[18] = (syndrome_o == 7'h68) ^ d_i[18];
+ assign d_o[19] = (syndrome_o == 7'h26) ^ d_i[19];
+ assign d_o[20] = (syndrome_o == 7'he) ^ d_i[20];
+ assign d_o[21] = (syndrome_o == 7'h4a) ^ d_i[21];
+ assign d_o[22] = (syndrome_o == 7'h64) ^ d_i[22];
+ assign d_o[23] = (syndrome_o == 7'h34) ^ d_i[23];
+ assign d_o[24] = (syndrome_o == 7'h70) ^ d_i[24];
+ assign d_o[25] = (syndrome_o == 7'h54) ^ d_i[25];
+ assign d_o[26] = (syndrome_o == 7'h2a) ^ d_i[26];
+ assign d_o[27] = (syndrome_o == 7'h31) ^ d_i[27];
+ assign d_o[28] = (syndrome_o == 7'h15) ^ d_i[28];
assign d_o[29] = (syndrome_o == 7'h29) ^ d_i[29];
- assign d_o[30] = (syndrome_o == 7'h54) ^ d_i[30];
- assign d_o[31] = (syndrome_o == 7'h4a) ^ d_i[31];
+ assign d_o[30] = (syndrome_o == 7'h46) ^ d_i[30];
+ assign d_o[31] = (syndrome_o == 7'h1a) ^ d_i[31];
assign d_o[32] = (syndrome_o == 7'h1) ^ d_i[32];
assign d_o[33] = (syndrome_o == 7'h2) ^ d_i[33];
assign d_o[34] = (syndrome_o == 7'h4) ^ d_i[34];
diff --git a/rtl/lowrisc_ecc/prim_secded_72_64_cor.sv b/rtl/lowrisc_ecc/prim_secded_72_64_cor.sv
index c1a8d3ea..72c85cf4 100644
--- a/rtl/lowrisc_ecc/prim_secded_72_64_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_72_64_cor.sv
@@ -15,14 +15,14 @@ module prim_secded_72_64_cor (
logic single_error;
// Syndrome calculation
- assign syndrome_o[0] = ^(d_i & 72'h015B000000001FFFFF);
- assign syndrome_o[1] = ^(d_i & 72'h026B00000FFFE0003F);
- assign syndrome_o[2] = ^(d_i & 72'h046D003FF003E007C1);
- assign syndrome_o[3] = ^(d_i & 72'h08AD0FC0F03C207842);
- assign syndrome_o[4] = ^(d_i & 72'h10B571C711C4438884);
- assign syndrome_o[5] = ^(d_i & 72'h20B6B65926488C9108);
- assign syndrome_o[6] = ^(d_i & 72'h40D6DAAA4A91152210);
- assign syndrome_o[7] = ^(d_i & 72'h80DAED348D221A4420);
+ assign syndrome_o[0] = ^(d_i & 72'h01F8000000001FFFFF);
+ assign syndrome_o[1] = ^(d_i & 72'h029D00000FFFE0003F);
+ assign syndrome_o[2] = ^(d_i & 72'h048F003FF003E007C1);
+ assign syndrome_o[3] = ^(d_i & 72'h08F10FC0F03C207842);
+ assign syndrome_o[4] = ^(d_i & 72'h106E71C711C4438884);
+ assign syndrome_o[5] = ^(d_i & 72'h203EB65926488C9108);
+ assign syndrome_o[6] = ^(d_i & 72'h40D3DAAA4A91152210);
+ assign syndrome_o[7] = ^(d_i & 72'h8067ED348D221A4420);
// Corrected output calculation
assign d_o[0] = (syndrome_o == 8'h7) ^ d_i[0];
@@ -81,14 +81,14 @@ module prim_secded_72_64_cor (
assign d_o[53] = (syndrome_o == 8'hb0) ^ d_i[53];
assign d_o[54] = (syndrome_o == 8'hd0) ^ d_i[54];
assign d_o[55] = (syndrome_o == 8'he0) ^ d_i[55];
- assign d_o[56] = (syndrome_o == 8'h1f) ^ d_i[56];
- assign d_o[57] = (syndrome_o == 8'he3) ^ d_i[57];
- assign d_o[58] = (syndrome_o == 8'h7c) ^ d_i[58];
- assign d_o[59] = (syndrome_o == 8'h8f) ^ d_i[59];
- assign d_o[60] = (syndrome_o == 8'hf1) ^ d_i[60];
- assign d_o[61] = (syndrome_o == 8'h3e) ^ d_i[61];
- assign d_o[62] = (syndrome_o == 8'hc7) ^ d_i[62];
- assign d_o[63] = (syndrome_o == 8'hf8) ^ d_i[63];
+ assign d_o[56] = (syndrome_o == 8'hce) ^ d_i[56];
+ assign d_o[57] = (syndrome_o == 8'hf4) ^ d_i[57];
+ assign d_o[58] = (syndrome_o == 8'hb6) ^ d_i[58];
+ assign d_o[59] = (syndrome_o == 8'h37) ^ d_i[59];
+ assign d_o[60] = (syndrome_o == 8'h6b) ^ d_i[60];
+ assign d_o[61] = (syndrome_o == 8'hb9) ^ d_i[61];
+ assign d_o[62] = (syndrome_o == 8'hd9) ^ d_i[62];
+ assign d_o[63] = (syndrome_o == 8'h4f) ^ d_i[63];
assign d_o[64] = (syndrome_o == 8'h1) ^ d_i[64];
assign d_o[65] = (syndrome_o == 8'h2) ^ d_i[65];
assign d_o[66] = (syndrome_o == 8'h4) ^ d_i[66];
diff --git a/rtl/lowrisc_ecc/prim_secded_hamming_22_16_cor.sv b/rtl/lowrisc_ecc/prim_secded_hamming_22_16_cor.sv
index 249a9e7f..e9f47371 100644
--- a/rtl/lowrisc_ecc/prim_secded_hamming_22_16_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_hamming_22_16_cor.sv
@@ -19,25 +19,25 @@ module prim_secded_hamming_22_16_cor (
assign syndrome_o[2] = ^(d_i & 22'h04C78E);
assign syndrome_o[3] = ^(d_i & 22'h0807F0);
assign syndrome_o[4] = ^(d_i & 22'h10F800);
- assign syndrome_o[5] = ^(d_i & 22'h205CB7);
+ assign syndrome_o[5] = ^(d_i & 22'h3FFFFF);
// Corrected output calculation
assign d_o[0] = (syndrome_o == 6'h23) ^ d_i[0];
assign d_o[1] = (syndrome_o == 6'h25) ^ d_i[1];
assign d_o[2] = (syndrome_o == 6'h26) ^ d_i[2];
- assign d_o[3] = (syndrome_o == 6'h7) ^ d_i[3];
+ assign d_o[3] = (syndrome_o == 6'h27) ^ d_i[3];
assign d_o[4] = (syndrome_o == 6'h29) ^ d_i[4];
assign d_o[5] = (syndrome_o == 6'h2a) ^ d_i[5];
- assign d_o[6] = (syndrome_o == 6'hb) ^ d_i[6];
+ assign d_o[6] = (syndrome_o == 6'h2b) ^ d_i[6];
assign d_o[7] = (syndrome_o == 6'h2c) ^ d_i[7];
- assign d_o[8] = (syndrome_o == 6'hd) ^ d_i[8];
- assign d_o[9] = (syndrome_o == 6'he) ^ d_i[9];
+ assign d_o[8] = (syndrome_o == 6'h2d) ^ d_i[8];
+ assign d_o[9] = (syndrome_o == 6'h2e) ^ d_i[9];
assign d_o[10] = (syndrome_o == 6'h2f) ^ d_i[10];
assign d_o[11] = (syndrome_o == 6'h31) ^ d_i[11];
assign d_o[12] = (syndrome_o == 6'h32) ^ d_i[12];
- assign d_o[13] = (syndrome_o == 6'h13) ^ d_i[13];
+ assign d_o[13] = (syndrome_o == 6'h33) ^ d_i[13];
assign d_o[14] = (syndrome_o == 6'h34) ^ d_i[14];
- assign d_o[15] = (syndrome_o == 6'h15) ^ d_i[15];
+ assign d_o[15] = (syndrome_o == 6'h35) ^ d_i[15];
assign d_o[16] = (syndrome_o == 6'h1) ^ d_i[16];
assign d_o[17] = (syndrome_o == 6'h2) ^ d_i[17];
assign d_o[18] = (syndrome_o == 6'h4) ^ d_i[18];
diff --git a/rtl/lowrisc_ecc/prim_secded_hamming_39_32_cor.sv b/rtl/lowrisc_ecc/prim_secded_hamming_39_32_cor.sv
index c861663c..2918c058 100644
--- a/rtl/lowrisc_ecc/prim_secded_hamming_39_32_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_hamming_39_32_cor.sv
@@ -20,41 +20,41 @@ module prim_secded_hamming_39_32_cor (
assign syndrome_o[3] = ^(d_i & 39'h0803FC07F0);
assign syndrome_o[4] = ^(d_i & 39'h1003FFF800);
assign syndrome_o[5] = ^(d_i & 39'h20FC000000);
- assign syndrome_o[6] = ^(d_i & 39'h402DA65CB7);
+ assign syndrome_o[6] = ^(d_i & 39'h7FFFFFFFFF);
// Corrected output calculation
assign d_o[0] = (syndrome_o == 7'h43) ^ d_i[0];
assign d_o[1] = (syndrome_o == 7'h45) ^ d_i[1];
assign d_o[2] = (syndrome_o == 7'h46) ^ d_i[2];
- assign d_o[3] = (syndrome_o == 7'h7) ^ d_i[3];
+ assign d_o[3] = (syndrome_o == 7'h47) ^ d_i[3];
assign d_o[4] = (syndrome_o == 7'h49) ^ d_i[4];
assign d_o[5] = (syndrome_o == 7'h4a) ^ d_i[5];
- assign d_o[6] = (syndrome_o == 7'hb) ^ d_i[6];
+ assign d_o[6] = (syndrome_o == 7'h4b) ^ d_i[6];
assign d_o[7] = (syndrome_o == 7'h4c) ^ d_i[7];
- assign d_o[8] = (syndrome_o == 7'hd) ^ d_i[8];
- assign d_o[9] = (syndrome_o == 7'he) ^ d_i[9];
+ assign d_o[8] = (syndrome_o == 7'h4d) ^ d_i[8];
+ assign d_o[9] = (syndrome_o == 7'h4e) ^ d_i[9];
assign d_o[10] = (syndrome_o == 7'h4f) ^ d_i[10];
assign d_o[11] = (syndrome_o == 7'h51) ^ d_i[11];
assign d_o[12] = (syndrome_o == 7'h52) ^ d_i[12];
- assign d_o[13] = (syndrome_o == 7'h13) ^ d_i[13];
+ assign d_o[13] = (syndrome_o == 7'h53) ^ d_i[13];
assign d_o[14] = (syndrome_o == 7'h54) ^ d_i[14];
- assign d_o[15] = (syndrome_o == 7'h15) ^ d_i[15];
- assign d_o[16] = (syndrome_o == 7'h16) ^ d_i[16];
+ assign d_o[15] = (syndrome_o == 7'h55) ^ d_i[15];
+ assign d_o[16] = (syndrome_o == 7'h56) ^ d_i[16];
assign d_o[17] = (syndrome_o == 7'h57) ^ d_i[17];
assign d_o[18] = (syndrome_o == 7'h58) ^ d_i[18];
- assign d_o[19] = (syndrome_o == 7'h19) ^ d_i[19];
- assign d_o[20] = (syndrome_o == 7'h1a) ^ d_i[20];
+ assign d_o[19] = (syndrome_o == 7'h59) ^ d_i[19];
+ assign d_o[20] = (syndrome_o == 7'h5a) ^ d_i[20];
assign d_o[21] = (syndrome_o == 7'h5b) ^ d_i[21];
- assign d_o[22] = (syndrome_o == 7'h1c) ^ d_i[22];
+ assign d_o[22] = (syndrome_o == 7'h5c) ^ d_i[22];
assign d_o[23] = (syndrome_o == 7'h5d) ^ d_i[23];
assign d_o[24] = (syndrome_o == 7'h5e) ^ d_i[24];
- assign d_o[25] = (syndrome_o == 7'h1f) ^ d_i[25];
+ assign d_o[25] = (syndrome_o == 7'h5f) ^ d_i[25];
assign d_o[26] = (syndrome_o == 7'h61) ^ d_i[26];
assign d_o[27] = (syndrome_o == 7'h62) ^ d_i[27];
- assign d_o[28] = (syndrome_o == 7'h23) ^ d_i[28];
+ assign d_o[28] = (syndrome_o == 7'h63) ^ d_i[28];
assign d_o[29] = (syndrome_o == 7'h64) ^ d_i[29];
- assign d_o[30] = (syndrome_o == 7'h25) ^ d_i[30];
- assign d_o[31] = (syndrome_o == 7'h26) ^ d_i[31];
+ assign d_o[30] = (syndrome_o == 7'h65) ^ d_i[30];
+ assign d_o[31] = (syndrome_o == 7'h66) ^ d_i[31];
assign d_o[32] = (syndrome_o == 7'h1) ^ d_i[32];
assign d_o[33] = (syndrome_o == 7'h2) ^ d_i[33];
assign d_o[34] = (syndrome_o == 7'h4) ^ d_i[34];
diff --git a/rtl/lowrisc_ecc/prim_secded_hamming_72_64_cor.sv b/rtl/lowrisc_ecc/prim_secded_hamming_72_64_cor.sv
index 896f97ac..e8f2e854 100644
--- a/rtl/lowrisc_ecc/prim_secded_hamming_72_64_cor.sv
+++ b/rtl/lowrisc_ecc/prim_secded_hamming_72_64_cor.sv
@@ -21,72 +21,72 @@ module prim_secded_hamming_72_64_cor (
assign syndrome_o[4] = ^(d_i & 72'h1001FFFE0003FFF800);
assign syndrome_o[5] = ^(d_i & 72'h2001FFFFFFFC000000);
assign syndrome_o[6] = ^(d_i & 72'h40FE00000000000000);
- assign syndrome_o[7] = ^(d_i & 72'h80972CD2D32DA65CB7);
+ assign syndrome_o[7] = ^(d_i & 72'hFFFFFFFFFFFFFFFFFF);
// Corrected output calculation
assign d_o[0] = (syndrome_o == 8'h83) ^ d_i[0];
assign d_o[1] = (syndrome_o == 8'h85) ^ d_i[1];
assign d_o[2] = (syndrome_o == 8'h86) ^ d_i[2];
- assign d_o[3] = (syndrome_o == 8'h7) ^ d_i[3];
+ assign d_o[3] = (syndrome_o == 8'h87) ^ d_i[3];
assign d_o[4] = (syndrome_o == 8'h89) ^ d_i[4];
assign d_o[5] = (syndrome_o == 8'h8a) ^ d_i[5];
- assign d_o[6] = (syndrome_o == 8'hb) ^ d_i[6];
+ assign d_o[6] = (syndrome_o == 8'h8b) ^ d_i[6];
assign d_o[7] = (syndrome_o == 8'h8c) ^ d_i[7];
- assign d_o[8] = (syndrome_o == 8'hd) ^ d_i[8];
- assign d_o[9] = (syndrome_o == 8'he) ^ d_i[9];
+ assign d_o[8] = (syndrome_o == 8'h8d) ^ d_i[8];
+ assign d_o[9] = (syndrome_o == 8'h8e) ^ d_i[9];
assign d_o[10] = (syndrome_o == 8'h8f) ^ d_i[10];
assign d_o[11] = (syndrome_o == 8'h91) ^ d_i[11];
assign d_o[12] = (syndrome_o == 8'h92) ^ d_i[12];
- assign d_o[13] = (syndrome_o == 8'h13) ^ d_i[13];
+ assign d_o[13] = (syndrome_o == 8'h93) ^ d_i[13];
assign d_o[14] = (syndrome_o == 8'h94) ^ d_i[14];
- assign d_o[15] = (syndrome_o == 8'h15) ^ d_i[15];
- assign d_o[16] = (syndrome_o == 8'h16) ^ d_i[16];
+ assign d_o[15] = (syndrome_o == 8'h95) ^ d_i[15];
+ assign d_o[16] = (syndrome_o == 8'h96) ^ d_i[16];
assign d_o[17] = (syndrome_o == 8'h97) ^ d_i[17];
assign d_o[18] = (syndrome_o == 8'h98) ^ d_i[18];
- assign d_o[19] = (syndrome_o == 8'h19) ^ d_i[19];
- assign d_o[20] = (syndrome_o == 8'h1a) ^ d_i[20];
+ assign d_o[19] = (syndrome_o == 8'h99) ^ d_i[19];
+ assign d_o[20] = (syndrome_o == 8'h9a) ^ d_i[20];
assign d_o[21] = (syndrome_o == 8'h9b) ^ d_i[21];
- assign d_o[22] = (syndrome_o == 8'h1c) ^ d_i[22];
+ assign d_o[22] = (syndrome_o == 8'h9c) ^ d_i[22];
assign d_o[23] = (syndrome_o == 8'h9d) ^ d_i[23];
assign d_o[24] = (syndrome_o == 8'h9e) ^ d_i[24];
- assign d_o[25] = (syndrome_o == 8'h1f) ^ d_i[25];
+ assign d_o[25] = (syndrome_o == 8'h9f) ^ d_i[25];
assign d_o[26] = (syndrome_o == 8'ha1) ^ d_i[26];
assign d_o[27] = (syndrome_o == 8'ha2) ^ d_i[27];
- assign d_o[28] = (syndrome_o == 8'h23) ^ d_i[28];
+ assign d_o[28] = (syndrome_o == 8'ha3) ^ d_i[28];
assign d_o[29] = (syndrome_o == 8'ha4) ^ d_i[29];
- assign d_o[30] = (syndrome_o == 8'h25) ^ d_i[30];
- assign d_o[31] = (syndrome_o == 8'h26) ^ d_i[31];
+ assign d_o[30] = (syndrome_o == 8'ha5) ^ d_i[30];
+ assign d_o[31] = (syndrome_o == 8'ha6) ^ d_i[31];
assign d_o[32] = (syndrome_o == 8'ha7) ^ d_i[32];
assign d_o[33] = (syndrome_o == 8'ha8) ^ d_i[33];
- assign d_o[34] = (syndrome_o == 8'h29) ^ d_i[34];
- assign d_o[35] = (syndrome_o == 8'h2a) ^ d_i[35];
+ assign d_o[34] = (syndrome_o == 8'ha9) ^ d_i[34];
+ assign d_o[35] = (syndrome_o == 8'haa) ^ d_i[35];
assign d_o[36] = (syndrome_o == 8'hab) ^ d_i[36];
- assign d_o[37] = (syndrome_o == 8'h2c) ^ d_i[37];
+ assign d_o[37] = (syndrome_o == 8'hac) ^ d_i[37];
assign d_o[38] = (syndrome_o == 8'had) ^ d_i[38];
assign d_o[39] = (syndrome_o == 8'hae) ^ d_i[39];
- assign d_o[40] = (syndrome_o == 8'h2f) ^ d_i[40];
+ assign d_o[40] = (syndrome_o == 8'haf) ^ d_i[40];
assign d_o[41] = (syndrome_o == 8'hb0) ^ d_i[41];
- assign d_o[42] = (syndrome_o == 8'h31) ^ d_i[42];
- assign d_o[43] = (syndrome_o == 8'h32) ^ d_i[43];
+ assign d_o[42] = (syndrome_o == 8'hb1) ^ d_i[42];
+ assign d_o[43] = (syndrome_o == 8'hb2) ^ d_i[43];
assign d_o[44] = (syndrome_o == 8'hb3) ^ d_i[44];
- assign d_o[45] = (syndrome_o == 8'h34) ^ d_i[45];
+ assign d_o[45] = (syndrome_o == 8'hb4) ^ d_i[45];
assign d_o[46] = (syndrome_o == 8'hb5) ^ d_i[46];
assign d_o[47] = (syndrome_o == 8'hb6) ^ d_i[47];
- assign d_o[48] = (syndrome_o == 8'h37) ^ d_i[48];
- assign d_o[49] = (syndrome_o == 8'h38) ^ d_i[49];
+ assign d_o[48] = (syndrome_o == 8'hb7) ^ d_i[48];
+ assign d_o[49] = (syndrome_o == 8'hb8) ^ d_i[49];
assign d_o[50] = (syndrome_o == 8'hb9) ^ d_i[50];
assign d_o[51] = (syndrome_o == 8'hba) ^ d_i[51];
- assign d_o[52] = (syndrome_o == 8'h3b) ^ d_i[52];
+ assign d_o[52] = (syndrome_o == 8'hbb) ^ d_i[52];
assign d_o[53] = (syndrome_o == 8'hbc) ^ d_i[53];
- assign d_o[54] = (syndrome_o == 8'h3d) ^ d_i[54];
- assign d_o[55] = (syndrome_o == 8'h3e) ^ d_i[55];
+ assign d_o[54] = (syndrome_o == 8'hbd) ^ d_i[54];
+ assign d_o[55] = (syndrome_o == 8'hbe) ^ d_i[55];
assign d_o[56] = (syndrome_o == 8'hbf) ^ d_i[56];
assign d_o[57] = (syndrome_o == 8'hc1) ^ d_i[57];
assign d_o[58] = (syndrome_o == 8'hc2) ^ d_i[58];
- assign d_o[59] = (syndrome_o == 8'h43) ^ d_i[59];
+ assign d_o[59] = (syndrome_o == 8'hc3) ^ d_i[59];
assign d_o[60] = (syndrome_o == 8'hc4) ^ d_i[60];
- assign d_o[61] = (syndrome_o == 8'h45) ^ d_i[61];
- assign d_o[62] = (syndrome_o == 8'h46) ^ d_i[62];
+ assign d_o[61] = (syndrome_o == 8'hc5) ^ d_i[61];
+ assign d_o[62] = (syndrome_o == 8'hc6) ^ d_i[62];
assign d_o[63] = (syndrome_o == 8'hc7) ^ d_i[63];
assign d_o[64] = (syndrome_o == 8'h1) ^ d_i[64];
assign d_o[65] = (syndrome_o == 8'h2) ^ d_i[65];
diff --git a/test/tb_ecc_secded.sv b/test/tb_ecc_secded.sv
index 30793d65..a463b54e 100644
--- a/test/tb_ecc_secded.sv
+++ b/test/tb_ecc_secded.sv
@@ -193,49 +193,103 @@ module tb_ecc_secded #(
prot_t prot_out, prot_in, prot_corrected;
logic [1:0] error, error_corrector, error_correcter_decoder;
- hsiao_ecc_enc #(
- .DataWidth(DataWidth),
- .ProtWidth (ProtectBits),
- .PrintHsiao(1'b1)
- ) i_dut_encode (
- .in (in),
- .out(prot_out)
- );
-
- assign prot_in = prot_out ^ inject;
-
- hsiao_ecc_dec #(
- .DataWidth(DataWidth),
- .ProtWidth (ProtectBits),
- .PrintHsiao(1'b1)
- ) i_dut_decode (
- .in (prot_in),
- .out (out),
- .syndrome_o(syndrome),
- .err_o (error)
- );
-
- hsiao_ecc_cor #(
- .DataWidth(DataWidth),
- .ProtWidth (ProtectBits),
- .PrintHsiao(1'b1)
- ) i_dut_correct (
- .in (prot_in),
- .out (prot_corrected),
- .syndrome_o(syndrome_corrector),
- .err_o (error_corrector)
- );
-
- hsiao_ecc_dec #(
- .DataWidth(DataWidth),
- .ProtWidth (ProtectBits),
- .PrintHsiao(1'b1)
- ) i_dut_correct_decode (
- .in (prot_corrected),
- .out (out_corrected),
- .syndrome_o(syndrome_corrector_decoder),
- .err_o (error_correcter_decoder)
- );
+ if (DataWidth == 8) begin
+ prim_secded_13_8_enc i_dut_encode (
+ .in (in),
+ .out(prot_out)
+ );
+ assign prot_in = prot_out ^ inject;
+ prim_secded_13_8_dec i_dut_decode (
+ .in (prot_in),
+ .d_o (out),
+ .syndrome_o(syndrome),
+ .err_o (error)
+ );
+ prim_secded_13_8_cor i_dut_correct (
+ .d_i (prot_in),
+ .d_o (prot_corrected),
+ .syndrome_o(syndrome_corrector),
+ .err_o (error_corrector)
+ );
+ prim_secded_13_8_dec i_dut_correct_decode (
+ .in (prot_corrected),
+ .d_o (out_corrected),
+ .syndrome_o(syndrome_corrector_decoder),
+ .err_o (error_correcter_decoder)
+ );
+ end else if (DataWidth == 16) begin
+ prim_secded_22_16_enc i_dut_encode (
+ .in (in),
+ .out(prot_out)
+ );
+ assign prot_in = prot_out ^ inject;
+ prim_secded_22_16_dec i_dut_decode (
+ .in (prot_in),
+ .d_o (out),
+ .syndrome_o(syndrome),
+ .err_o (error)
+ );
+ prim_secded_22_16_cor i_dut_correct (
+ .d_i (prot_in),
+ .d_o (prot_corrected),
+ .syndrome_o(syndrome_corrector),
+ .err_o (error_corrector)
+ );
+ prim_secded_22_16_dec i_dut_correct_decode (
+ .in (prot_corrected),
+ .d_o (out_corrected),
+ .syndrome_o(syndrome_corrector_decoder),
+ .err_o (error_correcter_decoder)
+ );
+ end else if (DataWidth == 32) begin
+ prim_secded_39_32_enc i_dut_encode (
+ .in (in),
+ .out(prot_out)
+ );
+ assign prot_in = prot_out ^ inject;
+ prim_secded_39_32_dec i_dut_decode (
+ .in (prot_in),
+ .d_o (out),
+ .syndrome_o(syndrome),
+ .err_o (error)
+ );
+ prim_secded_39_32_cor i_dut_correct (
+ .d_i (prot_in),
+ .d_o (prot_corrected),
+ .syndrome_o(syndrome_corrector),
+ .err_o (error_corrector)
+ );
+ prim_secded_39_32_dec i_dut_correct_decode (
+ .in (prot_corrected),
+ .d_o (out_corrected),
+ .syndrome_o(syndrome_corrector_decoder),
+ .err_o (error_correcter_decoder)
+ );
+ end else if (DataWidth == 64) begin
+ prim_secded_72_64_enc i_dut_encode (
+ .in (in),
+ .out(prot_out)
+ );
+ assign prot_in = prot_out ^ inject;
+ prim_secded_72_64_dec i_dut_decode (
+ .in (prot_in),
+ .d_o (out),
+ .syndrome_o(syndrome),
+ .err_o (error)
+ );
+ prim_secded_72_64_cor i_dut_correct (
+ .d_i (prot_in),
+ .d_o (prot_corrected),
+ .syndrome_o(syndrome_corrector),
+ .err_o (error_corrector)
+ );
+ prim_secded_72_64_dec i_dut_correct_decode (
+ .in (prot_corrected),
+ .d_o (out_corrected),
+ .syndrome_o(syndrome_corrector_decoder),
+ .err_o (error_correcter_decoder)
+ );
+ end
/***********************
* Output collection *