From 216106fa40eec80a51ad19ed68f57c4d41472382 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 22 Dec 2022 15:56:58 +0100 Subject: [PATCH 01/72] HMR: Add initial wrapper structure HMR: Add ODRG & TCLS support HMR: add initial configuration regfile HMR: additional registers Add files, initial fixes Add registers for tmr, modify and connect config Clarify core interleaving with functions, fixes Clean up Changed HMR interface's core grouping parameters to localparam as they depend on other parameters. Removed dependency from red_mode_q in generate statements. Indentation :art: Having couples of cores with the same inputs and generating the same outputs. Integrated DMR Core Checker. Use functions for DMR core selection Reposition TMR registers and FSM Externalize TMR control from HMR Add DMR configuration registers HMR: Add C include files Fix signal assignment in TMR mode --- Bender.yml | 13 + Makefile | 17 + rtl/DMR_checker.sv | 34 ++ rtl/HMR/HMR_core_regs.hjson | 48 ++ rtl/HMR/HMR_dmr_regs.hjson | 52 ++ rtl/HMR/HMR_regs.hjson | 123 ++++ rtl/HMR/HMR_tmr_regs.hjson | 68 +++ rtl/HMR/HMR_wrap.sv | 949 +++++++++++++++++++++++++++++++ rtl/HMR/doc.html | 80 +++ rtl/HMR/doc.md | 312 ++++++++++ rtl/HMR/hmr_core.h | 25 + rtl/HMR/hmr_core_regs_reg_pkg.sv | 71 +++ rtl/HMR/hmr_core_regs_reg_top.sv | 267 +++++++++ rtl/HMR/hmr_dmr.h | 27 + rtl/HMR/hmr_dmr_regs_reg_pkg.sv | 80 +++ rtl/HMR/hmr_dmr_regs_reg_top.sv | 278 +++++++++ rtl/HMR/hmr_global.h | 56 ++ rtl/HMR/hmr_registers_reg_pkg.sv | 144 +++++ rtl/HMR/hmr_registers_reg_top.sv | 417 ++++++++++++++ rtl/HMR/hmr_tmr.h | 30 + rtl/HMR/hmr_tmr_ctrl.sv | 179 ++++++ rtl/HMR/hmr_tmr_regs_reg_pkg.sv | 108 ++++ rtl/HMR/hmr_tmr_regs_reg_top.sv | 378 ++++++++++++ 23 files changed, 3756 insertions(+) create mode 100644 rtl/DMR_checker.sv create mode 100644 rtl/HMR/HMR_core_regs.hjson create mode 100644 rtl/HMR/HMR_dmr_regs.hjson create mode 100644 rtl/HMR/HMR_regs.hjson create mode 100644 rtl/HMR/HMR_tmr_regs.hjson create mode 100644 rtl/HMR/HMR_wrap.sv create mode 100644 rtl/HMR/doc.html create mode 100644 rtl/HMR/doc.md create mode 100644 rtl/HMR/hmr_core.h create mode 100644 rtl/HMR/hmr_core_regs_reg_pkg.sv create mode 100644 rtl/HMR/hmr_core_regs_reg_top.sv create mode 100644 rtl/HMR/hmr_dmr.h create mode 100644 rtl/HMR/hmr_dmr_regs_reg_pkg.sv create mode 100644 rtl/HMR/hmr_dmr_regs_reg_top.sv create mode 100644 rtl/HMR/hmr_global.h create mode 100644 rtl/HMR/hmr_registers_reg_pkg.sv create mode 100644 rtl/HMR/hmr_registers_reg_top.sv create mode 100644 rtl/HMR/hmr_tmr.h create mode 100644 rtl/HMR/hmr_tmr_ctrl.sv create mode 100644 rtl/HMR/hmr_tmr_regs_reg_pkg.sv create mode 100644 rtl/HMR/hmr_tmr_regs_reg_top.sv diff --git a/Bender.yml b/Bender.yml index 14bfe737..8a79ec13 100644 --- a/Bender.yml +++ b/Bender.yml @@ -24,6 +24,7 @@ sources: - rtl/hsiao_ecc/hsiao_ecc_cor.sv - rtl/TMR_voter.sv - rtl/TMR_word_voter.sv + - rtl/DMR_checker.sv # Level 1 - rtl/ODRG_unit/odrg_manager_reg_top.sv - rtl/ecc_wrap/ecc_manager_reg_top.sv @@ -92,6 +93,18 @@ sources: - test/tb_tmr_word_voter.sv - test/tb_bitwise_tmr_voter.sv + - files: + - 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_tmr_regs_reg_top.sv + - rtl/HMR/hmr_tmr_ctrl.sv + - rtl/HMR/HMR_wrap.sv + vendor_package: - name: lowrisc_opentitan target_dir: "util/lowrisc_opentitan" diff --git a/Makefile b/Makefile index 64af21f9..97df330e 100644 --- a/Makefile +++ b/Makefile @@ -22,10 +22,15 @@ 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 .PHONY: gen_ODRG gen_TCLS gen_ecc_registers gen_ECC @@ -39,6 +44,18 @@ 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) -D > $(TARGET_DIR_HMR)/hmr_global.h + 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_core) -D > $(TARGET_DIR_HMR)/hmr_core.h + python $(REG_TOOL) $(HJSON_HMR_dmr) -t $(TARGET_DIR_HMR) -r + python $(REG_TOOL) $(HJSON_HMR_dmr) -D > $(TARGET_DIR_HMR)/hmr_dmr.h + python $(REG_TOOL) $(HJSON_HMR_tmr) -t $(TARGET_DIR_HMR) -r + python $(REG_TOOL) $(HJSON_HMR_tmr) -D > $(TARGET_DIR_HMR)/hmr_tmr.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/DMR_checker.sv b/rtl/DMR_checker.sv new file mode 100644 index 00000000..21842bdb --- /dev/null +++ b/rtl/DMR_checker.sv @@ -0,0 +1,34 @@ +/* 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 int unsigned DataWidth = 41 +)( + input logic [DataWidth-1:0] inp_a_i, + input logic [DataWidth-1:0] inp_b_i, + output logic [DataWidth-1:0] check_o, + output logic error_o +); + +logic error; +logic [DataWidth-1:0] compare; + +assign compare = inp_a_i ^ inp_b_i; +assign error = |compare; +assign check_o = (!error) ? inp_a_i : '0; +assign error_o = error; + +endmodule : DMR_checker diff --git a/rtl/HMR/HMR_core_regs.hjson b/rtl/HMR/HMR_core_regs.hjson new file mode 100644 index 00000000..b37d5499 --- /dev/null +++ b/rtl/HMR/HMR_core_regs.hjson @@ -0,0 +1,48 @@ +{ 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" + } + ] + } + ] +} diff --git a/rtl/HMR/HMR_dmr_regs.hjson b/rtl/HMR/HMR_dmr_regs.hjson new file mode 100644 index 00000000..dcf54459 --- /dev/null +++ b/rtl/HMR/HMR_dmr_regs.hjson @@ -0,0 +1,52 @@ +{ + 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: "TMR_enable", + desc: "TMR configuration enable." + } + ] + }, + { name: "DMR_config", + desc: "DMR configuration bits." + swaccess: "rw", + hwaccess: "hrw", + hwqe: "true", + fields: [ + { bits: "0", + name: "todo", + desc: "TODO" + } + ] + }, + { 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..30b98a8c --- /dev/null +++ b/rtl/HMR/HMR_regs.hjson @@ -0,0 +1,123 @@ +{ + 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 32 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." + } + ] + }, + { 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", + # fields: [] + # }, + { 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: "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..ec01dad2 --- /dev/null +++ b/rtl/HMR/HMR_tmr_regs.hjson @@ -0,0 +1,68 @@ +{ + 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: "force_resynch", + resval: "0", + desc: "Forces a resynchronization routine" + } + ] + }, + { name: "sp_store", + desc: "Stack Pointer storage register", + swaccess: "rw", + hwaccess: "hrw", + hwqe: "true", + fields: [ + { bits: "31:0", + name: "SP", + desc: "Stack Pointer" + } + ] + } + ] +} diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv new file mode 100644 index 00000000..f6296558 --- /dev/null +++ b/rtl/HMR/HMR_wrap.sv @@ -0,0 +1,949 @@ +// 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 #( + // Wrapper parameters + parameter int unsigned NumCores = 0, + parameter bit DMRSupported = 1'b1, + parameter bit DMRFixed = 1'b0, + parameter bit TMRSupported = 1'b1, + parameter bit TMRFixed = 1'b0, + parameter bit SeparateData = 1'b1, + parameter bit BackupRegfile = 1'b0, + parameter bit InterleaveGrps = 1'b1, // alternative is sequential grouping + 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 + localparam int unsigned NumTMRGroups = NumCores/3, + localparam int unsigned NumTMRCores = NumTMRGroups * 3, + localparam int unsigned NumTMRLeftover = NumCores - NumTMRCores, + localparam int unsigned NumDMRGroups = NumCores/2, + localparam int unsigned NumDMRCores = NumDMRGroups * 2, + localparam int unsigned NumDMRLeftover = NumCores - NumDMRCores, + 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, + 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, + input logic [NumDMRGroups-1:0] dmr_cores_synch_i, + + // TODO other required signals + + // 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] core_setback_o , + + 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_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 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 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 + + 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 DataConcatWidth = 32 + 1 + DataWidth + BeWidth + UserWidth; + // data_add data_wen data_wdata data_be data_user + localparam int unsigned MainConcatWidth = SeparateData ? CtrlConcatWidth : + CtrlConcatWidth + DataConcatWidth; + + 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 [NumTMRGroups-1:0] dmr_failure, dmr_failure_main, dmr_failure_data; + logic [NumTMRGroups-1:0][2:0] dmr_error, dmr_error_main, dmr_error_data; + logic [NumTMRGroups-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; + + for (genvar i = 0; i < NumCores; i++) begin : gen_concat + if (SeparateData) begin + 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]}; + 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 + 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]}; + assign data_concat_in = '0; + end + end + + /*************************** + * HMR Control Registers * + ***************************/ + + logic [NumSysCores-1:0] core_en_as_master; + logic [NumSysCores-1:0] core_in_independent; + logic [NumSysCores-1:0] core_in_dmr; + logic [NumSysCores-1:0] core_in_tmr; + + for (genvar i = 0; i < NumSysCores; i++) begin + assign core_in_independent[i] = ~core_in_dmr[i] & ~core_in_tmr[i]; + assign core_in_dmr[i] = 1'b0; + 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]); + 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; + + always_comb begin + hmr_hw2reg.cores_en.d = '0; + hmr_hw2reg.cores_en.d = core_en_as_master; + end + + assign hmr_hw2reg.dmr_enable.d = '0; + assign hmr_hw2reg.tmr_enable.d = '0; + + 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; + + // Core Config Registers + + reg_req_t [NumCores-1:0] core_register_reqs; + reg_resp_t [NumCores-1:0] core_register_resps; + + // 2 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[3+$clog2(NumCores)-1:3] ), + .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; + assign dmr_incr_mismatches = '0; + + for (genvar i = 0; i < NumCores; i++) begin + 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]; + end + + logic [NumTMRGroups-1:0] tmr_setback_q; + logic [NumTMRGroups-1:0] tmr_grp_in_independent; + + + /********************************************************** + ******************** TMR Voters & Regs ******************* + **********************************************************/ + + if (TMRSupported || TMRFixed) begin : gen_tmr_logic + if (TMRFixed && NumCores % 3 != 0) $warning("Extra cores added not properly handled!"); + + hmr_tmr_regs_reg_pkg::hmr_tmr_regs_reg2hw_t [NumTMRGroups-1:0] tmr_reg2hw; + hmr_tmr_regs_reg_pkg::hmr_tmr_regs_hw2reg_t [NumTMRGroups-1:0] tmr_hw2reg; + + reg_req_t [NumTMRGroups-1:0] tmr_register_reqs; + reg_resp_t [NumTMRGroups-1:0] tmr_register_resps; + + 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 = 0; i < NumTMRCores; i++) begin : gen_core_in_tmr + assign core_in_tmr[i] = !tmr_grp_in_independent[tmr_group_id(i)]; + end + + for (genvar i = NumTMRCores; i < NumCores; i++) begin : gen_extra_core_assigns + assign tmr_incr_mismatches[i] = '0; + assign core_in_tmr[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) + ) 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 ), + .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] ), + .grp_in_independent_o ( tmr_grp_in_independent[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] ), + .fetch_en_i ( sys_fetch_en_i[tmr_core_id(i, 0)] ), + .cores_synch_i ( tmr_cores_synch_i[i] ) + ); + + assign tmr_failure[i] = tmr_data_req_out[i] ? + tmr_failure_main | tmr_failure_data : tmr_failure_main; + 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_main_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]} = 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]} = main_tmr_out[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 core_in_tmr = '0; + assign tmr_setback_q = '0; + end + + /************************************************************ + ******************** DMR Voters and Regs ******************* + ************************************************************/ + + if (DMRSupported || DMRFixed) begin: gen_dmr_checkers + for (genvar i = 0; i < NumDMRGroups; i++) begin + assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main | dmr_failure_data) + : dmr_failure_main; + assign dmr_error [i*2+:2] = dmr_data_req_out [i] ? (dmr_error_main [i*2+:2] | dmr_error_data [i*2+:2]) + : tmr_error_main [i*2+:2]; + assign dmr_single_mismatch [i] = dmr_error [i*2+:2] != 3'b000; + + 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] } + = 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_error_data[i] = 3'b000; + 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]} + = main_dmr_out[i]; + end + end + if (NumDMRLeftover > 0) begin : gen_dmr_leftover_error + assign dmr_error_main[NumCores-1-:NumDMRLeftover] = '0; + assign dmr_error_data[NumCores-1-:NumDMRLeftover] = '0; + assign dmr_error [NumCores-1-:NumDMRLeftover] = '0; + end + end else begin: no_dmr_checkers // block: gen_dmr_checkers + assign dmr_error_main = '0; + assign dmr_error_data = '0; + assign dmr_error = '0; + assign dmr_failure_main = '0; + assign dmr_failure_data = '0; + assign dmr_failure = '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; + 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!"); + + // TODO + + 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 + if (i < NumTMRCores && (TMRFixed || core_in_tmr[i])) begin : tmr_mode + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + + // 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]; + + core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex]; + 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] = sys_instr_gnt_i [SysCoreIndex]; + core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[SysCoreIndex]; + core_instr_r_valid_o[i] = sys_instr_r_valid_i[SysCoreIndex]; + core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; + + // DATA + core_data_gnt_o [i] = sys_data_gnt_i [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] = sys_data_r_valid_i [SysCoreIndex]; + core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; + + end else begin : independent_mode + core_setback_o [i] = '0; + + // 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] = sys_instr_gnt_i [i]; + core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; + core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; + core_instr_err_o [i] = sys_instr_err_i [i]; + + // DATA + core_data_gnt_o [i] = sys_data_gnt_i [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] = sys_data_r_valid_i [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] = core_irq_ack_i [CoreCoreIndex]; + assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[CoreCoreIndex]; + + // INSTR + assign sys_instr_req_o [i] = core_instr_req_i [CoreCoreIndex]; + assign sys_instr_addr_o [i] = core_instr_addr_i[CoreCoreIndex]; + + // DATA + assign sys_data_req_o [i] = core_data_req_i [CoreCoreIndex]; + assign sys_data_add_o [i] = core_data_add_i [CoreCoreIndex]; + assign sys_data_wen_o [i] = core_data_wen_i [CoreCoreIndex]; + assign sys_data_wdata_o [i] = core_data_wdata_i[CoreCoreIndex]; + assign sys_data_user_o [i] = core_data_user_i [CoreCoreIndex]; + assign sys_data_be_o [i] = core_data_be_i [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 sys_instr_req_o [i] = core_instr_req_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_instr_addr_o [i] = core_instr_addr_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + + // DATA + assign sys_data_req_o [i] = core_data_req_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_data_add_o [i] = core_data_add_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_data_wen_o [i] = core_data_wen_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_data_wdata_o [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 sys_data_be_o [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] = core_irq_ack_i [CoreCoreIndex]; + sys_irq_ack_id_o [i] = core_irq_ack_id_i[CoreCoreIndex]; + + // INSTR + sys_instr_req_o [i] = core_instr_req_i [CoreCoreIndex]; + sys_instr_addr_o [i] = core_instr_addr_i[CoreCoreIndex]; + + // DATA + sys_data_req_o [i] = core_data_req_i [CoreCoreIndex]; + sys_data_add_o [i] = core_data_add_i [CoreCoreIndex]; + sys_data_wen_o [i] = core_data_wen_i [CoreCoreIndex]; + sys_data_wdata_o [i] = core_data_wdata_i[CoreCoreIndex]; + sys_data_user_o [i] = core_data_user_i [CoreCoreIndex]; + sys_data_be_o [i] = core_data_be_i [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 + sys_instr_req_o [i] = '0; + sys_instr_addr_o [i] = '0; + + // DATA + sys_data_req_o [i] = '0; + sys_data_add_o [i] = '0; + sys_data_wen_o [i] = '0; + sys_data_wdata_o [i] = '0; + sys_data_user_o [i] = '0; + sys_data_be_o [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 + sys_instr_req_o [i] = core_instr_req_i [i]; + sys_instr_addr_o [i] = core_instr_addr_i[i]; + + // DATA + sys_data_req_o [i] = core_data_req_i [i]; + sys_data_add_o [i] = core_data_add_i [i]; + sys_data_wen_o [i] = core_data_wen_i [i]; + sys_data_wdata_o [i] = core_data_wdata_i[i]; + sys_data_user_o [i] = core_data_user_i [i]; + sys_data_be_o [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); + if (i < NumDMRCores && DMRFixed) begin : gen_dmr_mode + // CTRL + assign core_core_id_o [i] = sys_core_id_i [SysCoreIndex]; + assign core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex]; + + assign core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex]; + assign core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex]; + assign core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex]; + + assign core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex]; + assign core_perf_counters_o[i] = sys_perf_counters_i[SysCoreIndex]; + + // IRQ + assign core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex]; + assign core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; + + // INSTR + assign core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; + assign core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[SysCoreIndex]; + assign core_instr_r_valid_o[i] = sys_instr_r_valid_i[SysCoreIndex]; + assign core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; + + // DATA + assign core_data_gnt_o [i] = sys_data_gnt_i [SysCoreIndex]; + assign core_data_r_opc_o [i] = sys_data_r_opc_i [SysCoreIndex]; + assign core_data_r_rdata_o [i] = sys_data_r_rdata_i [SysCoreIndex]; + assign core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex]; + assign core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; + assign core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; + + end else begin : gen_independent_mode + + // CTRL + assign core_core_id_o [i] = sys_core_id_i [i]; + assign core_cluster_id_o [i] = sys_cluster_id_i [i]; + + assign core_clock_en_o [i] = sys_clock_en_i [i]; + assign core_fetch_en_o [i] = sys_fetch_en_i [i]; + assign core_boot_addr_o [i] = sys_boot_addr_i [i]; + + assign core_debug_req_o [i] = sys_debug_req_i [i]; + assign core_perf_counters_o[i] = sys_perf_counters_i[i]; + + // IRQ + assign core_irq_req_o [i] = sys_irq_req_i [i]; + assign core_irq_id_o [i] = sys_irq_id_i [i]; + + // INSTR + assign core_instr_gnt_o [i] = sys_instr_gnt_i [i]; + assign core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; + assign core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; + assign core_instr_err_o [i] = sys_instr_err_i [i]; + + // DATA + assign core_data_gnt_o [i] = sys_data_gnt_i [i]; + assign core_data_r_opc_o [i] = sys_data_r_opc_i [i]; + assign core_data_r_rdata_o [i] = sys_data_r_rdata_i [i]; + assign core_data_r_user_o [i] = sys_data_r_user_i [i]; + assign core_data_r_valid_o [i] = sys_data_r_valid_i [i]; + assign core_data_err_o [i] = sys_data_err_i [i]; + + end + end // gen_core_inputs + + for (genvar i = 0; i < NumSysCores; i++) begin : gen_core_outputs + localparam CoreCoreIndex = DMRFixed ? i : dmr_core_id(i, 0); + if ((DMRFixed && i < NumDMRGroups) || (i < NumDMRCores)) begin : gen_dmr_mode + if (DMRFixed || (InterleaveGrps && i < NumDMRGroups) || (!InterleaveGrps && i%2 == 0)) begin : gen_is_dmr + + // CTRL + assign sys_core_busy_o [i] = dmr_core_busy_out[CoreCoreIndex]; + + // IRQ + assign sys_irq_ack_o [i] = core_irq_ack_i [CoreCoreIndex]; + assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[CoreCoreIndex]; + + // INSTR + assign sys_instr_req_o [i] = core_instr_req_i [CoreCoreIndex]; + assign sys_instr_addr_o [i] = core_instr_addr_i[CoreCoreIndex]; + + // DATA + assign sys_data_req_o [i] = core_data_req_i [CoreCoreIndex]; + assign sys_data_add_o [i] = core_data_add_i [CoreCoreIndex]; + assign sys_data_wen_o [i] = core_data_wen_i [CoreCoreIndex]; + assign sys_data_wdata_o [i] = core_data_wdata_i[CoreCoreIndex]; + assign sys_data_user_o [i] = core_data_user_i [CoreCoreIndex]; + assign sys_data_be_o [i] = core_data_be_i [CoreCoreIndex]; + + end else begin : gen_disable_core // Assign disable + + // CTLR + assign sys_core_busy_o [i] = '0; + + // IRQ + assign sys_irq_ack_o [i] = '0; + assign sys_irq_ack_id_o [i] = '0; + + // INSTR + assign sys_instr_req_o [i] = '0; + assign sys_instr_addr_o [i] = '0; + + // DATA + assign sys_data_req_o [i] = '0; + assign sys_data_add_o [i] = '0; + assign sys_data_wen_o [i] = '0; + assign sys_data_wdata_o [i] = '0; + assign sys_data_user_o [i] = '0; + assign sys_data_be_o [i] = '0; + + end + end else begin : gen_independent_mode + // CTRL + assign sys_core_busy_o [i] = core_core_busy_i [i]; + + // IRQ + assign sys_irq_ack_o [i] = core_irq_ack_i [i]; + assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[i]; + + // INSTR + assign sys_instr_req_o [i] = core_instr_req_i [i]; + assign sys_instr_addr_o [i] = core_instr_addr_i[i]; + + // DATA + assign sys_data_req_o [i] = core_data_req_i [i]; + assign sys_data_add_o [i] = core_data_add_i [i]; + assign sys_data_wen_o [i] = core_data_wen_i [i]; + assign sys_data_wdata_o [i] = core_data_wdata_i[i]; + assign sys_data_user_o [i] = core_data_user_i [i]; + assign sys_data_be_o [i] = core_data_be_i [i]; + end + end // gen_core_outputs + + 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 sys_instr_req_o = core_instr_req_i; + assign core_instr_gnt_o = sys_instr_gnt_i; + assign sys_instr_addr_o = core_instr_addr_i; + assign core_instr_r_rdata_o = sys_instr_r_rdata_i; + assign core_instr_r_valid_o = sys_instr_r_valid_i; + assign core_instr_err_o = sys_instr_err_i; + + // DATA + assign sys_data_req_o = core_data_req_i; + assign sys_data_add_o = core_data_add_i; + assign sys_data_wen_o = core_data_wen_i; + assign sys_data_wdata_o = core_data_wdata_i; + assign sys_data_user_o = core_data_user_i; + assign sys_data_be_o = core_data_be_i; + assign core_data_gnt_o = sys_data_gnt_i; + 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 = sys_data_r_valid_i; + 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..ee0cb44f --- /dev/null +++ b/rtl/HMR/doc.html @@ -0,0 +1,80 @@ + + + + + +
+
HMR_registers.avail_config @ 0x0
+

Available Configurations from implemented hardware.

+
Reset default = 0x0, mask 0x7
+
+ + + + + +
31302928272625242322212019181716
 
1514131211109876543210
 tripledualindependent
BitsTypeResetNameDescription
0roxindependent

Independent mode is available.

1roxdual

Dual Modular Redundancy (DMR) is available.

2roxtriple

Triple Modular Redundancy (TMR) is available.

+
+ + + + + +
+
HMR_registers.cores_en @ 0x4
+

Enabled cores, based on the configuration. Can be used for barriers.

+
Reset default = 0x0, mask 0xfff
+
+ + + +
31302928272625242322212019181716
 
1514131211109876543210
 cores_en
BitsTypeResetNameDescription
11:0roxcores_en

Enabled cores.

+
+ + + + + +
+
HMR_registers.DMR_enable @ 0x8
+

DMR configuration enable, on bit per DMR group.

+
Reset default = 0x0, mask 0x3f
+
+ + + +
31302928272625242322212019181716
 
1514131211109876543210
 DMR_enable
BitsTypeResetNameDescription
5:0rw0x0DMR_enable

DMR configuration enable.

+
+ + + + + +
+
HMR_registers.TMR_enable @ 0xc
+

TMR configuration enable, one bit per TMR group.

+
Reset default = 0x0, mask 0xf
+
+ + + +
31302928272625242322212019181716
 
1514131211109876543210
 TMR_enable
BitsTypeResetNameDescription
3:0rw0x0TMR_enable

TMR configuration enable.

+
+ + + + + +
+
HMR_registers.TMR_config @ 0x10
+

TMR configuration bits.

+
Reset default = 0x6, mask 0xf
+
+ + + + + + +
31302928272625242322212019181716
 
1514131211109876543210
 force_resynchreload_setbacksetbackdelay_resynch
BitsTypeResetNameDescription
0rw0x0delay_resynch

Enable wait-for-restoration

1rw0x1setback

Enable setback (synchronous reset) during re-synch.

2rw0x1reload_setback

Enable setback on mismatch during reload section of re-synch (only possible with setback)

3rw0x0force_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.h b/rtl/HMR/hmr_core.h new file mode 100644 index 00000000..58d7d0c5 --- /dev/null +++ b/rtl/HMR/hmr_core.h @@ -0,0 +1,25 @@ +// 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 + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _HMR_CORE_REGS_REG_DEFS_ +// End generated register defines for HMR_core_regs \ No newline at end of file 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..b594350c --- /dev/null +++ b/rtl/HMR/hmr_core_regs_reg_pkg.sv @@ -0,0 +1,71 @@ +// 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 = 3; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + logic [31:0] q; + } hmr_core_regs_reg2hw_mismatches_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; // [31: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 = 3'h 0; + parameter logic [BlockAw-1:0] HMR_CORE_REGS_MISMATCHES_OFFSET = 3'h 4; + + // 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_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] HMR_CORE_REGS_PERMIT [2] = '{ + 4'b 0001, // index[0] HMR_CORE_REGS_CURRENT_MODE + 4'b 1111 // index[1] HMR_CORE_REGS_MISMATCHES + }; + +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..39e65762 --- /dev/null +++ b/rtl/HMR/hmr_core_regs_reg_top.sv @@ -0,0 +1,267 @@ +// 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 = 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_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; + + // 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) + ); + + + + + logic [1: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); + 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))))); + 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]; + + // 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 + + 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 = 3, + 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.h b/rtl/HMR/hmr_dmr.h new file mode 100644 index 00000000..a97a51bc --- /dev/null +++ b/rtl/HMR/hmr_dmr.h @@ -0,0 +1,27 @@ +// 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_TMR_ENABLE_BIT 0 + +// DMR configuration bits. +#define HMR_DMR_REGS_DMR_CONFIG_REG_OFFSET 0x4 +#define HMR_DMR_REGS_DMR_CONFIG_TODO_BIT 0 + +// 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 \ No newline at end of file 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..b568f175 --- /dev/null +++ b/rtl/HMR/hmr_dmr_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_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 { + logic q; + logic qe; + } 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 { + logic d; + logic de; + } 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; // [36:35] + hmr_dmr_regs_reg2hw_dmr_config_reg_t dmr_config; // [34: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; // [36:35] + hmr_dmr_regs_hw2reg_dmr_config_reg_t dmr_config; // [34: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..80722d6b --- /dev/null +++ b/rtl/HMR/hmr_dmr_regs_reg_top.sv @@ -0,0 +1,278 @@ +// 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_qs; + logic dmr_config_wd; + logic dmr_config_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) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_dmr_config ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (dmr_config_we), + .wd (dmr_config_wd), + + // from internal hardware + .de (hw2reg.dmr_config.de), + .d (hw2reg.dmr_config.d ), + + // to internal hardware + .qe (reg2hw.dmr_config.qe), + .q (reg2hw.dmr_config.q ), + + // to register interface (read) + .qs (dmr_config_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_we = addr_hit[1] & reg_we & !reg_error; + assign dmr_config_wd = reg_wdata[0]; + + 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_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_global.h b/rtl/HMR/hmr_global.h new file mode 100644 index 00000000..6a687f15 --- /dev/null +++ b/rtl/HMR/hmr_global.h @@ -0,0 +1,56 @@ +// 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 + +// 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 }) + +// TMR configuration bits. +#define HMR_REGISTERS_TMR_CONFIG_REG_OFFSET 0x10 +#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_FORCE_RESYNCH_BIT 3 + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _HMR_REGISTERS_REG_DEFS_ +// End generated register defines for HMR_registers \ No newline at end of file diff --git a/rtl/HMR/hmr_registers_reg_pkg.sv b/rtl/HMR/hmr_registers_reg_pkg.sv new file mode 100644 index 00000000..3858c81d --- /dev/null +++ b/rtl/HMR/hmr_registers_reg_pkg.sv @@ -0,0 +1,144 @@ +// 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; + } delay_resynch; + struct packed { + logic q; + logic qe; + } setback; + struct packed { + logic q; + logic qe; + } reload_setback; + 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; + } 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; + } delay_resynch; + struct packed { + logic d; + } setback; + struct packed { + logic d; + } reload_setback; + 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; // [19:13] + hmr_registers_reg2hw_tmr_enable_reg_t tmr_enable; // [12:8] + hmr_registers_reg2hw_tmr_config_reg_t tmr_config; // [7:0] + } hmr_registers_reg2hw_t; + + // HW -> register type + typedef struct packed { + hmr_registers_hw2reg_avail_config_reg_t avail_config; // [28:26] + hmr_registers_hw2reg_cores_en_reg_t cores_en; // [25:14] + hmr_registers_hw2reg_dmr_enable_reg_t dmr_enable; // [13:8] + hmr_registers_hw2reg_tmr_enable_reg_t tmr_enable; // [7:4] + hmr_registers_hw2reg_tmr_config_reg_t tmr_config; // [3: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_TMR_CONFIG_OFFSET = 5'h 10; + + // Reset values for hwext registers and their fields + parameter logic [2:0] HMR_REGISTERS_AVAIL_CONFIG_RESVAL = 3'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 [3:0] HMR_REGISTERS_TMR_CONFIG_RESVAL = 4'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_TMR_CONFIG + } hmr_registers_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] HMR_REGISTERS_PERMIT [5] = '{ + 4'b 0001, // 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_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..e2649082 --- /dev/null +++ b/rtl/HMR/hmr_registers_reg_top.sv @@ -0,0 +1,417 @@ +// 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 [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 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_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) + ); + + + // 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[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[force_resynch]: 3:3 + 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 [4: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_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))))); + 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 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 tmr_config_delay_resynch_we = addr_hit[4] & reg_we & !reg_error; + assign tmr_config_delay_resynch_wd = reg_wdata[0]; + assign tmr_config_delay_resynch_re = addr_hit[4] & reg_re & !reg_error; + + assign tmr_config_setback_we = addr_hit[4] & reg_we & !reg_error; + assign tmr_config_setback_wd = reg_wdata[1]; + assign tmr_config_setback_re = addr_hit[4] & reg_re & !reg_error; + + assign tmr_config_reload_setback_we = addr_hit[4] & reg_we & !reg_error; + assign tmr_config_reload_setback_wd = reg_wdata[2]; + assign tmr_config_reload_setback_re = addr_hit[4] & reg_re & !reg_error; + + assign tmr_config_force_resynch_we = addr_hit[4] & reg_we & !reg_error; + assign tmr_config_force_resynch_wd = reg_wdata[3]; + assign tmr_config_force_resynch_re = addr_hit[4] & 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; + 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] = 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_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.h b/rtl/HMR/hmr_tmr.h new file mode 100644 index 00000000..9751e30d --- /dev/null +++ b/rtl/HMR/hmr_tmr.h @@ -0,0 +1,30 @@ +// 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_FORCE_RESYNCH_BIT 3 + +// Stack Pointer storage register +#define HMR_TMR_REGS_SP_STORE_REG_OFFSET 0x8 + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _HMR_TMR_REGS_REG_DEFS_ +// End generated register defines for HMR_tmr_regs \ No newline at end of file diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv new file mode 100644 index 00000000..13055a3f --- /dev/null +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -0,0 +1,179 @@ +// 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 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 ctr 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 force_resynch_q_i, + input logic force_resynch_qe_i, + + // TMR control signals + output logic setback_o, + output logic grp_in_independent_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 fetch_en_i, + input logic cores_synch_i +); + + typedef enum logic [1:0] {NON_TMR, TMR_RUN, TMR_UNLOAD, TMR_RELOAD} 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; + logic tmr_setback_d, tmr_setback_q; + + assign setback_o = tmr_setback_q; + assign grp_in_independent_o = tmr_red_mode_q == NON_TMR; + + 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.force_resynch.d = force_resynch_qe_i ? force_resynch_q_i : 1'b0; + + /************************** + * FSM for TMR lockstep * + **************************/ + always_comb begin : proc_fsm + tmr_setback_d = 1'b0; + tmr_red_mode_d = tmr_red_mode_q; + tmr_incr_mismatches_o[0] = 1'b0; + tmr_incr_mismatches_o[1] = 1'b0; + tmr_incr_mismatches_o[2] = 1'b0; + + tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; + + // If forced execute resynchronization + if (tmr_red_mode_q == TMR_RUN && tmr_reg2hw.tmr_config.force_resynch.q) begin + tmr_hw2reg.tmr_config.force_resynch.de = 1'b1; + if (tmr_reg2hw.tmr_config.delay_resynch == 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_red_mode_q == TMR_RUN && tmr_single_mismatch_i) begin + $display("[ODRG] %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.delay_resynch == 0) begin + tmr_red_mode_d = TMR_UNLOAD; + // TODO: buffer the restoration until delay_resynch is disabled + end + end + + // If unload complete, go to reload (and reset) + if (tmr_red_mode_q == TMR_UNLOAD) begin + if (tmr_reg2hw.sp_store.q != '0) begin + tmr_red_mode_d = TMR_RELOAD; + if (tmr_reg2hw.tmr_config.setback.q) begin + tmr_setback_d = 1'b1; + end + end + end + + // If reload complete, finish (or reset if error happens during reload) + if (tmr_red_mode_q == TMR_RELOAD) begin + if (tmr_reg2hw.sp_store.q == '0) begin + $display("[ODRG] %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 && + !(tmr_reg2hw.sp_store.qe && reg_req_i.wdata == '0)) begin + tmr_setback_d = 1'b1; + end + end + end + + // Before core startup: set TMR mode from reg2hw.mode.mode + if (!TMRFixed) begin + 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; + end + end + // split single-error 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 + tmr_red_mode_d = NON_TMR; + end + end + // Set TMR mode on external signal that cores are synchronized + if (tmr_red_mode_q == NON_TMR && cores_synch_i) begin + if (tmr_reg2hw.tmr_enable.q == 1'b1) begin + tmr_red_mode_d = TMR_RUN; + 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; + tmr_setback_q <= '0; + end else begin + tmr_red_mode_q <= tmr_red_mode_d; + tmr_setback_q <= tmr_setback_d; + 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..0643b9c0 --- /dev/null +++ b/rtl/HMR/hmr_tmr_regs_reg_pkg.sv @@ -0,0 +1,108 @@ +// 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 = 4; + + //////////////////////////// + // 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; + } force_resynch; + } hmr_tmr_regs_reg2hw_tmr_config_reg_t; + + typedef struct packed { + logic [31:0] q; + logic qe; + } hmr_tmr_regs_reg2hw_sp_store_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; + } force_resynch; + } hmr_tmr_regs_hw2reg_tmr_config_reg_t; + + typedef struct packed { + logic [31:0] d; + logic de; + } hmr_tmr_regs_hw2reg_sp_store_reg_t; + + // Register -> HW type + typedef struct packed { + hmr_tmr_regs_reg2hw_tmr_enable_reg_t tmr_enable; // [42:41] + hmr_tmr_regs_reg2hw_tmr_config_reg_t tmr_config; // [40:33] + hmr_tmr_regs_reg2hw_sp_store_reg_t sp_store; // [32:0] + } hmr_tmr_regs_reg2hw_t; + + // HW -> register type + typedef struct packed { + hmr_tmr_regs_hw2reg_tmr_enable_reg_t tmr_enable; // [42:41] + hmr_tmr_regs_hw2reg_tmr_config_reg_t tmr_config; // [40:33] + hmr_tmr_regs_hw2reg_sp_store_reg_t sp_store; // [32:0] + } hmr_tmr_regs_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] HMR_TMR_REGS_TMR_ENABLE_OFFSET = 4'h 0; + parameter logic [BlockAw-1:0] HMR_TMR_REGS_TMR_CONFIG_OFFSET = 4'h 4; + parameter logic [BlockAw-1:0] HMR_TMR_REGS_SP_STORE_OFFSET = 4'h 8; + + // Register index + typedef enum int { + HMR_TMR_REGS_TMR_ENABLE, + HMR_TMR_REGS_TMR_CONFIG, + HMR_TMR_REGS_SP_STORE + } hmr_tmr_regs_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] HMR_TMR_REGS_PERMIT [3] = '{ + 4'b 0001, // index[0] HMR_TMR_REGS_TMR_ENABLE + 4'b 0001, // index[1] HMR_TMR_REGS_TMR_CONFIG + 4'b 1111 // index[2] HMR_TMR_REGS_SP_STORE + }; + +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..25879e1c --- /dev/null +++ b/rtl/HMR/hmr_tmr_regs_reg_top.sv @@ -0,0 +1,378 @@ +// 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 = 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_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_force_resynch_qs; + logic tmr_config_force_resynch_wd; + logic tmr_config_force_resynch_we; + logic [31:0] sp_store_qs; + logic [31:0] sp_store_wd; + logic sp_store_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[force_resynch]: 3:3 + 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) + ); + + + // 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 (hw2reg.sp_store.de), + .d (hw2reg.sp_store.d ), + + // 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_TMR_REGS_TMR_ENABLE_OFFSET); + addr_hit[1] = (reg_addr == HMR_TMR_REGS_TMR_CONFIG_OFFSET); + addr_hit[2] = (reg_addr == HMR_TMR_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_TMR_REGS_PERMIT[0] & ~reg_be))) | + (addr_hit[1] & (|(HMR_TMR_REGS_PERMIT[1] & ~reg_be))) | + (addr_hit[2] & (|(HMR_TMR_REGS_PERMIT[2] & ~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_force_resynch_we = addr_hit[1] & reg_we & !reg_error; + assign tmr_config_force_resynch_wd = reg_wdata[3]; + + 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] = 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_force_resynch_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_tmr_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_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 + + From 30c420c0a5096403e080fb28cc8c20f4481d6b08 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 8 May 2023 11:33:17 +0200 Subject: [PATCH 02/72] Integrated ECC-protected Recovery RF. Making clear that the internal Floating-Point memory decoder is actually for Floating-Points. Added functions for DMR grouping. Reverted grouping functions to previous implementations Recovery Routine quite complete for RF refill. Successfully rewriting cores' RF from backup copy. Resuming cores from debug mode during recovery routine. Reverted phase of instruction lock signal. Reverted core reset into synchronous setback for clear. Recovering cores' Program Counter during the Recovery Routine. Move recovery and DMR files to HMR Change debug_rsp to debug_halted Bind branch address read from Recovery PC to assertion of internal branch detection. Fixed PC backup. Remove intruder lock Making DMR address generator start from 0. --- Bender.yml | 27 ++- rtl/HMR/DMR_address_generator.sv | 71 +++++++ rtl/{ => HMR}/DMR_checker.sv | 0 rtl/HMR/DMR_controller.sv | 341 +++++++++++++++++++++++++++++++ rtl/HMR/HMR_wrap.sv | 294 +++++++++++++++++++++++--- rtl/HMR/recovery_pc.sv | 190 +++++++++++++++++ rtl/HMR/recovery_pkg.sv | 53 +++++ rtl/HMR/recovery_rf.sv | 257 +++++++++++++++++++++++ 8 files changed, 1189 insertions(+), 44 deletions(-) create mode 100644 rtl/HMR/DMR_address_generator.sv rename rtl/{ => HMR}/DMR_checker.sv (100%) create mode 100644 rtl/HMR/DMR_controller.sv create mode 100644 rtl/HMR/recovery_pc.sv create mode 100644 rtl/HMR/recovery_pkg.sv create mode 100644 rtl/HMR/recovery_rf.sv diff --git a/Bender.yml b/Bender.yml index 8a79ec13..341c3022 100644 --- a/Bender.yml +++ b/Bender.yml @@ -24,7 +24,6 @@ sources: - rtl/hsiao_ecc/hsiao_ecc_cor.sv - rtl/TMR_voter.sv - rtl/TMR_word_voter.sv - - rtl/DMR_checker.sv # Level 1 - rtl/ODRG_unit/odrg_manager_reg_top.sv - rtl/ecc_wrap/ecc_manager_reg_top.sv @@ -94,16 +93,22 @@ sources: - test/tb_bitwise_tmr_voter.sv - files: - - 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_tmr_regs_reg_top.sv - - rtl/HMR/hmr_tmr_ctrl.sv - - rtl/HMR/HMR_wrap.sv + - rtl/HMR/recovery_pkg.sv + - rtl/HMR/recovery_rf.sv + - rtl/HMR/recovery_pc.sv + - rtl/HMR/DMR_checker.sv + - rtl/HMR/DMR_address_generator.sv + - rtl/HMR/DMR_controller.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_tmr_regs_reg_top.sv + - rtl/HMR/hmr_tmr_ctrl.sv + - rtl/HMR/HMR_wrap.sv vendor_package: - name: lowrisc_opentitan diff --git a/rtl/HMR/DMR_address_generator.sv b/rtl/HMR/DMR_address_generator.sv new file mode 100644 index 00000000..12e4d41d --- /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] <= '0; + else begin + if (clear_i || addr_count_rst [i]) + addr_count [i] <= '0; + 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'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/DMR_checker.sv b/rtl/HMR/DMR_checker.sv similarity index 100% rename from rtl/DMR_checker.sv rename to rtl/HMR/DMR_checker.sv diff --git a/rtl/HMR/DMR_controller.sv b/rtl/HMR/DMR_controller.sv new file mode 100644 index 00000000..b0e1927c --- /dev/null +++ b/rtl/HMR/DMR_controller.sv @@ -0,0 +1,341 @@ +/* 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 + * + */ + +import recovery_pkg::*; + +module DMR_controller #( + parameter int unsigned NumCores = 0, + parameter bit DMRFixed = 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; + +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 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_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; + 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_wrap.sv b/rtl/HMR/HMR_wrap.sv index f6296558..eea74848 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -10,7 +10,7 @@ // // Hybrid modular redundancy wrapping unit -module HMR_wrap #( +module HMR_wrap import recovery_pkg::*; #( // Wrapper parameters parameter int unsigned NumCores = 0, parameter bit DMRSupported = 1'b1, @@ -53,8 +53,21 @@ module HMR_wrap #( 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_rf_readback_o, input logic [NumDMRGroups-1:0] dmr_cores_synch_i, + // 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_raddr_t [ NumSysCores-1:0] core_regfile_raddr_o, + output regfile_write_t [ NumSysCores-1:0] core_recovery_regfile_wport_o, // TODO other required signals // Ports connecting to System @@ -97,6 +110,7 @@ module HMR_wrap #( // Ports connecting to the cores output logic [ NumCores-1:0] core_setback_o , + output logic [ NumCores-1:0] core_recover_o , output logic [ NumCores-1:0][ 3:0] core_core_id_o , output logic [ NumCores-1:0][ 5:0] core_cluster_id_o , @@ -116,9 +130,12 @@ module HMR_wrap #( 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_lock_o , output logic [ NumCores-1:0] core_instr_err_o , output logic [ NumCores-1:0] core_debug_req_o , + output logic [ NumCores-1:0] core_debug_resume_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 , @@ -167,6 +184,8 @@ module HMR_wrap #( localparam int unsigned MainConcatWidth = 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; @@ -179,9 +198,9 @@ module HMR_wrap #( logic [NumTMRGroups-1:0][2:0] tmr_error, tmr_error_main, tmr_error_data; logic [NumTMRGroups-1:0] tmr_single_mismatch; - logic [NumTMRGroups-1:0] dmr_failure, dmr_failure_main, dmr_failure_data; - logic [NumTMRGroups-1:0][2:0] dmr_error, dmr_error_main, dmr_error_data; - logic [NumTMRGroups-1:0] dmr_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; @@ -207,6 +226,38 @@ module HMR_wrap #( 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][ 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 [NumDMRGroups-1:0] backup_branch_int, + recovery_branch_out, + backup_program_counter_error, + dmr_ctrl_pc_read_enable_out, + dmr_ctrl_pc_write_enable_out, + backup_regfile_we_a, + backup_regfile_we_b, + backup_regfile_error_a, + backup_regfile_error_b, + backup_branch_error, + backup_branch_addr_error, + regfile_readback_out, + dmr_ctrl_core_rstn_out, + dmr_ctrl_core_debug_req_out, + dmr_ctrl_core_debug_halted_in, + dmr_ctrl_core_instr_lock_out, + dmr_ctrl_core_setback_out, + dmr_ctrl_core_recover_out, + dmr_ctrl_debug_resume_out; + logic intruder_lock; + + regfile_raddr_t [NumDMRGroups-1:0] core_regfile_raddr_out; + regfile_rdata_t [NumDMRGroups-1:0] core_recovery_regfile_rdata_out; + regfile_write_t [NumDMRGroups-1:0] backup_regfile_wport_in, + core_recovery_regfile_wport_out; + for (genvar i = 0; i < NumCores; i++) begin : gen_concat if (SeparateData) begin assign main_concat_in[i] = {core_core_busy_i[i], core_irq_ack_i[i], core_irq_ack_id_i[i], @@ -492,8 +543,45 @@ module HMR_wrap #( /************************************************************ ******************** DMR Voters and Regs ******************* ************************************************************/ + for (genvar i = 0; i < NumCores; i++) begin + assign backup_regfile_wport_in [i] = backup_regfile_wport_i [dmr_core_id(dmr_group_id(i), 0)]; + end + + for (genvar i = 0; i < NumDMRGroups; i++) begin + assign dmr_ctrl_core_debug_halted_in [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 + + /****************** + * DMR Controller * + ******************/ + DMR_controller #( + .NumCores ( NumCores ), + .DMRFixed ( DMRFixed ), + .RFAddrWidth ( RFAddrWidth ) + ) dmr_controller ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .dmr_rf_checker_error_port_a_i ( backup_regfile_error_a ), + .dmr_rf_checker_error_port_b_i ( backup_regfile_error_b ), + .dmr_core_checker_error_main_i ( dmr_failure_main ), + .dmr_core_checker_error_data_i ( dmr_failure_data ), + .backup_regfile_write_i ( backup_regfile_wport_in ), + .core_recovery_regfile_wport_o ( core_recovery_regfile_wport_out ), + .regfile_readback_o ( regfile_readback_out ), + .regfile_raddr_o ( core_regfile_raddr_out ), + .dmr_ctrl_core_debug_req_o ( dmr_ctrl_core_debug_req_out ), + .dmr_ctrl_core_debug_rsp_i ( dmr_ctrl_core_debug_halted_in ), + .dmr_ctrl_core_instr_lock_o ( dmr_ctrl_core_instr_lock_out ), + .dmr_ctrl_core_setback_o ( dmr_ctrl_core_setback_out ), + .dmr_ctrl_core_recover_o ( dmr_ctrl_core_recover_out ), + .dmr_ctrl_core_debug_resume_o ( dmr_ctrl_debug_resume_out ), + .dmr_ctrl_pc_read_enable_o ( dmr_ctrl_pc_read_enable_out ), + .dmr_ctrl_pc_write_enable_o ( dmr_ctrl_pc_write_enable_out ), + .dmr_ctrl_core_clk_en_o ( ) + ); - if (DMRSupported || DMRFixed) begin: gen_dmr_checkers + if (DMRSupported || DMRFixed) begin: gen_dmr_recovery_region for (genvar i = 0; i < NumDMRGroups; i++) begin assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main | dmr_failure_data) : dmr_failure_main; @@ -501,22 +589,25 @@ module HMR_wrap #( : tmr_error_main [i*2+:2]; assign dmr_single_mismatch [i] = dmr_error [i*2+:2] != 3'b000; + /********************* + * 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]) + .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]) + .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] } @@ -533,13 +624,128 @@ module HMR_wrap #( dmr_data_be_out[i] , dmr_data_user_out[i]} = main_dmr_out[i]; end + + /****************** + * DMR PC Checker * + ******************/ + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_pc_checker ( + .inp_a_i ( backup_program_counter_i[dmr_core_id(i, 0)] ), + .inp_b_i ( backup_program_counter_i[dmr_core_id(i, 1)] ), + .check_o ( backup_program_counter_int [i] ), + .error_o ( backup_program_counter_error [i] ) + ); + + /********************* + * DMR Branch Checker * + **********************/ + DMR_checker # ( + .DataWidth ( 1 ) + ) dmr_branch_checker ( + .inp_a_i ( backup_branch_i[dmr_core_id(i, 0)] ), + .inp_b_i ( backup_branch_i[dmr_core_id(i, 1)] ), + .check_o ( backup_branch_int [i] ), + .error_o ( backup_branch_error [i] ) + ); + + /***************************** + * DMR Branch Address Checker * + ******************************/ + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_branch_addr_checker ( + .inp_a_i ( backup_branch_addr_i[dmr_core_id(i, 0)] ), + .inp_b_i ( backup_branch_addr_i[dmr_core_id(i, 1)] ), + .check_o ( backup_branch_addr_int [i] ), + .error_o ( backup_branch_addr_error [i] ) + ); + + /******************* + * DMR RF Checkers * + *******************/ + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_rf_checker_port_a ( + .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_a ), + .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_a ), + .check_o ( backup_regfile_wdata_a[i] ), + .error_o ( backup_regfile_error_a[i] ) + ); + + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_rf_checker_port_b ( + .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_b ), + .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_b ), + .check_o ( backup_regfile_wdata_b [i] ), + .error_o ( backup_regfile_error_b [i] ) + ); + + assign backup_regfile_we_a [i] = backup_regfile_wport_i[i].we_a + & ~backup_regfile_error_a [i] + & ~dmr_ctrl_core_recover_out [i]; + assign backup_regfile_we_b [i] = backup_regfile_wport_i[i].we_b + & ~backup_regfile_error_b [i] + & ~dmr_ctrl_core_recover_out [i]; + /**************************** + * Recovery Program Counter * + ****************************/ + recovery_pc #( + .ECCEnabled ( 1 ) + ) RPC ( + // Control Ports + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .clear_i ( '0 ), + .read_enable_i ( dmr_ctrl_pc_read_enable_out [i] ), + .write_enable_i ( ~backup_program_counter_error [i] + & dmr_ctrl_pc_write_enable_out [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_i [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 ( clk_i ), + .rst_ni ( rst_ni ), + .test_en_i ( '0 ), + //Read port A + .raddr_a_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_a ), + .rdata_a_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_a ), + //Read port B + .raddr_b_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_b ), + .rdata_b_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_b ), + //Read port C + .raddr_c_i ( '0 ), + .rdata_c_o ( ), + // Write Port A + .waddr_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_a ), + .wdata_a_i ( backup_regfile_wdata_a [i] ), + .we_a_i ( backup_regfile_we_a [i] ), + // Write Port B + .waddr_b_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_b ), + .wdata_b_i ( backup_regfile_wdata_b [i] ), + .we_b_i ( backup_regfile_we_b [i] ) + ); end if (NumDMRLeftover > 0) begin : gen_dmr_leftover_error assign dmr_error_main[NumCores-1-:NumDMRLeftover] = '0; assign dmr_error_data[NumCores-1-:NumDMRLeftover] = '0; assign dmr_error [NumCores-1-:NumDMRLeftover] = '0; end - end else begin: no_dmr_checkers // block: gen_dmr_checkers + end else begin: no_dmr_checkers assign dmr_error_main = '0; assign dmr_error_data = '0; assign dmr_error = '0; @@ -768,33 +974,52 @@ module HMR_wrap #( localparam SysCoreIndex = DMRFixed ? i/2 : dmr_core_id(dmr_group_id(i), 0); if (i < NumDMRCores && DMRFixed) begin : gen_dmr_mode // CTRL - assign core_core_id_o [i] = sys_core_id_i [SysCoreIndex]; - assign core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex]; + assign core_core_id_o [i] = sys_core_id_i [SysCoreIndex]; + assign core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex]; - assign core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex]; - assign core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex]; - assign core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex]; + assign core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex]; + assign core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex]; + assign core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex]; - assign core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex]; - assign core_perf_counters_o[i] = sys_perf_counters_i[SysCoreIndex]; + assign core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex] + | dmr_ctrl_core_debug_req_out [SysCoreIndex]; + assign core_debug_resume_o [i] = dmr_ctrl_debug_resume_out [SysCoreIndex]; + assign core_perf_counters_o[i] = sys_perf_counters_i [SysCoreIndex]; // IRQ - assign core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex]; - assign core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; + assign core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex]; + assign core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; // INSTR - assign core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; - assign core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[SysCoreIndex]; - assign core_instr_r_valid_o[i] = sys_instr_r_valid_i[SysCoreIndex]; - assign core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; + assign core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; + assign core_instr_r_rdata_o[i] = sys_instr_r_rdata_i [SysCoreIndex]; + assign core_instr_r_valid_o[i] = sys_instr_r_valid_i [SysCoreIndex]; + assign core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; + assign core_instr_lock_o [i] = dmr_ctrl_core_instr_lock_out [SysCoreIndex]; // DATA - assign core_data_gnt_o [i] = sys_data_gnt_i [SysCoreIndex]; - assign core_data_r_opc_o [i] = sys_data_r_opc_i [SysCoreIndex]; - assign core_data_r_rdata_o [i] = sys_data_r_rdata_i [SysCoreIndex]; - assign core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex]; - assign core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; - assign core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; + assign core_data_gnt_o [i] = sys_data_gnt_i [SysCoreIndex]; + assign core_data_r_opc_o [i] = sys_data_r_opc_i [SysCoreIndex]; + assign core_data_r_rdata_o [i] = sys_data_r_rdata_i [SysCoreIndex]; + assign core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex]; + assign core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; + assign core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; + + // PC + assign pc_recover_o [i] = dmr_ctrl_pc_read_enable_out [SysCoreIndex]; + assign recovery_program_counter_o [i] = recovery_program_counter_out [SysCoreIndex]; + assign recovery_branch_o [i] = recovery_branch_out [SysCoreIndex]; + assign recovery_branch_addr_o [i] = recovery_branch_addr_out [SysCoreIndex]; + + // RF + assign dmr_rf_readback_o [i] = regfile_readback_out [SysCoreIndex]; + assign core_regfile_raddr_o [i] = core_regfile_raddr_out [SysCoreIndex]; + assign core_recovery_regfile_wport_o[i].we_a = core_recovery_regfile_wport_out[SysCoreIndex].we_a; + assign core_recovery_regfile_wport_o[i].waddr_a = core_recovery_regfile_wport_out[SysCoreIndex].waddr_a; + assign core_recovery_regfile_wport_o[i].wdata_a = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_a; + assign core_recovery_regfile_wport_o[i].we_b = core_recovery_regfile_wport_out[SysCoreIndex].we_b; + assign core_recovery_regfile_wport_o[i].waddr_b = core_recovery_regfile_wport_out[SysCoreIndex].waddr_b; + assign core_recovery_regfile_wport_o[i].wdata_b = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_b; end else begin : gen_independent_mode @@ -854,6 +1079,9 @@ module HMR_wrap #( assign sys_data_user_o [i] = core_data_user_i [CoreCoreIndex]; assign sys_data_be_o [i] = core_data_be_i [CoreCoreIndex]; + assign core_setback_o [i] = dmr_ctrl_core_setback_out [CoreCoreIndex]; + assign core_recover_o [i] = dmr_ctrl_core_recover_out [CoreCoreIndex]; + end else begin : gen_disable_core // Assign disable // CTLR diff --git a/rtl/HMR/recovery_pc.sv b/rtl/HMR/recovery_pc.sv new file mode 100644 index 00000000..8b5fdf53 --- /dev/null +++ b/rtl/HMR/recovery_pc.sv @@ -0,0 +1,190 @@ +/* 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 ECCEnabled = 0, + parameter NonProtectedWidth = 32, + parameter ProtectedWidth = 39, + localparam 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_pkg.sv b/rtl/HMR/recovery_pkg.sv new file mode 100644 index 00000000..f3ec4ac5 --- /dev/null +++ b/rtl/HMR/recovery_pkg.sv @@ -0,0 +1,53 @@ +/* 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 recovery_pkg; + +localparam int unsigned DataWidth = 32; +localparam int unsigned RegfileAddr = 6; +localparam int unsigned RecoveryStateBits = 3; + +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 enum logic [RecoveryStateBits-1:0]{ + IDLE , + RESET , + HALT_REQ , + HALT_WAIT , + RESTORE_PC , + RESTORE_RF , + RESTORE_CSR, + EXIT +} recovery_routine_state_e; + +endpackage diff --git a/rtl/HMR/recovery_rf.sv b/rtl/HMR/recovery_rf.sv new file mode 100644 index 00000000..9572d26d --- /dev/null +++ b/rtl/HMR/recovery_rf.sv @@ -0,0 +1,257 @@ +// 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 ECCEnabled = 0, + parameter ADDR_WIDTH = 5, + parameter NonProtectedWidth = 32, + parameter ProtectedWidth = 39, + parameter FPU = 0, + parameter PULP_ZFINX = 0, + localparam 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 From 37e0583d0e694c21f19492e4620bd247581614e3 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 27 Jan 2023 16:50:32 +0100 Subject: [PATCH 03/72] Fix TMR and DMR assignments Add TMR-DMR support in assignments --- rtl/HMR/HMR_wrap.sv | 584 +++++++++++++++++++++++++++++++++----------- 1 file changed, 444 insertions(+), 140 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index eea74848..858aaff6 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -771,13 +771,249 @@ module HMR_wrap import recovery_pkg::*; #( *****************/ if (TMRFixed || DMRFixed) $fatal(1, "Cannot support both TMR and DMR and fix one!"); - // TODO + 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 + if (i < NumTMRCores && core_in_tmr[i]) begin : tmr_mode + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + + // 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]; + + core_debug_req_o [i] = sys_debug_req_i [TMRCoreIndex]; + 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] = sys_instr_gnt_i [TMRCoreIndex]; + core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[TMRCoreIndex]; + core_instr_r_valid_o[i] = sys_instr_r_valid_i[TMRCoreIndex]; + core_instr_err_o [i] = sys_instr_err_i [TMRCoreIndex]; + + // DATA + core_data_gnt_o [i] = sys_data_gnt_i [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] = sys_data_r_valid_i [TMRCoreIndex]; + core_data_err_o [i] = sys_data_err_i [TMRCoreIndex]; + end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode + core_setback_o [i] = '0; + + // 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]; + + core_debug_req_o [i] = sys_debug_req_i [DMRCoreIndex]; + 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] = sys_instr_gnt_i [DMRCoreIndex]; + core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[DMRCoreIndex]; + core_instr_r_valid_o[i] = sys_instr_r_valid_i[DMRCoreIndex]; + core_instr_err_o [i] = sys_instr_err_i [DMRCoreIndex]; + + // DATA + core_data_gnt_o [i] = sys_data_gnt_i [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] = sys_data_r_valid_i [DMRCoreIndex]; + core_data_err_o [i] = sys_data_err_i [DMRCoreIndex]; + end else begin : independent_mode + core_setback_o [i] = '0; + + // 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] = sys_instr_gnt_i [i]; + core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; + core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; + core_instr_err_o [i] = sys_instr_err_i [i]; + + // DATA + core_data_gnt_o [i] = sys_data_gnt_i [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] = sys_data_r_valid_i [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 + sys_instr_req_o [i] = tmr_instr_req_out [TMRCoreIndex]; + sys_instr_addr_o [i] = tmr_instr_addr_out[TMRCoreIndex]; + + // DATA + sys_data_req_o [i] = tmr_data_req_out [TMRCoreIndex]; + sys_data_add_o [i] = tmr_data_add_out [TMRCoreIndex]; + sys_data_wen_o [i] = tmr_data_wen_out [TMRCoreIndex]; + sys_data_wdata_o [i] = tmr_data_wdata_out[TMRCoreIndex]; + sys_data_user_o [i] = tmr_data_user_out [TMRCoreIndex]; + sys_data_be_o [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 + sys_instr_req_o [i] = '0; + sys_instr_addr_o [i] = '0; + + // DATA + sys_data_req_o [i] = '0; + sys_data_add_o [i] = '0; + sys_data_wen_o [i] = '0; + sys_data_wdata_o [i] = '0; + sys_data_user_o [i] = '0; + sys_data_be_o [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 + sys_instr_req_o [i] = dmr_instr_req_out [DMRCoreIndex]; + sys_instr_addr_o [i] = dmr_instr_addr_out[DMRCoreIndex]; + + // DATA + sys_data_req_o [i] = dmr_data_req_out [DMRCoreIndex]; + sys_data_add_o [i] = dmr_data_add_out [DMRCoreIndex]; + sys_data_wen_o [i] = dmr_data_wen_out [DMRCoreIndex]; + sys_data_wdata_o [i] = dmr_data_wdata_out[DMRCoreIndex]; + sys_data_user_o [i] = dmr_data_user_out [DMRCoreIndex]; + sys_data_be_o [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 + sys_instr_req_o [i] = '0; + sys_instr_addr_o [i] = '0; + + // DATA + sys_data_req_o [i] = '0; + sys_data_add_o [i] = '0; + sys_data_wen_o [i] = '0; + sys_data_wdata_o [i] = '0; + sys_data_user_o [i] = '0; + sys_data_be_o [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 + sys_instr_req_o [i] = core_instr_req_i [i]; + sys_instr_addr_o [i] = core_instr_addr_i[i]; + + // DATA + sys_data_req_o [i] = core_data_req_i [i]; + sys_data_add_o [i] = core_data_add_i [i]; + sys_data_wen_o [i] = core_data_wen_i [i]; + sys_data_wdata_o [i] = core_data_wdata_i[i]; + sys_data_user_o [i] = core_data_user_i [i]; + sys_data_be_o [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 + // Temporary disable of RapidRecovery + assign core_debug_resume_o [i] = '0; + + // Setback + assign core_recover_o [i] = '0; + assign core_instr_lock_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 dmr_rf_readback_o [i] = '0; + assign core_regfile_raddr_o [i] = '0; + 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; + localparam SysCoreIndex = TMRFixed ? i/3 : tmr_core_id(tmr_group_id(i), 0); always_comb begin if (i < NumTMRCores && (TMRFixed || core_in_tmr[i])) begin : tmr_mode @@ -855,20 +1091,20 @@ module HMR_wrap import recovery_pkg::*; #( assign sys_core_busy_o [i] = tmr_core_busy_out[CoreCoreIndex]; // IRQ - assign sys_irq_ack_o [i] = core_irq_ack_i [CoreCoreIndex]; - assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[CoreCoreIndex]; + 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 sys_instr_req_o [i] = core_instr_req_i [CoreCoreIndex]; - assign sys_instr_addr_o [i] = core_instr_addr_i[CoreCoreIndex]; + assign sys_instr_req_o [i] = tmr_instr_req_out [CoreCoreIndex]; + assign sys_instr_addr_o [i] = tmr_instr_addr_out[CoreCoreIndex]; // DATA - assign sys_data_req_o [i] = core_data_req_i [CoreCoreIndex]; - assign sys_data_add_o [i] = core_data_add_i [CoreCoreIndex]; - assign sys_data_wen_o [i] = core_data_wen_i [CoreCoreIndex]; - assign sys_data_wdata_o [i] = core_data_wdata_i[CoreCoreIndex]; - assign sys_data_user_o [i] = core_data_user_i [CoreCoreIndex]; - assign sys_data_be_o [i] = core_data_be_i [CoreCoreIndex]; + assign sys_data_req_o [i] = tmr_data_req_out [CoreCoreIndex]; + assign sys_data_add_o [i] = tmr_data_add_out [CoreCoreIndex]; + assign sys_data_wen_o [i] = tmr_data_wen_out [CoreCoreIndex]; + assign sys_data_wdata_o [i] = tmr_data_wdata_out[CoreCoreIndex]; + assign sys_data_user_o [i] = tmr_data_user_out [CoreCoreIndex]; + assign sys_data_be_o [i] = tmr_data_be_out [CoreCoreIndex]; end else begin if (i >= NumTMRCores) begin : independent_stragglers // CTRL @@ -898,20 +1134,20 @@ module HMR_wrap import recovery_pkg::*; #( sys_core_busy_o [i] = tmr_core_busy_out[CoreCoreIndex]; // IRQ - sys_irq_ack_o [i] = core_irq_ack_i [CoreCoreIndex]; - sys_irq_ack_id_o [i] = core_irq_ack_id_i[CoreCoreIndex]; + sys_irq_ack_o [i] = tmr_irq_ack_out [CoreCoreIndex]; + sys_irq_ack_id_o [i] = tmr_irq_ack_id_out[CoreCoreIndex]; // INSTR - sys_instr_req_o [i] = core_instr_req_i [CoreCoreIndex]; - sys_instr_addr_o [i] = core_instr_addr_i[CoreCoreIndex]; + sys_instr_req_o [i] = tmr_instr_req_out [CoreCoreIndex]; + sys_instr_addr_o [i] = tmr_instr_addr_out[CoreCoreIndex]; // DATA - sys_data_req_o [i] = core_data_req_i [CoreCoreIndex]; - sys_data_add_o [i] = core_data_add_i [CoreCoreIndex]; - sys_data_wen_o [i] = core_data_wen_i [CoreCoreIndex]; - sys_data_wdata_o [i] = core_data_wdata_i[CoreCoreIndex]; - sys_data_user_o [i] = core_data_user_i [CoreCoreIndex]; - sys_data_be_o [i] = core_data_be_i [CoreCoreIndex]; + sys_data_req_o [i] = tmr_data_req_out [CoreCoreIndex]; + sys_data_add_o [i] = tmr_data_add_out [CoreCoreIndex]; + sys_data_wen_o [i] = tmr_data_wen_out [CoreCoreIndex]; + sys_data_wdata_o [i] = tmr_data_wdata_out[CoreCoreIndex]; + sys_data_user_o [i] = tmr_data_user_out [CoreCoreIndex]; + sys_data_be_o [i] = tmr_data_be_out [CoreCoreIndex]; end else begin : disable_core // Assign disable @@ -972,159 +1208,227 @@ module HMR_wrap import recovery_pkg::*; #( for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs localparam SysCoreIndex = DMRFixed ? i/2 : dmr_core_id(dmr_group_id(i), 0); - if (i < NumDMRCores && DMRFixed) begin : gen_dmr_mode - // CTRL - assign core_core_id_o [i] = sys_core_id_i [SysCoreIndex]; - assign core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex]; + localparam SysGroupId = DMRFixed ? i/2 : dmr_group_id(i); + always_comb begin + 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]; - assign core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex]; - assign core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex]; - assign core_boot_addr_o [i] = sys_boot_addr_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]; - assign core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex] - | dmr_ctrl_core_debug_req_out [SysCoreIndex]; - assign core_debug_resume_o [i] = dmr_ctrl_debug_resume_out [SysCoreIndex]; - assign core_perf_counters_o[i] = sys_perf_counters_i [SysCoreIndex]; + core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex] + | dmr_ctrl_core_debug_req_out [SysGroupId]; + core_debug_resume_o [i] = dmr_ctrl_debug_resume_out [SysGroupId]; + core_perf_counters_o[i] = sys_perf_counters_i [SysCoreIndex]; - // IRQ - assign core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex]; - assign core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; + // Setback + core_setback_o [i] = dmr_ctrl_core_setback_out [SysGroupId]; + core_recover_o [i] = dmr_ctrl_core_recover_out [SysGroupId]; - // INSTR - assign core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; - assign core_instr_r_rdata_o[i] = sys_instr_r_rdata_i [SysCoreIndex]; - assign core_instr_r_valid_o[i] = sys_instr_r_valid_i [SysCoreIndex]; - assign core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; - assign core_instr_lock_o [i] = dmr_ctrl_core_instr_lock_out [SysCoreIndex]; + // IRQ + core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex]; + core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; - // DATA - assign core_data_gnt_o [i] = sys_data_gnt_i [SysCoreIndex]; - assign core_data_r_opc_o [i] = sys_data_r_opc_i [SysCoreIndex]; - assign core_data_r_rdata_o [i] = sys_data_r_rdata_i [SysCoreIndex]; - assign core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex]; - assign core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; - assign core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; - - // PC - assign pc_recover_o [i] = dmr_ctrl_pc_read_enable_out [SysCoreIndex]; - assign recovery_program_counter_o [i] = recovery_program_counter_out [SysCoreIndex]; - assign recovery_branch_o [i] = recovery_branch_out [SysCoreIndex]; - assign recovery_branch_addr_o [i] = recovery_branch_addr_out [SysCoreIndex]; - - // RF - assign dmr_rf_readback_o [i] = regfile_readback_out [SysCoreIndex]; - assign core_regfile_raddr_o [i] = core_regfile_raddr_out [SysCoreIndex]; - assign core_recovery_regfile_wport_o[i].we_a = core_recovery_regfile_wport_out[SysCoreIndex].we_a; - assign core_recovery_regfile_wport_o[i].waddr_a = core_recovery_regfile_wport_out[SysCoreIndex].waddr_a; - assign core_recovery_regfile_wport_o[i].wdata_a = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_a; - assign core_recovery_regfile_wport_o[i].we_b = core_recovery_regfile_wport_out[SysCoreIndex].we_b; - assign core_recovery_regfile_wport_o[i].waddr_b = core_recovery_regfile_wport_out[SysCoreIndex].waddr_b; - assign core_recovery_regfile_wport_o[i].wdata_b = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_b; - - end else begin : gen_independent_mode + // INSTR + core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; + core_instr_r_rdata_o[i] = sys_instr_r_rdata_i [SysCoreIndex]; + core_instr_r_valid_o[i] = sys_instr_r_valid_i [SysCoreIndex]; + core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; + core_instr_lock_o [i] = dmr_ctrl_core_instr_lock_out [SysGroupId]; - // CTRL - assign core_core_id_o [i] = sys_core_id_i [i]; - assign core_cluster_id_o [i] = sys_cluster_id_i [i]; + // DATA + core_data_gnt_o [i] = sys_data_gnt_i [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] = sys_data_r_valid_i [SysCoreIndex]; + core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; + + // PC + pc_recover_o [i] = dmr_ctrl_pc_read_enable_out [SysCoreIndex]; + recovery_program_counter_o [i] = recovery_program_counter_out [SysCoreIndex]; + recovery_branch_o [i] = recovery_branch_out [SysCoreIndex]; + recovery_branch_addr_o [i] = recovery_branch_addr_out [SysCoreIndex]; + + // RF + dmr_rf_readback_o [i] = regfile_readback_out [SysCoreIndex]; + core_regfile_raddr_o [i] = core_regfile_raddr_out [SysCoreIndex]; + core_recovery_regfile_wport_o[i].we_a = core_recovery_regfile_wport_out[SysCoreIndex].we_a; + core_recovery_regfile_wport_o[i].waddr_a = core_recovery_regfile_wport_out[SysCoreIndex].waddr_a; + core_recovery_regfile_wport_o[i].wdata_a = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_a; + core_recovery_regfile_wport_o[i].we_b = core_recovery_regfile_wport_out[SysCoreIndex].we_b; + core_recovery_regfile_wport_o[i].waddr_b = core_recovery_regfile_wport_out[SysCoreIndex].waddr_b; + core_recovery_regfile_wport_o[i].wdata_b = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_b; + + 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]; - assign core_clock_en_o [i] = sys_clock_en_i [i]; - assign core_fetch_en_o [i] = sys_fetch_en_i [i]; - assign core_boot_addr_o [i] = sys_boot_addr_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]; - assign core_debug_req_o [i] = sys_debug_req_i [i]; - assign core_perf_counters_o[i] = sys_perf_counters_i[i]; + core_debug_req_o [i] = sys_debug_req_i [i]; + core_debug_resume_o [i] = '0; + core_perf_counters_o[i] = sys_perf_counters_i[i]; - // IRQ - assign core_irq_req_o [i] = sys_irq_req_i [i]; - assign core_irq_id_o [i] = sys_irq_id_i [i]; + // Setback + core_setback_o [i] = '0; + core_recover_o [i] = '0; - // INSTR - assign core_instr_gnt_o [i] = sys_instr_gnt_i [i]; - assign core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; - assign core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; - assign core_instr_err_o [i] = sys_instr_err_i [i]; + // IRQ + core_irq_req_o [i] = sys_irq_req_i [i]; + core_irq_id_o [i] = sys_irq_id_i [i]; - // DATA - assign core_data_gnt_o [i] = sys_data_gnt_i [i]; - assign core_data_r_opc_o [i] = sys_data_r_opc_i [i]; - assign core_data_r_rdata_o [i] = sys_data_r_rdata_i [i]; - assign core_data_r_user_o [i] = sys_data_r_user_i [i]; - assign core_data_r_valid_o [i] = sys_data_r_valid_i [i]; - assign core_data_err_o [i] = sys_data_err_i [i]; + // INSTR + core_instr_gnt_o [i] = sys_instr_gnt_i [i]; + core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; + core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; + core_instr_err_o [i] = sys_instr_err_i [i]; + core_instr_lock_o [i] = '0; + // DATA + core_data_gnt_o [i] = sys_data_gnt_i [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] = sys_data_r_valid_i [i]; + core_data_err_o [i] = sys_data_err_i [i]; + + // PC + pc_recover_o [i] = '0; + recovery_program_counter_o [i] = '0; + recovery_branch_o [i] = '0; + recovery_branch_addr_o [i] = '0; + + // RF + dmr_rf_readback_o [i] = '0; + core_regfile_raddr_o [i] = '0; + 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 // gen_core_inputs for (genvar i = 0; i < NumSysCores; i++) begin : gen_core_outputs - localparam CoreCoreIndex = DMRFixed ? i : dmr_core_id(i, 0); - if ((DMRFixed && i < NumDMRGroups) || (i < NumDMRCores)) begin : gen_dmr_mode - if (DMRFixed || (InterleaveGrps && i < NumDMRGroups) || (!InterleaveGrps && i%2 == 0)) begin : gen_is_dmr - + 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 sys_instr_req_o [i] = dmr_instr_req_out [CoreCoreIndex]; + assign sys_instr_addr_o [i] = dmr_instr_addr_out[CoreCoreIndex]; + + // DATA + assign sys_data_req_o [i] = dmr_data_req_out [CoreCoreIndex]; + assign sys_data_add_o [i] = dmr_data_add_out [CoreCoreIndex]; + assign sys_data_wen_o [i] = dmr_data_wen_out [CoreCoreIndex]; + assign sys_data_wdata_o [i] = dmr_data_wdata_out[CoreCoreIndex]; + assign sys_data_user_o [i] = dmr_data_user_out [CoreCoreIndex]; + assign sys_data_be_o [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[CoreCoreIndex]; + assign sys_core_busy_o [i] = dmr_core_busy_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; // IRQ - assign sys_irq_ack_o [i] = core_irq_ack_i [CoreCoreIndex]; - assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[CoreCoreIndex]; + 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 sys_instr_req_o [i] = core_instr_req_i [CoreCoreIndex]; - assign sys_instr_addr_o [i] = core_instr_addr_i[CoreCoreIndex]; + assign sys_instr_req_o [i] = dmr_instr_req_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_instr_addr_o [i] = dmr_instr_addr_out[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; // DATA - assign sys_data_req_o [i] = core_data_req_i [CoreCoreIndex]; - assign sys_data_add_o [i] = core_data_add_i [CoreCoreIndex]; - assign sys_data_wen_o [i] = core_data_wen_i [CoreCoreIndex]; - assign sys_data_wdata_o [i] = core_data_wdata_i[CoreCoreIndex]; - assign sys_data_user_o [i] = core_data_user_i [CoreCoreIndex]; - assign sys_data_be_o [i] = core_data_be_i [CoreCoreIndex]; + assign sys_data_req_o [i] = dmr_data_req_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_data_add_o [i] = dmr_data_add_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_data_wen_o [i] = dmr_data_wen_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + assign sys_data_wdata_o [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 sys_data_be_o [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]; - assign core_setback_o [i] = dmr_ctrl_core_setback_out [CoreCoreIndex]; - assign core_recover_o [i] = dmr_ctrl_core_recover_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]; - end else begin : gen_disable_core // Assign disable + // INSTR + sys_instr_req_o [i] = dmr_instr_req_out [CoreCoreIndex]; + sys_instr_addr_o [i] = dmr_instr_addr_out[CoreCoreIndex]; - // CTLR - assign sys_core_busy_o [i] = '0; + // DATA + sys_data_req_o [i] = dmr_data_req_out [CoreCoreIndex]; + sys_data_add_o [i] = dmr_data_add_out [CoreCoreIndex]; + sys_data_wen_o [i] = dmr_data_wen_out [CoreCoreIndex]; + sys_data_wdata_o [i] = dmr_data_wdata_out[CoreCoreIndex]; + sys_data_user_o [i] = dmr_data_user_out [CoreCoreIndex]; + sys_data_be_o [i] = dmr_data_be_out [CoreCoreIndex]; - // IRQ - assign sys_irq_ack_o [i] = '0; - assign sys_irq_ack_id_o [i] = '0; + end else begin : disable_core // Assign disable - // INSTR - assign sys_instr_req_o [i] = '0; - assign sys_instr_addr_o [i] = '0; + // CTLR + sys_core_busy_o [i] = '0; - // DATA - assign sys_data_req_o [i] = '0; - assign sys_data_add_o [i] = '0; - assign sys_data_wen_o [i] = '0; - assign sys_data_wdata_o [i] = '0; - assign sys_data_user_o [i] = '0; - assign sys_data_be_o [i] = '0; + // IRQ + sys_irq_ack_o [i] = '0; + sys_irq_ack_id_o [i] = '0; - end - end else begin : gen_independent_mode - // CTRL - assign sys_core_busy_o [i] = core_core_busy_i [i]; + // INSTR + sys_instr_req_o [i] = '0; + sys_instr_addr_o [i] = '0; - // IRQ - assign sys_irq_ack_o [i] = core_irq_ack_i [i]; - assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[i]; + // DATA + sys_data_req_o [i] = '0; + sys_data_add_o [i] = '0; + sys_data_wen_o [i] = '0; + sys_data_wdata_o [i] = '0; + sys_data_user_o [i] = '0; + sys_data_be_o [i] = '0; - // INSTR - assign sys_instr_req_o [i] = core_instr_req_i [i]; - assign sys_instr_addr_o [i] = core_instr_addr_i[i]; + end + end else begin : independent_mode + // CTRL + sys_core_busy_o [i] = core_core_busy_i [i]; - // DATA - assign sys_data_req_o [i] = core_data_req_i [i]; - assign sys_data_add_o [i] = core_data_add_i [i]; - assign sys_data_wen_o [i] = core_data_wen_i [i]; - assign sys_data_wdata_o [i] = core_data_wdata_i[i]; - assign sys_data_user_o [i] = core_data_user_i [i]; - assign sys_data_be_o [i] = core_data_be_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 + sys_instr_req_o [i] = core_instr_req_i [i]; + sys_instr_addr_o [i] = core_instr_addr_i[i]; + + // DATA + sys_data_req_o [i] = core_data_req_i [i]; + sys_data_add_o [i] = core_data_add_i [i]; + sys_data_wen_o [i] = core_data_wen_i [i]; + sys_data_wdata_o [i] = core_data_wdata_i[i]; + sys_data_user_o [i] = core_data_user_i [i]; + sys_data_be_o [i] = core_data_be_i [i]; + end + end + end end - end // gen_core_outputs + end end else begin : gen_no_redundancy /***************** From 93c99eb2a669a8a5448a65edd5fc0646e2e7f65b Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 27 Jan 2023 16:52:12 +0100 Subject: [PATCH 04/72] Add RapidRecovery parameter to en-/disable backup RF --- rtl/HMR/DMR_controller.sv | 1 + rtl/HMR/HMR_wrap.sv | 234 +++++++++++++++++++------------------- 2 files changed, 121 insertions(+), 114 deletions(-) diff --git a/rtl/HMR/DMR_controller.sv b/rtl/HMR/DMR_controller.sv index b0e1927c..1d8fd3f3 100644 --- a/rtl/HMR/DMR_controller.sv +++ b/rtl/HMR/DMR_controller.sv @@ -18,6 +18,7 @@ import recovery_pkg::*; module DMR_controller #( 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, diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 858aaff6..e01b2f09 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -17,8 +17,8 @@ module HMR_wrap import recovery_pkg::*; #( parameter bit DMRFixed = 1'b0, parameter bit TMRSupported = 1'b1, parameter bit TMRFixed = 1'b0, + parameter bit RapidRecovery = 1'b0, // Backup Regfile parameter bit SeparateData = 1'b1, - parameter bit BackupRegfile = 1'b0, parameter bit InterleaveGrps = 1'b1, // alternative is sequential grouping parameter int unsigned InstrDataWidth = 32, parameter int unsigned DataWidth = 32, @@ -556,9 +556,10 @@ module HMR_wrap import recovery_pkg::*; #( * DMR Controller * ******************/ DMR_controller #( - .NumCores ( NumCores ), - .DMRFixed ( DMRFixed ), - .RFAddrWidth ( RFAddrWidth ) + .NumCores ( NumCores ), + .DMRFixed ( DMRFixed ), + .RapidRecovery ( RapidRecovery ), + .RFAddrWidth ( RFAddrWidth ) ) dmr_controller ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -625,120 +626,125 @@ module HMR_wrap import recovery_pkg::*; #( = main_dmr_out[i]; end - /****************** - * DMR PC Checker * - ******************/ - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_pc_checker ( - .inp_a_i ( backup_program_counter_i[dmr_core_id(i, 0)] ), - .inp_b_i ( backup_program_counter_i[dmr_core_id(i, 1)] ), - .check_o ( backup_program_counter_int [i] ), - .error_o ( backup_program_counter_error [i] ) - ); - - /********************* - * DMR Branch Checker * - **********************/ - DMR_checker # ( - .DataWidth ( 1 ) - ) dmr_branch_checker ( - .inp_a_i ( backup_branch_i[dmr_core_id(i, 0)] ), - .inp_b_i ( backup_branch_i[dmr_core_id(i, 1)] ), - .check_o ( backup_branch_int [i] ), - .error_o ( backup_branch_error [i] ) - ); - - /***************************** - * DMR Branch Address Checker * - ******************************/ - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_branch_addr_checker ( - .inp_a_i ( backup_branch_addr_i[dmr_core_id(i, 0)] ), - .inp_b_i ( backup_branch_addr_i[dmr_core_id(i, 1)] ), - .check_o ( backup_branch_addr_int [i] ), - .error_o ( backup_branch_addr_error [i] ) - ); - - /******************* - * DMR RF Checkers * - *******************/ - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_rf_checker_port_a ( - .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_a ), - .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_a ), - .check_o ( backup_regfile_wdata_a[i] ), - .error_o ( backup_regfile_error_a[i] ) - ); + if (RapidRecovery) begin - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_rf_checker_port_b ( - .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_b ), - .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_b ), - .check_o ( backup_regfile_wdata_b [i] ), - .error_o ( backup_regfile_error_b [i] ) - ); + /****************** + * DMR PC Checker * + ******************/ + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_pc_checker ( + .inp_a_i ( backup_program_counter_i[dmr_core_id(i, 0)] ), + .inp_b_i ( backup_program_counter_i[dmr_core_id(i, 1)] ), + .check_o ( backup_program_counter_int [i] ), + .error_o ( backup_program_counter_error [i] ) + ); + + /********************** + * DMR Branch Checker * + **********************/ + DMR_checker # ( + .DataWidth ( 1 ) + ) dmr_branch_checker ( + .inp_a_i ( backup_branch_i[dmr_core_id(i, 0)] ), + .inp_b_i ( backup_branch_i[dmr_core_id(i, 1)] ), + .check_o ( backup_branch_int [i] ), + .error_o ( backup_branch_error [i] ) + ); + + /***************************** + * DMR Branch Address Checker * + ******************************/ + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_branch_addr_checker ( + .inp_a_i ( backup_branch_addr_i[dmr_core_id(i, 0)] ), + .inp_b_i ( backup_branch_addr_i[dmr_core_id(i, 1)] ), + .check_o ( backup_branch_addr_int [i] ), + .error_o ( backup_branch_addr_error [i] ) + ); - assign backup_regfile_we_a [i] = backup_regfile_wport_i[i].we_a - & ~backup_regfile_error_a [i] - & ~dmr_ctrl_core_recover_out [i]; - assign backup_regfile_we_b [i] = backup_regfile_wport_i[i].we_b - & ~backup_regfile_error_b [i] - & ~dmr_ctrl_core_recover_out [i]; - /**************************** - * Recovery Program Counter * - ****************************/ - recovery_pc #( - .ECCEnabled ( 1 ) - ) RPC ( - // Control Ports - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( '0 ), - .read_enable_i ( dmr_ctrl_pc_read_enable_out [i] ), - .write_enable_i ( ~backup_program_counter_error [i] - & dmr_ctrl_pc_write_enable_out [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_i [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 #( + /******************* + * DMR RF Checkers * + *******************/ + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_rf_checker_port_a ( + .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_a ), + .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_a ), + .check_o ( backup_regfile_wdata_a[i] ), + .error_o ( backup_regfile_error_a[i] ) + ); + + DMR_checker # ( + .DataWidth ( DataWidth ) + ) dmr_rf_checker_port_b ( + .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_b ), + .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_b ), + .check_o ( backup_regfile_wdata_b [i] ), + .error_o ( backup_regfile_error_b [i] ) + ); + + assign backup_regfile_we_a [i] = backup_regfile_wport_i[i].we_a + & ~backup_regfile_error_a [i] + & ~dmr_ctrl_core_recover_out [i]; + assign backup_regfile_we_b [i] = backup_regfile_wport_i[i].we_b + & ~backup_regfile_error_b [i] + & ~dmr_ctrl_core_recover_out [i]; + /**************************** + * Recovery Program Counter * + ****************************/ + recovery_pc #( + .ECCEnabled ( 1 ) + ) RPC ( + // Control Ports + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .clear_i ( '0 ), + .read_enable_i ( dmr_ctrl_pc_read_enable_out [i] ), + .write_enable_i ( ~backup_program_counter_error [i] + & dmr_ctrl_pc_write_enable_out [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_i [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 ( clk_i ), - .rst_ni ( rst_ni ), - .test_en_i ( '0 ), - //Read port A - .raddr_a_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_a ), - .rdata_a_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_a ), - //Read port B - .raddr_b_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_b ), - .rdata_b_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_b ), - //Read port C - .raddr_c_i ( '0 ), - .rdata_c_o ( ), - // Write Port A - .waddr_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_a ), - .wdata_a_i ( backup_regfile_wdata_a [i] ), - .we_a_i ( backup_regfile_we_a [i] ), - // Write Port B - .waddr_b_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_b ), - .wdata_b_i ( backup_regfile_wdata_b [i] ), - .we_b_i ( backup_regfile_we_b [i] ) - ); + ) RRF ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .test_en_i ( '0 ), + //Read port A + .raddr_a_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_a ), + .rdata_a_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_a ), + //Read port B + .raddr_b_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_b ), + .rdata_b_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_b ), + //Read port C + .raddr_c_i ( '0 ), + .rdata_c_o ( ), + // Write Port A + .waddr_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_a ), + .wdata_a_i ( backup_regfile_wdata_a [i] ), + .we_a_i ( backup_regfile_we_a [i] ), + // Write Port B + .waddr_b_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_b ), + .wdata_b_i ( backup_regfile_wdata_b [i] ), + .we_b_i ( backup_regfile_we_b [i] ) + ); + end else begin + + end end if (NumDMRLeftover > 0) begin : gen_dmr_leftover_error assign dmr_error_main[NumCores-1-:NumDMRLeftover] = '0; From 1215c43b17ee55f5b96dd318e9b30fab5becbb85 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Fri, 27 Jan 2023 10:49:36 +0100 Subject: [PATCH 05/72] Added clock gating to lock unfaulty cores during recovery routine. --- rtl/HMR/DMR_controller.sv | 28 +++++++++++++++++++++++++++- rtl/HMR/HMR_wrap.sv | 6 ++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/rtl/HMR/DMR_controller.sv b/rtl/HMR/DMR_controller.sv index 1d8fd3f3..3fb9bd17 100644 --- a/rtl/HMR/DMR_controller.sv +++ b/rtl/HMR/DMR_controller.sv @@ -77,7 +77,9 @@ logic [NumDMRGroups-1:0] dmr_ctrl_core_setback_out , 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_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, @@ -165,6 +167,25 @@ generate 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 @@ -276,6 +297,7 @@ always_comb begin : recovery_routine_fsm 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; @@ -293,6 +315,10 @@ always_comb begin : recovery_routine_fsm 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 diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index e01b2f09..727bcf33 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -237,6 +237,7 @@ module HMR_wrap import recovery_pkg::*; #( backup_program_counter_error, dmr_ctrl_pc_read_enable_out, dmr_ctrl_pc_write_enable_out, + dmr_ctrl_core_clk_en_out, backup_regfile_we_a, backup_regfile_we_b, backup_regfile_error_a, @@ -579,7 +580,7 @@ module HMR_wrap import recovery_pkg::*; #( .dmr_ctrl_core_debug_resume_o ( dmr_ctrl_debug_resume_out ), .dmr_ctrl_pc_read_enable_o ( dmr_ctrl_pc_read_enable_out ), .dmr_ctrl_pc_write_enable_o ( dmr_ctrl_pc_write_enable_out ), - .dmr_ctrl_core_clk_en_o ( ) + .dmr_ctrl_core_clk_en_o ( dmr_ctrl_core_clk_en_out ) ); if (DMRSupported || DMRFixed) begin: gen_dmr_recovery_region @@ -1221,7 +1222,8 @@ module HMR_wrap import recovery_pkg::*; #( 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_clock_en_o [i] = sys_clock_en_i [SysCoreIndex] + & dmr_ctrl_core_clk_en_out[SysGroupId]; core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex]; core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex]; From dff93e44be78a8baf9a41dc80f0abddbd70566e2 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 27 Jan 2023 17:28:55 +0100 Subject: [PATCH 06/72] Add parameter documentation --- rtl/HMR/DMR_controller.sv | 4 +--- rtl/HMR/HMR_wrap.sv | 48 +++++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/rtl/HMR/DMR_controller.sv b/rtl/HMR/DMR_controller.sv index 3fb9bd17..f6c83fd3 100644 --- a/rtl/HMR/DMR_controller.sv +++ b/rtl/HMR/DMR_controller.sv @@ -13,9 +13,7 @@ * */ -import recovery_pkg::*; - -module DMR_controller #( +module DMR_controller import recovery_pkg::*; #( parameter int unsigned NumCores = 0, parameter bit DMRFixed = 1'b0, parameter bit RapidRecovery = 1'b0, diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 727bcf33..02337d5e 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -12,14 +12,22 @@ module HMR_wrap import 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, - parameter bit RapidRecovery = 1'b0, // Backup Regfile + /// 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, - parameter bit InterleaveGrps = 1'b1, // alternative is sequential grouping + /// 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, @@ -28,12 +36,19 @@ module HMR_wrap import recovery_pkg::*; #( 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 , @@ -199,8 +214,8 @@ module HMR_wrap import recovery_pkg::*; #( 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 [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; @@ -587,9 +602,9 @@ module HMR_wrap import recovery_pkg::*; #( for (genvar i = 0; i < NumDMRGroups; i++) begin assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main | dmr_failure_data) : dmr_failure_main; - assign dmr_error [i*2+:2] = dmr_data_req_out [i] ? (dmr_error_main [i*2+:2] | dmr_error_data [i*2+:2]) - : tmr_error_main [i*2+:2]; - assign dmr_single_mismatch [i] = dmr_error [i*2+:2] != 3'b000; + // assign dmr_error [i*2+:2] = dmr_data_req_out [i] ? (dmr_error_main [i*2+:2] | dmr_error_data [i*2+:2]) + // : dmr_error_main [i*2+:2]; + // assign dmr_single_mismatch [i] = dmr_error [i*2+:2] != 3'b000; /********************* * DMR Core Checkers * @@ -619,7 +634,7 @@ module HMR_wrap import recovery_pkg::*; #( = data_dmr_out[i]; end else begin : gen_data_in_main assign dmr_failure_data[i] = 1'b0; - assign dmr_error_data[i] = 3'b000; + // assign dmr_error_data[i] = 3'b000; 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], @@ -747,15 +762,15 @@ module HMR_wrap import recovery_pkg::*; #( end end - if (NumDMRLeftover > 0) begin : gen_dmr_leftover_error - assign dmr_error_main[NumCores-1-:NumDMRLeftover] = '0; - assign dmr_error_data[NumCores-1-:NumDMRLeftover] = '0; - assign dmr_error [NumCores-1-:NumDMRLeftover] = '0; - end + // if (NumDMRLeftover > 0) begin : gen_dmr_leftover_error + // assign dmr_error_main[NumCores-1-:NumDMRLeftover] = '0; + // assign dmr_error_data[NumCores-1-:NumDMRLeftover] = '0; + // assign dmr_error [NumCores-1-:NumDMRLeftover] = '0; + // end end else begin: no_dmr_checkers - assign dmr_error_main = '0; - assign dmr_error_data = '0; - assign dmr_error = '0; + // assign dmr_error_main = '0; + // assign dmr_error_data = '0; + // assign dmr_error = '0; assign dmr_failure_main = '0; assign dmr_failure_data = '0; assign dmr_failure = '0; @@ -1086,7 +1101,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [i]; core_data_r_valid_o [i] = sys_data_r_valid_i [i]; core_data_err_o [i] = sys_data_err_i [i]; - end end end From a994fe573acf2faebd8231b6979c30995796dfbd Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 30 Jan 2023 19:42:29 +0100 Subject: [PATCH 07/72] Update TMR signalling --- rtl/HMR/HMR_wrap.sv | 49 +++++++++++------------- rtl/HMR/hmr_tmr_ctrl.sv | 85 +++++++++++++++++++++++------------------ 2 files changed, 69 insertions(+), 65 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 02337d5e..9008e4c6 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -88,26 +88,26 @@ module HMR_wrap import recovery_pkg::*; #( // 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 , @@ -129,17 +129,17 @@ module HMR_wrap import recovery_pkg::*; #( 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 , @@ -147,11 +147,11 @@ module HMR_wrap import recovery_pkg::*; #( output logic [ NumCores-1:0] core_instr_r_valid_o, output logic [ NumCores-1:0] core_instr_lock_o , output logic [ NumCores-1:0] core_instr_err_o , - + output logic [ NumCores-1:0] core_debug_req_o , output logic [ NumCores-1:0] core_debug_resume_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 , @@ -164,7 +164,7 @@ module HMR_wrap import recovery_pkg::*; #( 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 @@ -292,14 +292,18 @@ module HMR_wrap import recovery_pkg::*; #( * HMR Control Registers * ***************************/ - logic [NumSysCores-1:0] core_en_as_master; - logic [NumSysCores-1:0] core_in_independent; - logic [NumSysCores-1:0] core_in_dmr; - logic [NumSysCores-1:0] core_in_tmr; + 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 [NumTMRGroups-1:0] tmr_setback_q; + logic [NumTMRGroups-1:0] tmr_grp_in_independent; - for (genvar i = 0; i < NumSysCores; i++) begin + for (genvar i = 0; i < NumCores; i++) begin assign core_in_independent[i] = ~core_in_dmr[i] & ~core_in_tmr[i]; assign core_in_dmr[i] = 1'b0; + 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]); end @@ -410,9 +414,6 @@ module HMR_wrap import recovery_pkg::*; #( assign core_config_hw2reg[i].current_mode.triple.d = core_in_tmr[i]; end - logic [NumTMRGroups-1:0] tmr_setback_q; - logic [NumTMRGroups-1:0] tmr_grp_in_independent; - /********************************************************** ******************** TMR Voters & Regs ******************* @@ -421,9 +422,6 @@ module HMR_wrap import recovery_pkg::*; #( if (TMRSupported || TMRFixed) begin : gen_tmr_logic if (TMRFixed && NumCores % 3 != 0) $warning("Extra cores added not properly handled!"); - hmr_tmr_regs_reg_pkg::hmr_tmr_regs_reg2hw_t [NumTMRGroups-1:0] tmr_reg2hw; - hmr_tmr_regs_reg_pkg::hmr_tmr_regs_hw2reg_t [NumTMRGroups-1:0] tmr_hw2reg; - reg_req_t [NumTMRGroups-1:0] tmr_register_reqs; reg_resp_t [NumTMRGroups-1:0] tmr_register_resps; @@ -445,14 +443,9 @@ module HMR_wrap import recovery_pkg::*; #( .out_req_o ( tmr_register_reqs ), .out_rsp_i ( tmr_register_resps ) ); - - for (genvar i = 0; i < NumTMRCores; i++) begin : gen_core_in_tmr - assign core_in_tmr[i] = !tmr_grp_in_independent[tmr_group_id(i)]; - end for (genvar i = NumTMRCores; i < NumCores; i++) begin : gen_extra_core_assigns assign tmr_incr_mismatches[i] = '0; - assign core_in_tmr[i] = '0; end for (genvar i = 0; i < NumTMRGroups; i++) begin : gen_tmr_groups @@ -482,6 +475,7 @@ module HMR_wrap import recovery_pkg::*; #( .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] ), .grp_in_independent_o ( tmr_grp_in_independent[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] ), @@ -554,6 +548,7 @@ module HMR_wrap import recovery_pkg::*; #( assign tmr_grp_in_independent = '0; assign core_in_tmr = '0; assign tmr_setback_q = '0; + assign tmr_resynch_req_o = '0; end /************************************************************ diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 13055a3f..9bf2df4d 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -25,7 +25,7 @@ module hmr_tmr_ctrl #( input reg_req_t reg_req_i, output reg_resp_t reg_resp_o, - // CTRL from external (e.g. HMR ctr regs) + // 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, @@ -39,6 +39,7 @@ module hmr_tmr_ctrl #( // TMR control signals output logic setback_o, + output logic sw_resynch_req_o, output logic grp_in_independent_o, output logic [2:0] tmr_incr_mismatches_o, input logic tmr_single_mismatch_i, @@ -59,6 +60,7 @@ module hmr_tmr_ctrl #( assign setback_o = tmr_setback_q; assign grp_in_independent_o = tmr_red_mode_q == NON_TMR; + assign tmr_resynch_req_o = tmr_red_mode_q == TMR_UNLOAD; hmr_tmr_regs_reg_top #( .reg_req_t(reg_req_t), @@ -96,51 +98,58 @@ module hmr_tmr_ctrl #( tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; - // If forced execute resynchronization - if (tmr_red_mode_q == TMR_RUN && tmr_reg2hw.tmr_config.force_resynch.q) begin - tmr_hw2reg.tmr_config.force_resynch.de = 1'b1; - if (tmr_reg2hw.tmr_config.delay_resynch == 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_red_mode_q == TMR_RUN && tmr_single_mismatch_i) begin - $display("[ODRG] %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; + 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.delay_resynch == 0) begin + tmr_red_mode_d = TMR_UNLOAD; + // TODO: buffer the restoration until delay_resynch is disabled + end + end - if (tmr_reg2hw.tmr_config.delay_resynch == 0) begin - tmr_red_mode_d = TMR_UNLOAD; - // TODO: buffer the restoration until delay_resynch is disabled + // If error detected, do resynchronization + if (tmr_single_mismatch_i) begin + $display("[ODRG] %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.delay_resynch == 0) begin + tmr_red_mode_d = TMR_UNLOAD; + // TODO: buffer the restoration until delay_resynch is disabled + end + end end - end - // If unload complete, go to reload (and reset) - if (tmr_red_mode_q == TMR_UNLOAD) begin - if (tmr_reg2hw.sp_store.q != '0) begin - tmr_red_mode_d = TMR_RELOAD; - if (tmr_reg2hw.tmr_config.setback.q) begin - tmr_setback_d = 1'b1; + TMR_UNLOAD: begin + // If unload complete, go to reload (and reset) + if (tmr_reg2hw.sp_store.q != '0) begin + tmr_red_mode_d = TMR_RELOAD; + if (tmr_reg2hw.tmr_config.setback.q) begin + tmr_setback_d = 1'b1; + end end end - end - // If reload complete, finish (or reset if error happens during reload) - if (tmr_red_mode_q == TMR_RELOAD) begin - if (tmr_reg2hw.sp_store.q == '0) begin - $display("[ODRG] %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 && - !(tmr_reg2hw.sp_store.qe && reg_req_i.wdata == '0)) begin - tmr_setback_d = 1'b1; + TMR_RELOAD: begin + // If reload complete, finish (or reset if error happens during reload) + if (tmr_reg2hw.sp_store.q == '0) begin + $display("[ODRG] %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 && + !(tmr_reg2hw.sp_store.qe && reg_req_i.wdata == '0)) begin + tmr_setback_d = 1'b1; + end end end - end + + // Default: do nothing + + endcase // Before core startup: set TMR mode from reg2hw.mode.mode if (!TMRFixed) begin From ed98b4793f189397593f4bd2c397bd4f7f76be0e Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 31 Jan 2023 16:01:03 +0100 Subject: [PATCH 08/72] Update signal alignments --- rtl/HMR/HMR_wrap.sv | 42 ++++++++++++++++------------------------- rtl/HMR/hmr_tmr_ctrl.sv | 9 ++++----- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 9008e4c6..8c8e7b47 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -794,8 +794,6 @@ module HMR_wrap import recovery_pkg::*; #( always_comb begin if (i < NumTMRCores && core_in_tmr[i]) begin : tmr_mode - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; - // CTRL core_core_id_o [i] = sys_core_id_i [TMRCoreIndex]; core_cluster_id_o [i] = sys_cluster_id_i [TMRCoreIndex]; @@ -824,9 +822,10 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [TMRCoreIndex]; core_data_r_valid_o [i] = sys_data_r_valid_i [TMRCoreIndex]; core_data_err_o [i] = sys_data_err_i [TMRCoreIndex]; - end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode - core_setback_o [i] = '0; + // Special signals + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + 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]; @@ -855,9 +854,10 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [DMRCoreIndex]; core_data_r_valid_o [i] = sys_data_r_valid_i [DMRCoreIndex]; core_data_err_o [i] = sys_data_err_i [DMRCoreIndex]; - end else begin : independent_mode + + // Special signals core_setback_o [i] = '0; - + 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]; @@ -886,6 +886,9 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [i]; core_data_r_valid_o [i] = sys_data_r_valid_i [i]; core_data_err_o [i] = sys_data_err_i [i]; + + // Special signals + core_setback_o [i] = '0; end end end @@ -914,9 +917,7 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = tmr_data_wdata_out[TMRCoreIndex]; sys_data_user_o [i] = tmr_data_user_out [TMRCoreIndex]; sys_data_be_o [i] = tmr_data_be_out [TMRCoreIndex]; - end else begin : disable_core // Assign disable - // CTLR sys_core_busy_o [i] = '0; @@ -935,7 +936,6 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = '0; sys_data_user_o [i] = '0; sys_data_be_o [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 @@ -957,9 +957,7 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = dmr_data_wdata_out[DMRCoreIndex]; sys_data_user_o [i] = dmr_data_user_out [DMRCoreIndex]; sys_data_be_o [i] = dmr_data_be_out [DMRCoreIndex]; - end else begin : disable_core // Assign disable - // CTLR sys_core_busy_o [i] = '0; @@ -978,7 +976,6 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = '0; sys_data_user_o [i] = '0; sys_data_be_o [i] = '0; - end end else begin : independent_mode // CTRL @@ -1034,8 +1031,6 @@ module HMR_wrap import recovery_pkg::*; #( localparam SysCoreIndex = TMRFixed ? i/3 : tmr_core_id(tmr_group_id(i), 0); always_comb begin if (i < NumTMRCores && (TMRFixed || core_in_tmr[i])) begin : tmr_mode - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; - // CTRL core_core_id_o [i] = sys_core_id_i [SysCoreIndex]; core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex]; @@ -1065,9 +1060,9 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; + // Special signals + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; end else begin : independent_mode - core_setback_o [i] = '0; - // CTRL core_core_id_o [i] = sys_core_id_i [i]; core_cluster_id_o [i] = sys_cluster_id_i [i]; @@ -1096,6 +1091,9 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [i]; core_data_r_valid_o [i] = sys_data_r_valid_i [i]; core_data_err_o [i] = sys_data_err_i [i]; + + // Special signals + core_setback_o [i] = '0; end end end @@ -1145,7 +1143,6 @@ module HMR_wrap import recovery_pkg::*; #( 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]; @@ -1164,9 +1161,7 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = tmr_data_wdata_out[CoreCoreIndex]; sys_data_user_o [i] = tmr_data_user_out [CoreCoreIndex]; sys_data_be_o [i] = tmr_data_be_out [CoreCoreIndex]; - end else begin : disable_core // Assign disable - // CTLR sys_core_busy_o [i] = '0; @@ -1185,7 +1180,6 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = '0; sys_data_user_o [i] = '0; sys_data_be_o [i] = '0; - end end else begin : independent_mode // CTRL @@ -1380,7 +1374,6 @@ module HMR_wrap import recovery_pkg::*; #( 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]; @@ -1399,9 +1392,7 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = dmr_data_wdata_out[CoreCoreIndex]; sys_data_user_o [i] = dmr_data_user_out [CoreCoreIndex]; sys_data_be_o [i] = dmr_data_be_out [CoreCoreIndex]; - end else begin : disable_core // Assign disable - // CTLR sys_core_busy_o [i] = '0; @@ -1420,7 +1411,6 @@ module HMR_wrap import recovery_pkg::*; #( sys_data_wdata_o [i] = '0; sys_data_user_o [i] = '0; sys_data_be_o [i] = '0; - end end else begin : independent_mode // CTRL @@ -1453,7 +1443,7 @@ module HMR_wrap import recovery_pkg::*; #( *****************/ // 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; @@ -1462,7 +1452,7 @@ module HMR_wrap import recovery_pkg::*; #( 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; diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 9bf2df4d..0244fb2f 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -92,9 +92,7 @@ module hmr_tmr_ctrl #( always_comb begin : proc_fsm tmr_setback_d = 1'b0; tmr_red_mode_d = tmr_red_mode_q; - tmr_incr_mismatches_o[0] = 1'b0; - tmr_incr_mismatches_o[1] = 1'b0; - tmr_incr_mismatches_o[2] = 1'b0; + tmr_incr_mismatches_o = '0; tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; @@ -151,8 +149,9 @@ module hmr_tmr_ctrl #( endcase - // Before core startup: set TMR mode from reg2hw.mode.mode + // Logic to switch in and out of TMR if (!TMRFixed) begin + // 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; @@ -160,7 +159,7 @@ module hmr_tmr_ctrl #( tmr_red_mode_d = TMR_RUN; end end - // split single-error tolerant mode to performance mode anytime (but require correct core state) + // 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 tmr_red_mode_d = NON_TMR; From 200a2df8d4caf508268efba4a7ede1060c638158 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 31 Jan 2023 17:53:30 +0100 Subject: [PATCH 09/72] Add individual dmr controller (separated rapid-recovery) --- Bender.yml | 3 +- rtl/HMR/HMR_wrap.sv | 294 +++++++++++++++++----------------------- rtl/HMR/hmr_dmr_ctrl.sv | 137 +++++++++++++++++++ 3 files changed, 262 insertions(+), 172 deletions(-) create mode 100644 rtl/HMR/hmr_dmr_ctrl.sv diff --git a/Bender.yml b/Bender.yml index 341c3022..3ee5f36c 100644 --- a/Bender.yml +++ b/Bender.yml @@ -98,7 +98,7 @@ sources: - rtl/HMR/recovery_pc.sv - rtl/HMR/DMR_checker.sv - rtl/HMR/DMR_address_generator.sv - - rtl/HMR/DMR_controller.sv + # - rtl/HMR/DMR_controller.sv - rtl/HMR/hmr_registers_reg_pkg.sv - rtl/HMR/hmr_core_regs_reg_pkg.sv - rtl/HMR/hmr_dmr_regs_reg_pkg.sv @@ -106,6 +106,7 @@ sources: - 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 diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 8c8e7b47..b2f57935 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -297,12 +297,15 @@ module HMR_wrap import recovery_pkg::*; #( logic [NumCores-1:0] core_in_dmr; logic [NumCores-1:0] core_in_tmr; + logic [NumDMRGroups-1:0] dmr_setback_q; + logic [NumDMRGroups-1:0] dmr_grp_in_independent; + logic [NumTMRGroups-1:0] tmr_setback_q; logic [NumTMRGroups-1:0] tmr_grp_in_independent; for (genvar i = 0; i < NumCores; i++) begin assign core_in_independent[i] = ~core_in_dmr[i] & ~core_in_tmr[i]; - assign core_in_dmr[i] = 1'b0; + 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]); @@ -391,7 +394,6 @@ module HMR_wrap import recovery_pkg::*; #( logic [NumCores-1:0] tmr_incr_mismatches; logic [NumCores-1:0] dmr_incr_mismatches; - assign dmr_incr_mismatches = '0; for (genvar i = 0; i < NumCores; i++) begin hmr_core_regs_reg_top #( @@ -451,17 +453,17 @@ module HMR_wrap import recovery_pkg::*; #( 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) + .reg_req_t ( reg_req_t ), + .reg_resp_t ( reg_resp_t ), + .TMRFixed ( TMRFixed ), + .InterleaveGrps ( InterleaveGrps ), + .DefaultInTMR ( 1'b0 ) ) i_tmr_ctrl ( .clk_i, .rst_ni, - .reg_req_i ( tmr_register_reqs[i]), - .reg_resp_o ( tmr_register_resps[i]), + .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 ), @@ -486,7 +488,7 @@ module HMR_wrap import recovery_pkg::*; #( ); assign tmr_failure[i] = tmr_data_req_out[i] ? - tmr_failure_main | tmr_failure_data : tmr_failure_main; + 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; @@ -546,7 +548,6 @@ module HMR_wrap import recovery_pkg::*; #( assign top_register_resps[3].ready = 1'b1; assign tmr_incr_mismatches = '0; assign tmr_grp_in_independent = '0; - assign core_in_tmr = '0; assign tmr_setback_q = '0; assign tmr_resynch_req_o = '0; end @@ -563,43 +564,68 @@ module HMR_wrap import recovery_pkg::*; #( & core_debug_halted_i [dmr_core_id(dmr_group_id(i), 1)]; end - /****************** - * DMR Controller * - ******************/ - DMR_controller #( - .NumCores ( NumCores ), - .DMRFixed ( DMRFixed ), - .RapidRecovery ( RapidRecovery ), - .RFAddrWidth ( RFAddrWidth ) - ) dmr_controller ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .dmr_rf_checker_error_port_a_i ( backup_regfile_error_a ), - .dmr_rf_checker_error_port_b_i ( backup_regfile_error_b ), - .dmr_core_checker_error_main_i ( dmr_failure_main ), - .dmr_core_checker_error_data_i ( dmr_failure_data ), - .backup_regfile_write_i ( backup_regfile_wport_in ), - .core_recovery_regfile_wport_o ( core_recovery_regfile_wport_out ), - .regfile_readback_o ( regfile_readback_out ), - .regfile_raddr_o ( core_regfile_raddr_out ), - .dmr_ctrl_core_debug_req_o ( dmr_ctrl_core_debug_req_out ), - .dmr_ctrl_core_debug_rsp_i ( dmr_ctrl_core_debug_halted_in ), - .dmr_ctrl_core_instr_lock_o ( dmr_ctrl_core_instr_lock_out ), - .dmr_ctrl_core_setback_o ( dmr_ctrl_core_setback_out ), - .dmr_ctrl_core_recover_o ( dmr_ctrl_core_recover_out ), - .dmr_ctrl_core_debug_resume_o ( dmr_ctrl_debug_resume_out ), - .dmr_ctrl_pc_read_enable_o ( dmr_ctrl_pc_read_enable_out ), - .dmr_ctrl_pc_write_enable_o ( dmr_ctrl_pc_write_enable_out ), - .dmr_ctrl_core_clk_en_o ( dmr_ctrl_core_clk_en_out ) - ); - if (DMRSupported || DMRFixed) begin: gen_dmr_recovery_region + + 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; + + 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; + end + for (genvar i = 0; i < NumDMRGroups; i++) begin - assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main | dmr_failure_data) - : dmr_failure_main; - // assign dmr_error [i*2+:2] = dmr_data_req_out [i] ? (dmr_error_main [i*2+:2] | dmr_error_data [i*2+:2]) - // : dmr_error_main [i*2+:2]; - // assign dmr_single_mismatch [i] = dmr_error [i*2+:2] != 3'b000; + + 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 ), + + .setback_o ( dmr_setback_q[i] ), + .sw_resynch_req_o ( dmr_resynch_req_o[i] ), + .grp_in_independent_o ( dmr_grp_in_independent[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 (), + .recovery_finished_i () + ); /********************* * DMR Core Checkers * @@ -702,73 +728,17 @@ module HMR_wrap import recovery_pkg::*; #( assign backup_regfile_we_b [i] = backup_regfile_wport_i[i].we_b & ~backup_regfile_error_b [i] & ~dmr_ctrl_core_recover_out [i]; - /**************************** - * Recovery Program Counter * - ****************************/ - recovery_pc #( - .ECCEnabled ( 1 ) - ) RPC ( - // Control Ports - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( '0 ), - .read_enable_i ( dmr_ctrl_pc_read_enable_out [i] ), - .write_enable_i ( ~backup_program_counter_error [i] - & dmr_ctrl_pc_write_enable_out [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_i [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 ( clk_i ), - .rst_ni ( rst_ni ), - .test_en_i ( '0 ), - //Read port A - .raddr_a_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_a ), - .rdata_a_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_a ), - //Read port B - .raddr_b_i ( core_recovery_regfile_wport_out[dmr_core_id(i, 0)].waddr_b ), - .rdata_b_o ( core_recovery_regfile_rdata_out[dmr_core_id(i, 0)].rdata_b ), - //Read port C - .raddr_c_i ( '0 ), - .rdata_c_o ( ), - // Write Port A - .waddr_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_a ), - .wdata_a_i ( backup_regfile_wdata_a [i] ), - .we_a_i ( backup_regfile_we_a [i] ), - // Write Port B - .waddr_b_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_b ), - .wdata_b_i ( backup_regfile_wdata_b [i] ), - .we_b_i ( backup_regfile_we_b [i] ) - ); + end else begin - + assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i]) + : dmr_failure_main[i]; end end - // if (NumDMRLeftover > 0) begin : gen_dmr_leftover_error - // assign dmr_error_main[NumCores-1-:NumDMRLeftover] = '0; - // assign dmr_error_data[NumCores-1-:NumDMRLeftover] = '0; - // assign dmr_error [NumCores-1-:NumDMRLeftover] = '0; - // end end else begin: no_dmr_checkers - // assign dmr_error_main = '0; - // assign dmr_error_data = '0; - // assign dmr_error = '0; 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, @@ -781,6 +751,36 @@ module HMR_wrap import recovery_pkg::*; #( assign top_register_resps[2].ready = 1'b1; end + // RapidRecovery output signals + if (RapidRecovery) begin : gen_rapid_recovery + // TODO: + end else begin : gen_sw_recovery + for (genvar i = 0; i < NumCores; i++) begin : gen_cores + // Temporary disable of RapidRecovery + assign core_debug_resume_o [i] = '0; + + // Setback + assign core_recover_o [i] = '0; + assign core_instr_lock_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 dmr_rf_readback_o [i] = '0; + assign core_regfile_raddr_o [i] = '0; + 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 /***************** @@ -1005,29 +1005,6 @@ module HMR_wrap import recovery_pkg::*; #( *** TMR only *** *****************/ for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs - // Temporary disable of RapidRecovery - assign core_debug_resume_o [i] = '0; - - // Setback - assign core_recover_o [i] = '0; - assign core_instr_lock_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 dmr_rf_readback_o [i] = '0; - assign core_regfile_raddr_o [i] = '0; - 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; - localparam SysCoreIndex = TMRFixed ? i/3 : tmr_core_id(tmr_group_id(i), 0); always_comb begin if (i < NumTMRCores && (TMRFixed || core_in_tmr[i])) begin : tmr_mode @@ -1214,7 +1191,7 @@ module HMR_wrap import recovery_pkg::*; #( // Binding DMR outputs to zero for now assign dmr_failure_o = '0; assign dmr_error_o = '0; - assign dmr_resynch_req_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); @@ -1225,19 +1202,30 @@ module HMR_wrap import recovery_pkg::*; #( 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] + if (RapidRecovery) begin + core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex] & dmr_ctrl_core_clk_en_out[SysGroupId]; + end else begin + core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex]; + end core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex]; core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex]; - core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex] + + if (RapidRecovery) begin + core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex] | dmr_ctrl_core_debug_req_out [SysGroupId]; - core_debug_resume_o [i] = dmr_ctrl_debug_resume_out [SysGroupId]; + end else begin + core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex]; + end core_perf_counters_o[i] = sys_perf_counters_i [SysCoreIndex]; // Setback - core_setback_o [i] = dmr_ctrl_core_setback_out [SysGroupId]; - core_recover_o [i] = dmr_ctrl_core_recover_out [SysGroupId]; + if (RapidRecovery) begin + core_setback_o [i] = dmr_ctrl_core_setback_out [SysGroupId]; + end else begin + core_setback_o [i] = '0; + end // IRQ core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex]; @@ -1248,7 +1236,6 @@ module HMR_wrap import recovery_pkg::*; #( core_instr_r_rdata_o[i] = sys_instr_r_rdata_i [SysCoreIndex]; core_instr_r_valid_o[i] = sys_instr_r_valid_i [SysCoreIndex]; core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; - core_instr_lock_o [i] = dmr_ctrl_core_instr_lock_out [SysGroupId]; // DATA core_data_gnt_o [i] = sys_data_gnt_i [SysCoreIndex]; @@ -1258,22 +1245,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; - // PC - pc_recover_o [i] = dmr_ctrl_pc_read_enable_out [SysCoreIndex]; - recovery_program_counter_o [i] = recovery_program_counter_out [SysCoreIndex]; - recovery_branch_o [i] = recovery_branch_out [SysCoreIndex]; - recovery_branch_addr_o [i] = recovery_branch_addr_out [SysCoreIndex]; - - // RF - dmr_rf_readback_o [i] = regfile_readback_out [SysCoreIndex]; - core_regfile_raddr_o [i] = core_regfile_raddr_out [SysCoreIndex]; - core_recovery_regfile_wport_o[i].we_a = core_recovery_regfile_wport_out[SysCoreIndex].we_a; - core_recovery_regfile_wport_o[i].waddr_a = core_recovery_regfile_wport_out[SysCoreIndex].waddr_a; - core_recovery_regfile_wport_o[i].wdata_a = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_a; - core_recovery_regfile_wport_o[i].we_b = core_recovery_regfile_wport_out[SysCoreIndex].we_b; - core_recovery_regfile_wport_o[i].waddr_b = core_recovery_regfile_wport_out[SysCoreIndex].waddr_b; - core_recovery_regfile_wport_o[i].wdata_b = core_recovery_regfile_rdata_out[SysCoreIndex].rdata_b; - end else begin : gen_independent_mode // CTRL core_core_id_o [i] = sys_core_id_i [i]; @@ -1284,12 +1255,10 @@ module HMR_wrap import recovery_pkg::*; #( core_boot_addr_o [i] = sys_boot_addr_i [i]; core_debug_req_o [i] = sys_debug_req_i [i]; - core_debug_resume_o [i] = '0; core_perf_counters_o[i] = sys_perf_counters_i[i]; // Setback core_setback_o [i] = '0; - core_recover_o [i] = '0; // IRQ core_irq_req_o [i] = sys_irq_req_i [i]; @@ -1300,7 +1269,6 @@ module HMR_wrap import recovery_pkg::*; #( core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; core_instr_err_o [i] = sys_instr_err_i [i]; - core_instr_lock_o [i] = '0; // DATA core_data_gnt_o [i] = sys_data_gnt_i [i]; @@ -1309,22 +1277,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [i]; core_data_r_valid_o [i] = sys_data_r_valid_i [i]; core_data_err_o [i] = sys_data_err_i [i]; - - // PC - pc_recover_o [i] = '0; - recovery_program_counter_o [i] = '0; - recovery_branch_o [i] = '0; - recovery_branch_addr_o [i] = '0; - - // RF - dmr_rf_readback_o [i] = '0; - core_regfile_raddr_o [i] = '0; - 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 // gen_core_inputs diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv new file mode 100644 index 00000000..1ed809d0 --- /dev/null +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -0,0 +1,137 @@ +// 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 recovery_pkg::*; #( + parameter bit InterleaveGrps = 1'b0, + 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, + + // DMR control signals + output logic setback_o, + output logic sw_resynch_req_o, + output logic grp_in_independent_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 +); + + 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; + logic dmr_setback_d, dmr_setback_q; + + assign setback_o = dmr_setback_q; + assign grp_in_independent_o = dmr_red_mode_q == NON_DMR; + + hmr_dmr_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 (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; + + /************************** + * FSM for DMR lockstep * + **************************/ + + always_comb begin : proc_fsm + dmr_setback_d = 1'b0; + dmr_red_mode_d = dmr_red_mode_q; + dmr_incr_mismatches_o = '0; + + case (dmr_red_mode_q) + DMR_RUN: begin + // If error detected, restore + if (dmr_error_i && RapidRecovery) begin + dmr_red_mode_d = DMR_RESTORE; + recovery_request_o = 1'b1; + end + end + + DMR_RESTORE: begin + if (recovery_finished_i) begin + dmr_red_mode_d = DMR_RUN; + end + end + + // Default: do nothing + endcase + + // Logic to switch in and out of DMR + if (!DMRFixed) begin + // 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 + 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; + end + end + // Set DMR mode on external signal that cores are synchronized + if (dmr_red_mode_q == NON_DMR && cores_synch_i) begin + if (dmr_reg2hw.dmr_enable.q == 1'b1) begin + dmr_red_mode_d = DMR_RUN; + 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; + dmr_setback_q <= '0; + end else begin + dmr_red_mode_q <= dmr_red_mode_d; + dmr_setback_q <= dmr_setback_d; + end + end + +endmodule From 95f94afef2e3a5f4b369a142f7135180af78e0e9 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 31 Jan 2023 18:38:30 +0100 Subject: [PATCH 10/72] Add dmr and rapid-recovery configuration registers Start adding rapid_recovery --- Bender.yml | 1 + rtl/HMR/HMR_dmr_regs.hjson | 8 +- rtl/HMR/HMR_regs.hjson | 32 ++- rtl/HMR/HMR_tmr_regs.hjson | 4 + rtl/HMR/HMR_wrap.sv | 372 ++++++++++++++++++++++------- rtl/HMR/doc.html | 33 ++- rtl/HMR/hmr_dmr.h | 3 +- rtl/HMR/hmr_dmr_ctrl.sv | 18 ++ rtl/HMR/hmr_dmr_regs_reg_pkg.sv | 28 ++- rtl/HMR/hmr_dmr_regs_reg_top.sv | 62 +++-- rtl/HMR/hmr_global.h | 11 +- rtl/HMR/hmr_rapid_recovery_ctrl.sv | 140 +++++++++++ rtl/HMR/hmr_registers_reg_pkg.sv | 64 +++-- rtl/HMR/hmr_registers_reg_top.sv | 127 ++++++++-- rtl/HMR/hmr_tmr.h | 3 +- rtl/HMR/hmr_tmr_ctrl.sv | 9 +- rtl/HMR/hmr_tmr_regs_reg_pkg.sv | 16 +- rtl/HMR/hmr_tmr_regs_reg_top.sv | 39 ++- 18 files changed, 809 insertions(+), 161 deletions(-) create mode 100644 rtl/HMR/hmr_rapid_recovery_ctrl.sv diff --git a/Bender.yml b/Bender.yml index 3ee5f36c..5c1bb114 100644 --- a/Bender.yml +++ b/Bender.yml @@ -99,6 +99,7 @@ sources: - rtl/HMR/DMR_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 diff --git a/rtl/HMR/HMR_dmr_regs.hjson b/rtl/HMR/HMR_dmr_regs.hjson index dcf54459..682c4b5b 100644 --- a/rtl/HMR/HMR_dmr_regs.hjson +++ b/rtl/HMR/HMR_dmr_regs.hjson @@ -31,8 +31,12 @@ hwqe: "true", fields: [ { bits: "0", - name: "todo", - desc: "TODO" + 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)." } ] }, diff --git a/rtl/HMR/HMR_regs.hjson b/rtl/HMR/HMR_regs.hjson index 30b98a8c..fb02cebc 100644 --- a/rtl/HMR/HMR_regs.hjson +++ b/rtl/HMR/HMR_regs.hjson @@ -40,6 +40,10 @@ { bits: "2", name: "triple", desc: "Triple Modular Redundancy (TMR) is available." + }, + { bits: "8", + name: "rapid_recovery", + desc: "Rapid Recovery is available." } ] }, @@ -83,13 +87,23 @@ } ] }, - # { name: "DMR_config", - # desc: "DMR configuration bits." - # swaccess: "rw", - # hwaccess: "hrw", - # hwqe: "true", - # fields: [] - # }, + { 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", @@ -113,6 +127,10 @@ 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 index ec01dad2..e01825b9 100644 --- a/rtl/HMR/HMR_tmr_regs.hjson +++ b/rtl/HMR/HMR_tmr_regs.hjson @@ -46,6 +46,10 @@ 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 index b2f57935..81ac22cf 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -68,22 +68,25 @@ module HMR_wrap import recovery_pkg::*; #( 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_rf_readback_o, input logic [NumDMRGroups-1:0] dmr_cores_synch_i, // 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, + 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_raddr_t [ NumSysCores-1:0] core_regfile_raddr_o, - output regfile_write_t [ NumSysCores-1:0] core_recovery_regfile_wport_o, - // TODO other required signals + input regfile_write_t [NumCores-1:0] backup_regfile_wport_i, + output regfile_raddr_t [NumCores-1:0] core_regfile_raddr_o, + 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 , @@ -124,9 +127,6 @@ module HMR_wrap import recovery_pkg::*; #( input logic [NumSysCores-1:0][NumExtPerf-1:0] sys_perf_counters_i, // Ports connecting to the cores - output logic [ NumCores-1:0] core_setback_o , - output logic [ NumCores-1:0] core_recover_o , - output logic [ NumCores-1:0][ 3:0] core_core_id_o , output logic [ NumCores-1:0][ 5:0] core_cluster_id_o , @@ -145,11 +145,9 @@ module HMR_wrap import recovery_pkg::*; #( 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_lock_o , output logic [ NumCores-1:0] core_instr_err_o , output logic [ NumCores-1:0] core_debug_req_o , - output logic [ NumCores-1:0] core_debug_resume_o , input logic [ NumCores-1:0] core_debug_halted_i , input logic [ NumCores-1:0] core_data_req_i , @@ -180,6 +178,11 @@ module HMR_wrap import recovery_pkg::*; #( else return (group_id * 3) + core_offset; endfunction + function int tmr_shared_id (int group_id); + if (InterleaveGrps) return group_id; + else return group_id + group_id/2; + endfunction + function int dmr_group_id (int core_id); if (InterleaveGrps) return core_id % NumDMRGroups; else return (core_id/2); @@ -190,6 +193,10 @@ module HMR_wrap import recovery_pkg::*; #( else return (group_id * 2) + core_offset; endfunction + function int dmr_shared_id(int group_id); + return group_id; + endfunction + if (TMRFixed && DMRFixed) $fatal(1, "Cannot fix both TMR and DMR!"); localparam int unsigned CtrlConcatWidth = 1 + 1 + 5 + 1 + 32 + 1; @@ -199,6 +206,8 @@ module HMR_wrap import recovery_pkg::*; #( localparam int unsigned MainConcatWidth = SeparateData ? CtrlConcatWidth : CtrlConcatWidth + DataConcatWidth; + let max(a,b) = (a > b) ? a : b; + localparam int unsigned NumBackupRegfiles = max(DMRSupported || DMRFixed ? NumDMRGroups : 0, TMRSupported || TMRFixed ? NumTMRGroups : 0); localparam int unsigned RFAddrWidth = 6; logic [ NumCores-1:0][MainConcatWidth-1:0] main_concat_in; @@ -241,37 +250,39 @@ module HMR_wrap import recovery_pkg::*; #( 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][ 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 [NumDMRGroups-1:0] backup_branch_int, - recovery_branch_out, - backup_program_counter_error, - dmr_ctrl_pc_read_enable_out, - dmr_ctrl_pc_write_enable_out, - dmr_ctrl_core_clk_en_out, - backup_regfile_we_a, - backup_regfile_we_b, - backup_regfile_error_a, - backup_regfile_error_b, - backup_branch_error, - backup_branch_addr_error, - regfile_readback_out, - dmr_ctrl_core_rstn_out, - dmr_ctrl_core_debug_req_out, - dmr_ctrl_core_debug_halted_in, - dmr_ctrl_core_instr_lock_out, - dmr_ctrl_core_setback_out, - dmr_ctrl_core_recover_out, - dmr_ctrl_debug_resume_out; - logic intruder_lock; - - regfile_raddr_t [NumDMRGroups-1:0] core_regfile_raddr_out; - regfile_rdata_t [NumDMRGroups-1:0] core_recovery_regfile_rdata_out; - regfile_write_t [NumDMRGroups-1:0] backup_regfile_wport_in, + + logic [ NumDMRGroups-1:0][ DataWidth-1:0] dmr_backup_program_counter; + logic [ NumTMRGroups-1:0][ DataWidth-1:0] tmr_backup_program_counter; + 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, + recovery_branch_out, + backup_program_counter_error, + backup_pc_enable_out, // dmr_ctrl_pc_read_enable_out, + recovery_pc_enable_out, // dmr_ctrl_pc_write_enable_out, + // dmr_ctrl_core_clk_en_out, + backup_regfile_we_a, + backup_regfile_we_b, + backup_regfile_error_a, + backup_regfile_error_b, + backup_branch_error, + backup_branch_addr_error, + // regfile_readback_out, + // dmr_ctrl_core_rstn_out, + recovery_debug_req_out, // dmr_ctrl_core_debug_req_out, + recovery_debug_halted_in, // dmr_ctrl_core_debug_halted_in, + recovery_instr_lock_out, // dmr_ctrl_core_instr_lock_out, + recovery_setback_out, // dmr_ctrl_core_setback_out, + recovery_trigger_out, // dmr_ctrl_core_recover_out, // TODO: for regfile only?!? + recovery_debug_resume_out; // dmr_ctrl_debug_resume_out; + + 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] backup_regfile_wport_in, core_recovery_regfile_wport_out; for (genvar i = 0; i < NumCores; i++) begin : gen_concat @@ -296,19 +307,25 @@ module HMR_wrap import recovery_pkg::*; #( 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] dmr_setback_q; logic [NumDMRGroups-1:0] dmr_grp_in_independent; + logic [NumDMRGroups-1:0] dmr_rapid_recovery_en; logic [NumTMRGroups-1:0] tmr_setback_q; logic [NumTMRGroups-1:0] tmr_grp_in_independent; + logic [NumTMRGroups-1:0] tmr_rapid_recovery_en; for (genvar i = 0; i < NumCores; i++) begin 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_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; @@ -354,19 +371,26 @@ module HMR_wrap import recovery_pkg::*; #( 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 hmr_hw2reg.cores_en.d = '0; hmr_hw2reg.cores_en.d = core_en_as_master; - end - assign hmr_hw2reg.dmr_enable.d = '0; - assign hmr_hw2reg.tmr_enable.d = '0; + 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 @@ -473,12 +497,15 @@ module HMR_wrap import recovery_pkg::*; #( .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] ), .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] ), @@ -488,9 +515,11 @@ module HMR_wrap import recovery_pkg::*; #( ); 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]; + 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 #( @@ -555,12 +584,14 @@ module HMR_wrap import recovery_pkg::*; #( /************************************************************ ******************** DMR Voters and Regs ******************* ************************************************************/ - for (genvar i = 0; i < NumCores; i++) begin + for (genvar i = 0; i < NumBackupRegfiles; i++) begin + // TODO fix assignment assign backup_regfile_wport_in [i] = backup_regfile_wport_i [dmr_core_id(dmr_group_id(i), 0)]; end for (genvar i = 0; i < NumDMRGroups; i++) begin - assign dmr_ctrl_core_debug_halted_in [i] = core_debug_halted_i [dmr_core_id(dmr_group_id(i), 0)] + // TODO fix assignment + assign recovery_debug_halted_in [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 @@ -608,23 +639,28 @@ module HMR_wrap import recovery_pkg::*; #( .clk_i, .rst_ni, - .reg_req_i ( dmr_register_reqs[i] ), - .reg_resp_o ( dmr_register_resps[i] ), + .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 ), + .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] ), - .grp_in_independent_o ( dmr_grp_in_independent[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] ), + .setback_o ( dmr_setback_q[i] ), + .sw_resynch_req_o ( dmr_resynch_req_o[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] ), + .fetch_en_i ( sys_fetch_en_i[dmr_core_id(i, 0)] ), + .cores_synch_i ( dmr_cores_synch_i[i] ), - .recovery_request_o (), - .recovery_finished_i () + .recovery_request_o (), + .recovery_finished_i () ); /********************* @@ -665,6 +701,14 @@ module HMR_wrap import recovery_pkg::*; #( if (RapidRecovery) begin + assign dmr_failure [i] = (dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i]) + : dmr_failure_main[i]) | + backup_program_counter_error[i] | + backup_branch_error [i] | + backup_branch_addr_error [i] | + backup_regfile_error_a [i] | + backup_regfile_error_b [i]; + /****************** * DMR PC Checker * ******************/ @@ -673,7 +717,7 @@ module HMR_wrap import recovery_pkg::*; #( ) dmr_pc_checker ( .inp_a_i ( backup_program_counter_i[dmr_core_id(i, 0)] ), .inp_b_i ( backup_program_counter_i[dmr_core_id(i, 1)] ), - .check_o ( backup_program_counter_int [i] ), + .check_o ( dmr_backup_program_counter[i] ), .error_o ( backup_program_counter_error [i] ) ); @@ -724,10 +768,10 @@ module HMR_wrap import recovery_pkg::*; #( assign backup_regfile_we_a [i] = backup_regfile_wport_i[i].we_a & ~backup_regfile_error_a [i] - & ~dmr_ctrl_core_recover_out [i]; + & ~recovery_trigger_out [i]; assign backup_regfile_we_b [i] = backup_regfile_wport_i[i].we_b & ~backup_regfile_error_b [i] - & ~dmr_ctrl_core_recover_out [i]; + & ~recovery_trigger_out [i]; end else begin assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i]) @@ -753,10 +797,173 @@ module HMR_wrap import recovery_pkg::*; #( // RapidRecovery output signals if (RapidRecovery) begin : gen_rapid_recovery + for (genvar i = 0; i < NumBackupRegfiles; i++) begin + hmr_rapid_recovery_ctrl #( + .RFAddrWidth( RFAddrWidth ) + ) i_rapid_recovery_ctrl ( + .clk_i, + .rst_ni, + .start_recovery_i (), + .recovery_finished_o (), + .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_pc_enable_o ( backup_pc_enable_out [i] ), + .recover_pc_enable_o ( recovery_pc_enable_out [i] ), + .recover_rf_enable_o ( recovery_trigger_out [i] ) + ); + + /**************************** + * Recovery Program Counter * + ****************************/ + recovery_pc #( + .ECCEnabled ( 1 ) + ) RPC ( + // Control Ports + .clk_i, + .rst_ni, + .clear_i ( '0 ), + .read_enable_i ( backup_pc_enable_out [i] ), + .write_enable_i ( ~backup_program_counter_error [i] + & recovery_pc_enable_out [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_i [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_wport_i[dmr_core_id(i, 0)].waddr_a ), + .wdata_a_i ( backup_regfile_wdata_a [i] ), + .we_a_i ( backup_regfile_we_a [i] ), + // Write Port B + .waddr_b_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_b ), + .wdata_b_i ( backup_regfile_wdata_b [i] ), + .we_b_i ( backup_regfile_we_b [i] ) + ); + + end + + + always_comb begin + backup_program_counter_int = '0; + + 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_program_counter_int[dmr_shared_id(i)] = dmr_backup_program_counter[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 + backup_program_counter_int[tmr_shared_id(i)] = tmr_backup_program_counter[i]; + 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))]; + + // PC + pc_recover_o [i] = backup_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_regfile_raddr_o [i] = core_regfile_raddr_out [dmr_shared_id(dmr_group_id(i))]; + 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))]; + + // PC + pc_recover_o [i] = backup_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; + + // 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_regfile_raddr_o [i] = '0; + 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 + // TODO: end else begin : gen_sw_recovery for (genvar i = 0; i < NumCores; i++) begin : gen_cores - // Temporary disable of RapidRecovery + // Disable RapidRecovery assign core_debug_resume_o [i] = '0; // Setback @@ -770,7 +977,6 @@ module HMR_wrap import recovery_pkg::*; #( assign recovery_branch_addr_o [i] = '0; // RF - assign dmr_rf_readback_o [i] = '0; assign core_regfile_raddr_o [i] = '0; assign core_recovery_regfile_wport_o[i].we_a = '0; assign core_recovery_regfile_wport_o[i].waddr_a = '0; @@ -1202,19 +1408,19 @@ module HMR_wrap import recovery_pkg::*; #( core_core_id_o [i] = sys_core_id_i [SysCoreIndex]; core_cluster_id_o [i] = sys_cluster_id_i [SysCoreIndex]; - if (RapidRecovery) begin - core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex] - & dmr_ctrl_core_clk_en_out[SysGroupId]; - end else begin + // if (RapidRecovery) begin + // core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex] + // & dmr_ctrl_core_clk_en_out[SysGroupId]; + // end else begin core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex]; - end + // end 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] - | dmr_ctrl_core_debug_req_out [SysGroupId]; + | recovery_debug_req_out [SysGroupId]; end else begin core_debug_req_o [i] = sys_debug_req_i [SysCoreIndex]; end @@ -1222,7 +1428,7 @@ module HMR_wrap import recovery_pkg::*; #( // Setback if (RapidRecovery) begin - core_setback_o [i] = dmr_ctrl_core_setback_out [SysGroupId]; + core_setback_o [i] = recovery_setback_out [SysGroupId]; end else begin core_setback_o [i] = '0; end diff --git a/rtl/HMR/doc.html b/rtl/HMR/doc.html index ee0cb44f..ab3898ef 100644 --- a/rtl/HMR/doc.html +++ b/rtl/HMR/doc.html @@ -3,17 +3,19 @@
HMR_registers.avail_config @ 0x0

Available Configurations from implemented hardware.

-
Reset default = 0x0, mask 0x7
+
Reset default = 0x0, mask 0x107
- + + +
31302928272625242322212019181716
 
1514131211109876543210
 
1514131211109876543210
 rapid_recovery  triple dual independent
-BitsTypeResetNameDescription0roxindependent

Independent mode is available.

1roxdual

Dual Modular Redundancy (DMR) is available.

2roxtriple

Triple Modular Redundancy (TMR) is available.

+BitsTypeResetNameDescription0roxindependent

Independent mode is available.

1roxdual

Dual Modular Redundancy (DMR) is available.

2roxtriple

Triple Modular Redundancy (TMR) is available.

7:3Reserved8roxrapid_recovery

Rapid Recovery is available.


@@ -60,21 +62,38 @@
BitsTypeResetNameDescription3:0rw0x0TMR_enable

TMR configuration enable.


+ + + + + +
+
HMR_registers.DMR_config @ 0x10
+

DMR configuration bits.

+
Reset default = 0x0, mask 0x3
+
+ + + + +
31302928272625242322212019181716
 
1514131211109876543210
 force_recoveryrapid_recovery
BitsTypeResetNameDescription
0rwxrapid_recovery

Enable rapid recovery using an additional register file.

1rwxforce_recovery

Forces recovery routine (if rapid_recovery is available).

+
-
-
HMR_registers.TMR_config @ 0x10
+
HMR_registers.TMR_config @ 0x14

TMR configuration bits.

-
Reset default = 0x6, mask 0xf
+
Reset default = 0x6, mask 0x1f
- + +
31302928272625242322212019181716
 
1514131211109876543210
 
1514131211109876543210
  force_resynchrapid_recovery reload_setback setback delay_resynch
BitsTypeResetNameDescription
0rw0x0delay_resynch

Enable wait-for-restoration

1rw0x1setback

Enable setback (synchronous reset) during re-synch.

2rw0x1reload_setback

Enable setback on mismatch during reload section of re-synch (only possible with setback)

3rw0x0force_resynch

Forces a resynchronization routine

+BitsTypeResetNameDescription0rw0x0delay_resynch

Enable wait-for-restoration

1rw0x1setback

Enable setback (synchronous reset) during re-synch.

2rw0x1reload_setback

Enable setback on mismatch during reload section of re-synch (only possible with setback)

3rwxrapid_recovery

Enable rapid recovery using additional register file.

4rw0x0force_resynch

Forces a resynchronization routine


diff --git a/rtl/HMR/hmr_dmr.h b/rtl/HMR/hmr_dmr.h index a97a51bc..d197bcb3 100644 --- a/rtl/HMR/hmr_dmr.h +++ b/rtl/HMR/hmr_dmr.h @@ -15,7 +15,8 @@ extern "C" { // DMR configuration bits. #define HMR_DMR_REGS_DMR_CONFIG_REG_OFFSET 0x4 -#define HMR_DMR_REGS_DMR_CONFIG_TODO_BIT 0 +#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 diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 1ed809d0..85ec8771 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -29,11 +29,16 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( // 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 setback_o, output logic sw_resynch_req_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, @@ -54,6 +59,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( assign setback_o = dmr_setback_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; hmr_dmr_regs_reg_top #( .reg_req_t(reg_req_t), @@ -71,6 +77,9 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( // 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; + assign dmr_hw2reg.dmr_config.rapid_recovery.d = rapid_recovery_q_i; + assign dmr_hw2reg.dmr_config.force_recovery.d = force_recovery_qe_i ? force_recovery_q_i : 1'b0; /************************** * FSM for DMR lockstep * @@ -80,9 +89,18 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( dmr_setback_d = 1'b0; dmr_red_mode_d = dmr_red_mode_q; dmr_incr_mismatches_o = '0; + recovery_request_o = 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) 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) begin dmr_red_mode_d = DMR_RESTORE; diff --git a/rtl/HMR/hmr_dmr_regs_reg_pkg.sv b/rtl/HMR/hmr_dmr_regs_reg_pkg.sv index b568f175..95199d4c 100644 --- a/rtl/HMR/hmr_dmr_regs_reg_pkg.sv +++ b/rtl/HMR/hmr_dmr_regs_reg_pkg.sv @@ -19,8 +19,14 @@ package hmr_dmr_regs_reg_pkg; } hmr_dmr_regs_reg2hw_dmr_enable_reg_t; typedef struct packed { - logic q; - logic qe; + 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 { @@ -34,8 +40,14 @@ package hmr_dmr_regs_reg_pkg; } hmr_dmr_regs_hw2reg_dmr_enable_reg_t; typedef struct packed { - logic d; - logic de; + 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 { @@ -45,15 +57,15 @@ package hmr_dmr_regs_reg_pkg; // Register -> HW type typedef struct packed { - hmr_dmr_regs_reg2hw_dmr_enable_reg_t dmr_enable; // [36:35] - hmr_dmr_regs_reg2hw_dmr_config_reg_t dmr_config; // [34:33] + 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; // [36:35] - hmr_dmr_regs_hw2reg_dmr_config_reg_t dmr_config; // [34:33] + 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; diff --git a/rtl/HMR/hmr_dmr_regs_reg_top.sv b/rtl/HMR/hmr_dmr_regs_reg_top.sv index 80722d6b..209d9348 100644 --- a/rtl/HMR/hmr_dmr_regs_reg_top.sv +++ b/rtl/HMR/hmr_dmr_regs_reg_top.sv @@ -71,9 +71,12 @@ module hmr_dmr_regs_reg_top #( logic dmr_enable_qs; logic dmr_enable_wd; logic dmr_enable_we; - logic dmr_config_qs; - logic dmr_config_wd; - logic dmr_config_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; @@ -108,28 +111,55 @@ module hmr_dmr_regs_reg_top #( // R[dmr_config]: V(False) + // F[rapid_recovery]: 0:0 prim_subreg #( .DW (1), .SWACCESS("RW"), .RESVAL (1'h0) - ) u_dmr_config ( + ) u_dmr_config_rapid_recovery ( .clk_i (clk_i ), .rst_ni (rst_ni ), // from register interface - .we (dmr_config_we), - .wd (dmr_config_wd), + .we (dmr_config_rapid_recovery_we), + .wd (dmr_config_rapid_recovery_wd), // from internal hardware - .de (hw2reg.dmr_config.de), - .d (hw2reg.dmr_config.d ), + .de (hw2reg.dmr_config.rapid_recovery.de), + .d (hw2reg.dmr_config.rapid_recovery.d ), // to internal hardware - .qe (reg2hw.dmr_config.qe), - .q (reg2hw.dmr_config.q ), + .qe (reg2hw.dmr_config.rapid_recovery.qe), + .q (reg2hw.dmr_config.rapid_recovery.q ), // to register interface (read) - .qs (dmr_config_qs) + .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) ); @@ -183,8 +213,11 @@ module hmr_dmr_regs_reg_top #( assign dmr_enable_we = addr_hit[0] & reg_we & !reg_error; assign dmr_enable_wd = reg_wdata[0]; - assign dmr_config_we = addr_hit[1] & reg_we & !reg_error; - assign dmr_config_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]; @@ -198,7 +231,8 @@ module hmr_dmr_regs_reg_top #( end addr_hit[1]: begin - reg_rdata_next[0] = dmr_config_qs; + reg_rdata_next[0] = dmr_config_rapid_recovery_qs; + reg_rdata_next[1] = dmr_config_force_recovery_qs; end addr_hit[2]: begin diff --git a/rtl/HMR/hmr_global.h b/rtl/HMR/hmr_global.h index 6a687f15..ef710129 100644 --- a/rtl/HMR/hmr_global.h +++ b/rtl/HMR/hmr_global.h @@ -20,6 +20,7 @@ extern "C" { #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 @@ -42,12 +43,18 @@ extern "C" { #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 0x10 +#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_FORCE_RESYNCH_BIT 3 +#define HMR_REGISTERS_TMR_CONFIG_RAPID_RECOVERY_BIT 3 +#define HMR_REGISTERS_TMR_CONFIG_FORCE_RESYNCH_BIT 4 #ifdef __cplusplus } // extern "C" diff --git a/rtl/HMR/hmr_rapid_recovery_ctrl.sv b/rtl/HMR/hmr_rapid_recovery_ctrl.sv new file mode 100644 index 00000000..5f409733 --- /dev/null +++ b/rtl/HMR/hmr_rapid_recovery_ctrl.sv @@ -0,0 +1,140 @@ +// 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 recovery_pkg::*; #( + parameter int unsigned RFAddrWidth = 6 +) ( + 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_pc_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 backup_pc_enable_d, backup_pc_enable_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 backup_pc_enable_o = backup_pc_enable_q; + assign setback_o = setback_q; + + always_comb begin + rec_mode_d = rec_mode_q; + instr_lock_d = instr_lock_q; + backup_pc_enable_d = backup_pc_enable_q; + setback_d = 1'b0; + debug_req_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 + // If requested start the routine in the reset state + if (start_recovery_i) begin + 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; + // Disable reading for the backup PC + backup_pc_enable_d = 1'b0; + // 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 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; + backup_pc_enable_d = 1'b1; + 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; + backup_pc_enable_q <= 1'b1; + setback_q <= 1'b0; + end else begin + instr_lock_q <= instr_lock_d; + rec_mode_q <= rec_mode_d; + backup_pc_enable_q <= backup_pc_enable_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 index 3858c81d..1c590cce 100644 --- a/rtl/HMR/hmr_registers_reg_pkg.sv +++ b/rtl/HMR/hmr_registers_reg_pkg.sv @@ -28,6 +28,17 @@ package hmr_registers_reg_pkg; 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; @@ -41,6 +52,10 @@ package hmr_registers_reg_pkg; logic q; logic qe; } reload_setback; + struct packed { + logic q; + logic qe; + } rapid_recovery; struct packed { logic q; logic qe; @@ -57,6 +72,9 @@ package hmr_registers_reg_pkg; struct packed { logic d; } triple; + struct packed { + logic d; + } rapid_recovery; } hmr_registers_hw2reg_avail_config_reg_t; typedef struct packed { @@ -71,6 +89,15 @@ package hmr_registers_reg_pkg; 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; @@ -81,6 +108,9 @@ package hmr_registers_reg_pkg; struct packed { logic d; } reload_setback; + struct packed { + logic d; + } rapid_recovery; struct packed { logic d; } force_resynch; @@ -88,18 +118,20 @@ package hmr_registers_reg_pkg; // Register -> HW type typedef struct packed { - hmr_registers_reg2hw_dmr_enable_reg_t dmr_enable; // [19:13] - hmr_registers_reg2hw_tmr_enable_reg_t tmr_enable; // [12:8] - hmr_registers_reg2hw_tmr_config_reg_t tmr_config; // [7:0] + 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; // [28:26] - hmr_registers_hw2reg_cores_en_reg_t cores_en; // [25:14] - hmr_registers_hw2reg_dmr_enable_reg_t dmr_enable; // [13:8] - hmr_registers_hw2reg_tmr_enable_reg_t tmr_enable; // [7:4] - hmr_registers_hw2reg_tmr_config_reg_t tmr_config; // [3:0] + 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 @@ -107,16 +139,18 @@ package hmr_registers_reg_pkg; 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_TMR_CONFIG_OFFSET = 5'h 10; + 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 [2:0] HMR_REGISTERS_AVAIL_CONFIG_RESVAL = 3'h 0; + 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 [3:0] HMR_REGISTERS_TMR_CONFIG_RESVAL = 4'h 6; + 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; @@ -128,16 +162,18 @@ package hmr_registers_reg_pkg; 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 [5] = '{ - 4'b 0001, // index[0] HMR_REGISTERS_AVAIL_CONFIG + 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_TMR_CONFIG + 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 index e2649082..9769fed7 100644 --- a/rtl/HMR/hmr_registers_reg_top.sv +++ b/rtl/HMR/hmr_registers_reg_top.sv @@ -74,6 +74,8 @@ module hmr_registers_reg_top #( 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; @@ -84,6 +86,14 @@ module hmr_registers_reg_top #( 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; @@ -96,6 +106,10 @@ module hmr_registers_reg_top #( 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; @@ -149,6 +163,21 @@ module hmr_registers_reg_top #( ); + // 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 #( @@ -197,6 +226,38 @@ module hmr_registers_reg_top #( ); + // 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 @@ -244,7 +305,22 @@ module hmr_registers_reg_top #( ); - // F[force_resynch]: 3:3 + // 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 ( @@ -261,14 +337,15 @@ module hmr_registers_reg_top #( - logic [4:0] addr_hit; + 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_TMR_CONFIG_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 ; @@ -280,7 +357,8 @@ module hmr_registers_reg_top #( (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[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; @@ -289,6 +367,8 @@ module hmr_registers_reg_top #( 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; @@ -299,21 +379,33 @@ module hmr_registers_reg_top #( assign tmr_enable_wd = reg_wdata[3:0]; assign tmr_enable_re = addr_hit[3] & reg_re & !reg_error; - assign tmr_config_delay_resynch_we = addr_hit[4] & reg_we & !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[4] & reg_re & !reg_error; + assign tmr_config_delay_resynch_re = addr_hit[5] & reg_re & !reg_error; - assign tmr_config_setback_we = addr_hit[4] & reg_we & !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[4] & reg_re & !reg_error; + assign tmr_config_setback_re = addr_hit[5] & reg_re & !reg_error; - assign tmr_config_reload_setback_we = addr_hit[4] & reg_we & !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[4] & reg_re & !reg_error; + 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[4] & reg_we & !reg_error; - assign tmr_config_force_resynch_wd = reg_wdata[3]; - assign tmr_config_force_resynch_re = addr_hit[4] & 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 @@ -323,6 +415,7 @@ module hmr_registers_reg_top #( 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 @@ -338,10 +431,16 @@ module hmr_registers_reg_top #( 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_force_resynch_qs; + reg_rdata_next[3] = tmr_config_rapid_recovery_qs; + reg_rdata_next[4] = tmr_config_force_resynch_qs; end default: begin diff --git a/rtl/HMR/hmr_tmr.h b/rtl/HMR/hmr_tmr.h index 9751e30d..2058c9e6 100644 --- a/rtl/HMR/hmr_tmr.h +++ b/rtl/HMR/hmr_tmr.h @@ -18,7 +18,8 @@ extern "C" { #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_FORCE_RESYNCH_BIT 3 +#define HMR_TMR_REGS_TMR_CONFIG_RAPID_RECOVERY_BIT 3 +#define HMR_TMR_REGS_TMR_CONFIG_FORCE_RESYNCH_BIT 4 // Stack Pointer storage register #define HMR_TMR_REGS_SP_STORE_REG_OFFSET 0x8 diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 0244fb2f..11e0b27d 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -14,6 +14,7 @@ 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 ) ( @@ -34,6 +35,8 @@ module hmr_tmr_ctrl #( 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, @@ -41,6 +44,7 @@ module hmr_tmr_ctrl #( output logic setback_o, output logic sw_resynch_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, @@ -61,6 +65,7 @@ module hmr_tmr_ctrl #( assign setback_o = tmr_setback_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; hmr_tmr_regs_reg_top #( .reg_req_t(reg_req_t), @@ -84,6 +89,8 @@ module hmr_tmr_ctrl #( 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; /************************** @@ -94,7 +101,7 @@ module hmr_tmr_ctrl #( tmr_red_mode_d = tmr_red_mode_q; tmr_incr_mismatches_o = '0; - tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; + tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; case (tmr_red_mode_q) TMR_RUN: begin diff --git a/rtl/HMR/hmr_tmr_regs_reg_pkg.sv b/rtl/HMR/hmr_tmr_regs_reg_pkg.sv index 0643b9c0..148055e7 100644 --- a/rtl/HMR/hmr_tmr_regs_reg_pkg.sv +++ b/rtl/HMR/hmr_tmr_regs_reg_pkg.sv @@ -31,6 +31,10 @@ package hmr_tmr_regs_reg_pkg; logic q; logic qe; } reload_setback; + struct packed { + logic q; + logic qe; + } rapid_recovery; struct packed { logic q; logic qe; @@ -60,6 +64,10 @@ package hmr_tmr_regs_reg_pkg; logic d; logic de; } reload_setback; + struct packed { + logic d; + logic de; + } rapid_recovery; struct packed { logic d; logic de; @@ -73,15 +81,15 @@ package hmr_tmr_regs_reg_pkg; // Register -> HW type typedef struct packed { - hmr_tmr_regs_reg2hw_tmr_enable_reg_t tmr_enable; // [42:41] - hmr_tmr_regs_reg2hw_tmr_config_reg_t tmr_config; // [40:33] + hmr_tmr_regs_reg2hw_tmr_enable_reg_t tmr_enable; // [44:43] + hmr_tmr_regs_reg2hw_tmr_config_reg_t tmr_config; // [42:33] hmr_tmr_regs_reg2hw_sp_store_reg_t sp_store; // [32:0] } hmr_tmr_regs_reg2hw_t; // HW -> register type typedef struct packed { - hmr_tmr_regs_hw2reg_tmr_enable_reg_t tmr_enable; // [42:41] - hmr_tmr_regs_hw2reg_tmr_config_reg_t tmr_config; // [40:33] + hmr_tmr_regs_hw2reg_tmr_enable_reg_t tmr_enable; // [44:43] + hmr_tmr_regs_hw2reg_tmr_config_reg_t tmr_config; // [42:33] hmr_tmr_regs_hw2reg_sp_store_reg_t sp_store; // [32:0] } hmr_tmr_regs_hw2reg_t; diff --git a/rtl/HMR/hmr_tmr_regs_reg_top.sv b/rtl/HMR/hmr_tmr_regs_reg_top.sv index 25879e1c..666d010a 100644 --- a/rtl/HMR/hmr_tmr_regs_reg_top.sv +++ b/rtl/HMR/hmr_tmr_regs_reg_top.sv @@ -80,6 +80,9 @@ module hmr_tmr_regs_reg_top #( 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; @@ -195,7 +198,33 @@ module hmr_tmr_regs_reg_top #( ); - // F[force_resynch]: 3:3 + // 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"), @@ -280,8 +309,11 @@ module hmr_tmr_regs_reg_top #( 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[3]; + assign tmr_config_force_resynch_wd = reg_wdata[4]; assign sp_store_we = addr_hit[2] & reg_we & !reg_error; assign sp_store_wd = reg_wdata[31:0]; @@ -298,7 +330,8 @@ module hmr_tmr_regs_reg_top #( 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_force_resynch_qs; + reg_rdata_next[3] = tmr_config_rapid_recovery_qs; + reg_rdata_next[4] = tmr_config_force_resynch_qs; end addr_hit[2]: begin From ea0358283d1d1e5ae0b981e48ac7027bca41055a Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 1 Feb 2023 08:43:17 +0100 Subject: [PATCH 11/72] Update header file generation --- Makefile | 54 ++++++++++++- rtl/HMR/hmr_core.h | 25 ------ rtl/HMR/hmr_dmr.h | 28 ------- rtl/HMR/hmr_global.h | 63 --------------- rtl/HMR/hmr_tmr.h | 31 -------- rtl/HMR/hmr_v1.h | 183 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 233 insertions(+), 151 deletions(-) delete mode 100644 rtl/HMR/hmr_core.h delete mode 100644 rtl/HMR/hmr_dmr.h delete mode 100644 rtl/HMR/hmr_global.h delete mode 100644 rtl/HMR/hmr_tmr.h create mode 100644 rtl/HMR/hmr_v1.h diff --git a/Makefile b/Makefile index 97df330e..44cdf475 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,46 @@ 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 0x008 +#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 @@ -47,14 +87,20 @@ gen_TCLS: 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) -D > $(TARGET_DIR_HMR)/hmr_global.h 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_core) -D > $(TARGET_DIR_HMR)/hmr_core.h python $(REG_TOOL) $(HJSON_HMR_dmr) -t $(TARGET_DIR_HMR) -r - python $(REG_TOOL) $(HJSON_HMR_dmr) -D > $(TARGET_DIR_HMR)/hmr_dmr.h python $(REG_TOOL) $(HJSON_HMR_tmr) -t $(TARGET_DIR_HMR) -r - python $(REG_TOOL) $(HJSON_HMR_tmr) -D > $(TARGET_DIR_HMR)/hmr_tmr.h + + @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 diff --git a/rtl/HMR/hmr_core.h b/rtl/HMR/hmr_core.h deleted file mode 100644 index 58d7d0c5..00000000 --- a/rtl/HMR/hmr_core.h +++ /dev/null @@ -1,25 +0,0 @@ -// 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 - -#ifdef __cplusplus -} // extern "C" -#endif -#endif // _HMR_CORE_REGS_REG_DEFS_ -// End generated register defines for HMR_core_regs \ No newline at end of file diff --git a/rtl/HMR/hmr_dmr.h b/rtl/HMR/hmr_dmr.h deleted file mode 100644 index d197bcb3..00000000 --- a/rtl/HMR/hmr_dmr.h +++ /dev/null @@ -1,28 +0,0 @@ -// 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_TMR_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 \ No newline at end of file diff --git a/rtl/HMR/hmr_global.h b/rtl/HMR/hmr_global.h deleted file mode 100644 index ef710129..00000000 --- a/rtl/HMR/hmr_global.h +++ /dev/null @@ -1,63 +0,0 @@ -// 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 \ No newline at end of file diff --git a/rtl/HMR/hmr_tmr.h b/rtl/HMR/hmr_tmr.h deleted file mode 100644 index 2058c9e6..00000000 --- a/rtl/HMR/hmr_tmr.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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 - -// Stack Pointer storage register -#define HMR_TMR_REGS_SP_STORE_REG_OFFSET 0x8 - -#ifdef __cplusplus -} // extern "C" -#endif -#endif // _HMR_TMR_REGS_REG_DEFS_ -// End generated register defines for HMR_tmr_regs \ No newline at end of file diff --git a/rtl/HMR/hmr_v1.h b/rtl/HMR/hmr_v1.h new file mode 100644 index 00000000..92ed91bb --- /dev/null +++ b/rtl/HMR/hmr_v1.h @@ -0,0 +1,183 @@ +/* + * 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 0x008 +#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 + +#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_TMR_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 + +// Stack Pointer storage register +#define HMR_TMR_REGS_SP_STORE_REG_OFFSET 0x8 + +#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__ From f6170d3636076d3d885ade37f23732759a125413 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 1 Feb 2023 11:32:22 +0100 Subject: [PATCH 12/72] Fix configurable rapid-recovery assignments --- Makefile | 2 + rtl/HMR/HMR_wrap.sv | 285 ++++++++++++++++++++++++++------------------ 2 files changed, 174 insertions(+), 113 deletions(-) diff --git a/Makefile b/Makefile index 44cdf475..5afec358 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,8 @@ define HMR_H_HEADER_STRING #define HMR_TMR_OFFSET 0x300 #define HMR_CORE_INCREMENT 0x008 +#define HMR_DMR_INCREMENT 0x010 +#define HMR_DMR_SLL 0x004 #define HMR_TMR_INCREMENT 0x010 #define HMR_TMR_SLL 0x004 \n diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 81ac22cf..f331ee17 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -80,7 +80,6 @@ module HMR_wrap import recovery_pkg::*; #( 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_raddr_t [NumCores-1:0] core_regfile_raddr_o, output regfile_write_t [NumCores-1:0] core_recovery_regfile_wport_o, // Nonstandard core control signals output logic [ NumCores-1:0] core_setback_o , @@ -251,8 +250,27 @@ module HMR_wrap import recovery_pkg::*; #( logic [NumDMRGroups-1:0][ BeWidth-1:0] dmr_data_be_out; - logic [ NumDMRGroups-1:0][ DataWidth-1:0] dmr_backup_program_counter; + 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_program_counter_error, + dmr_backup_branch_error, + dmr_backup_branch_addr_error, + dmr_backup_regfile_error_a, + dmr_backup_regfile_error_b, + dmr_backup_regfile_addr_error_a, + dmr_backup_regfile_addr_error_b, + dmr_backup_branch_int, + dmr_start_recovery, + dmr_backup_regfile_we_a, + dmr_backup_regfile_we_b, + dmr_recovery_finished; logic [ NumTMRGroups-1:0][ DataWidth-1:0] tmr_backup_program_counter; + 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, @@ -260,30 +278,24 @@ module HMR_wrap import recovery_pkg::*; #( backup_regfile_wdata_a, backup_regfile_wdata_b; logic [NumBackupRegfiles-1:0] backup_branch_int, - recovery_branch_out, - backup_program_counter_error, - backup_pc_enable_out, // dmr_ctrl_pc_read_enable_out, - recovery_pc_enable_out, // dmr_ctrl_pc_write_enable_out, - // dmr_ctrl_core_clk_en_out, backup_regfile_we_a, backup_regfile_we_b, - backup_regfile_error_a, - backup_regfile_error_b, - backup_branch_error, - backup_branch_addr_error, - // regfile_readback_out, - // dmr_ctrl_core_rstn_out, - recovery_debug_req_out, // dmr_ctrl_core_debug_req_out, - recovery_debug_halted_in, // dmr_ctrl_core_debug_halted_in, - recovery_instr_lock_out, // dmr_ctrl_core_instr_lock_out, - recovery_setback_out, // dmr_ctrl_core_setback_out, - recovery_trigger_out, // dmr_ctrl_core_recover_out, // TODO: for regfile only?!? - recovery_debug_resume_out; // dmr_ctrl_debug_resume_out; + backup_program_counter_error, + recovery_branch_out, + backup_pc_enable_out, + recovery_pc_enable_out, + recovery_debug_req_out, + recovery_debug_halted_in, + recovery_instr_lock_out, + recovery_setback_out, + recovery_trigger_out, // TODO: for regfile only?!? + recovery_debug_resume_out, + start_recovery, + recovery_finished; 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] backup_regfile_wport_in, - core_recovery_regfile_wport_out; + regfile_write_t [NumBackupRegfiles-1:0] core_recovery_regfile_wport_out; for (genvar i = 0; i < NumCores; i++) begin : gen_concat if (SeparateData) begin @@ -584,16 +596,6 @@ module HMR_wrap import recovery_pkg::*; #( /************************************************************ ******************** DMR Voters and Regs ******************* ************************************************************/ - for (genvar i = 0; i < NumBackupRegfiles; i++) begin - // TODO fix assignment - assign backup_regfile_wport_in [i] = backup_regfile_wport_i [dmr_core_id(dmr_group_id(i), 0)]; - end - - for (genvar i = 0; i < NumDMRGroups; i++) begin - // TODO fix assignment - assign recovery_debug_halted_in [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 if (DMRSupported || DMRFixed) begin: gen_dmr_recovery_region @@ -639,7 +641,7 @@ module HMR_wrap import recovery_pkg::*; #( .clk_i, .rst_ni, - .reg_req_i ( dmr_register_reqs[i] ), + .reg_req_i ( dmr_register_reqs [i] ), .reg_resp_o ( dmr_register_resps[i] ), .dmr_enable_q_i ( hmr_reg2hw.dmr_enable.q[i] ), @@ -649,18 +651,18 @@ module HMR_wrap import recovery_pkg::*; #( .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] ), + .setback_o ( dmr_setback_q [i] ), + .sw_resynch_req_o ( dmr_resynch_req_o [i] ), .grp_in_independent_o ( dmr_grp_in_independent[i] ), - .rapid_recovery_en_o ( dmr_rapid_recovery_en[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] ), + .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 (), - .recovery_finished_i () + .recovery_request_o ( dmr_start_recovery [i] ), + .recovery_finished_i ( dmr_recovery_finished[i] ) ); /********************* @@ -671,8 +673,8 @@ module HMR_wrap import recovery_pkg::*; #( ) 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] ) + .check_o ( main_dmr_out [i] ), + .error_o ( dmr_failure_main [i] ) ); if (SeparateData) begin : gen_data_checker DMR_checker # ( @@ -680,8 +682,8 @@ module HMR_wrap import recovery_pkg::*; #( ) 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] ) + .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] } @@ -703,11 +705,13 @@ module HMR_wrap import recovery_pkg::*; #( assign dmr_failure [i] = (dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i]) : dmr_failure_main[i]) | - backup_program_counter_error[i] | - backup_branch_error [i] | - backup_branch_addr_error [i] | - backup_regfile_error_a [i] | - backup_regfile_error_b [i]; + dmr_backup_program_counter_error[i] | + dmr_backup_branch_error [i] | + dmr_backup_branch_addr_error [i] | + dmr_backup_regfile_error_a [i] | + dmr_backup_regfile_error_b [i] | + dmr_backup_regfile_addr_error_a [i] | + dmr_backup_regfile_addr_error_b [i]; /****************** * DMR PC Checker * @@ -717,8 +721,8 @@ module HMR_wrap import recovery_pkg::*; #( ) dmr_pc_checker ( .inp_a_i ( backup_program_counter_i[dmr_core_id(i, 0)] ), .inp_b_i ( backup_program_counter_i[dmr_core_id(i, 1)] ), - .check_o ( dmr_backup_program_counter[i] ), - .error_o ( backup_program_counter_error [i] ) + .check_o ( dmr_backup_program_counter [i] ), + .error_o ( dmr_backup_program_counter_error [i] ) ); /********************** @@ -729,8 +733,8 @@ module HMR_wrap import recovery_pkg::*; #( ) dmr_branch_checker ( .inp_a_i ( backup_branch_i[dmr_core_id(i, 0)] ), .inp_b_i ( backup_branch_i[dmr_core_id(i, 1)] ), - .check_o ( backup_branch_int [i] ), - .error_o ( backup_branch_error [i] ) + .check_o ( dmr_backup_branch_int [i] ), + .error_o ( dmr_backup_branch_error [i] ) ); /***************************** @@ -741,8 +745,8 @@ module HMR_wrap import recovery_pkg::*; #( ) dmr_branch_addr_checker ( .inp_a_i ( backup_branch_addr_i[dmr_core_id(i, 0)] ), .inp_b_i ( backup_branch_addr_i[dmr_core_id(i, 1)] ), - .check_o ( backup_branch_addr_int [i] ), - .error_o ( backup_branch_addr_error [i] ) + .check_o ( dmr_backup_branch_addr_int [i] ), + .error_o ( dmr_backup_branch_addr_error [i] ) ); /******************* @@ -753,8 +757,17 @@ module HMR_wrap import recovery_pkg::*; #( ) dmr_rf_checker_port_a ( .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_a ), .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_a ), - .check_o ( backup_regfile_wdata_a[i] ), - .error_o ( backup_regfile_error_a[i] ) + .check_o ( dmr_backup_regfile_wdata_a [i] ), + .error_o ( dmr_backup_regfile_error_a [i] ) + ); + + DMR_checker # ( + .DataWidth ( RFAddrWidth ) + ) dmr_rf_checker_addr_port_a ( + .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_a ), + .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].waddr_a ), + .check_o ( dmr_backup_regfile_waddr_a [i] ), + .error_o ( dmr_backup_regfile_addr_error_a [i] ) ); DMR_checker # ( @@ -762,17 +775,29 @@ module HMR_wrap import recovery_pkg::*; #( ) dmr_rf_checker_port_b ( .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_b ), .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_b ), - .check_o ( backup_regfile_wdata_b [i] ), - .error_o ( backup_regfile_error_b [i] ) + .check_o ( dmr_backup_regfile_wdata_b [i] ), + .error_o ( dmr_backup_regfile_error_b [i] ) ); - assign backup_regfile_we_a [i] = backup_regfile_wport_i[i].we_a - & ~backup_regfile_error_a [i] - & ~recovery_trigger_out [i]; - assign backup_regfile_we_b [i] = backup_regfile_wport_i[i].we_b - & ~backup_regfile_error_b [i] - & ~recovery_trigger_out [i]; - + DMR_checker # ( + .DataWidth ( RFAddrWidth ) + ) dmr_rf_checker_addr_port_b ( + .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_b ), + .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].waddr_b ), + .check_o ( dmr_backup_regfile_waddr_b [i] ), + .error_o ( dmr_backup_regfile_addr_error_b [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_backup_regfile_error_a [i] + & ~dmr_backup_regfile_addr_error_a [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_backup_regfile_error_b [i] + & ~dmr_backup_regfile_addr_error_b [i]; + end else begin assign dmr_failure [i] = dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i]) : dmr_failure_main[i]; @@ -803,17 +828,17 @@ module HMR_wrap import recovery_pkg::*; #( ) i_rapid_recovery_ctrl ( .clk_i, .rst_ni, - .start_recovery_i (), - .recovery_finished_o (), - .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] ), + .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_pc_enable_o ( backup_pc_enable_out [i] ), - .recover_pc_enable_o ( recovery_pc_enable_out [i] ), - .recover_rf_enable_o ( recovery_trigger_out [i] ) + .backup_pc_enable_o ( backup_pc_enable_out [i] ), + .recover_pc_enable_o ( recovery_pc_enable_out [i] ), + .recover_rf_enable_o ( recovery_trigger_out [i] ) ); /**************************** @@ -825,18 +850,18 @@ module HMR_wrap import recovery_pkg::*; #( // Control Ports .clk_i, .rst_ni, - .clear_i ( '0 ), - .read_enable_i ( backup_pc_enable_out [i] ), + .clear_i ( '0 ), + .read_enable_i ( backup_pc_enable_out [i] ), .write_enable_i ( ~backup_program_counter_error [i] - & recovery_pc_enable_out [i] ), + & recovery_pc_enable_out [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_i [i] ), + .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_program_counter_o ( recovery_program_counter_out [i] ), + .recovery_branch_o ( recovery_branch_out [i] ), + .recovery_branch_addr_o ( recovery_branch_addr_out [i] ) ); /*************************** @@ -859,30 +884,68 @@ module HMR_wrap import recovery_pkg::*; #( .raddr_c_i ( '0 ), .rdata_c_o ( ), // Write Port A - .waddr_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_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] ), + .we_a_i ( backup_regfile_we_a[i] & ~recovery_trigger_out[i] ), // Write Port B - .waddr_b_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_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] ) + .we_b_i ( backup_regfile_we_b[i] & ~recovery_trigger_out[i] ) ); end - always_comb begin - backup_program_counter_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; + recovery_debug_halted_in = '0; 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_program_counter_int[dmr_shared_id(i)] = dmr_backup_program_counter[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_program_counter_int[tmr_shared_id(i)] = tmr_backup_program_counter[i]; + backup_program_counter_int [tmr_shared_id(i)] = tmr_backup_program_counter [i]; + // backup_program_counter_error[tmr_shared_id(i)] = tmr_backup_program_counter_error[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 @@ -891,20 +954,19 @@ module HMR_wrap import recovery_pkg::*; #( 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))]; + 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))]; + 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))]; // PC - pc_recover_o [i] = backup_pc_enable_out [dmr_shared_id(dmr_group_id(i))]; + 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))]; + 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_regfile_raddr_o [i] = core_regfile_raddr_out [dmr_shared_id(dmr_group_id(i))]; 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; @@ -913,20 +975,20 @@ module HMR_wrap import recovery_pkg::*; #( 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))]; + 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))]; + 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))]; // PC - pc_recover_o [i] = backup_pc_enable_out [tmr_shared_id(tmr_group_id(i))]; + 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))]; + 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_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; @@ -936,11 +998,11 @@ module HMR_wrap import recovery_pkg::*; #( end else begin // Disable RapidRecovery - core_debug_resume_o [i] = '0; + core_debug_resume_o [i] = '0; // Setback - core_recover_o [i] = '0; - core_instr_lock_o [i] = '0; + core_recover_o [i] = '0; + core_instr_lock_o [i] = '0; // PC pc_recover_o [i] = '0; @@ -949,7 +1011,6 @@ module HMR_wrap import recovery_pkg::*; #( recovery_branch_addr_o [i] = '0; // RF - core_regfile_raddr_o [i] = '0; 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; @@ -960,15 +1021,14 @@ module HMR_wrap import recovery_pkg::*; #( end end - // TODO: 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; + assign core_debug_resume_o [i] = '0; // Setback - assign core_recover_o [i] = '0; - assign core_instr_lock_o [i] = '0; + assign core_recover_o [i] = '0; + assign core_instr_lock_o [i] = '0; // PC assign pc_recover_o [i] = '0; @@ -977,7 +1037,6 @@ module HMR_wrap import recovery_pkg::*; #( assign recovery_branch_addr_o [i] = '0; // RF - assign core_regfile_raddr_o [i] = '0; 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; From 60bbf12325c8f98d411f3a95b18e2b787acb4929 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 1 Feb 2023 14:53:43 +0100 Subject: [PATCH 13/72] Fix connections for rapid-recovery --- rtl/HMR/HMR_wrap.sv | 88 +++++++++++++++++++++++++---------------- rtl/HMR/hmr_dmr_ctrl.sv | 18 ++++++--- rtl/HMR/hmr_tmr_ctrl.sv | 6 ++- 3 files changed, 72 insertions(+), 40 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index f331ee17..5fcb53fc 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -298,12 +298,12 @@ module HMR_wrap import recovery_pkg::*; #( regfile_write_t [NumBackupRegfiles-1:0] core_recovery_regfile_wport_out; for (genvar i = 0; i < NumCores; i++) begin : gen_concat - if (SeparateData) begin + 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]}; 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 + 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]}; @@ -330,7 +330,7 @@ module HMR_wrap import recovery_pkg::*; #( logic [NumTMRGroups-1:0] tmr_grp_in_independent; logic [NumTMRGroups-1:0] tmr_rapid_recovery_en; - for (genvar i = 0; i < NumCores; i++) begin + 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; @@ -385,7 +385,7 @@ module HMR_wrap import recovery_pkg::*; #( assign hmr_hw2reg.avail_config.triple.d = TMRFixed | TMRSupported; assign hmr_hw2reg.avail_config.rapid_recovery.d = RapidRecovery; - always_comb begin + always_comb begin : proc_reg_status hmr_hw2reg.cores_en.d = '0; hmr_hw2reg.cores_en.d = core_en_as_master; @@ -431,7 +431,7 @@ module HMR_wrap import recovery_pkg::*; #( logic [NumCores-1:0] tmr_incr_mismatches; logic [NumCores-1:0] dmr_incr_mismatches; - for (genvar i = 0; i < NumCores; i++) begin + 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) @@ -597,7 +597,7 @@ module HMR_wrap import recovery_pkg::*; #( ******************** DMR Voters and Regs ******************* ************************************************************/ - if (DMRSupported || DMRFixed) begin: gen_dmr_recovery_region + 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; @@ -628,7 +628,7 @@ module HMR_wrap import recovery_pkg::*; #( assign dmr_incr_mismatches[i] = '0; end - for (genvar i = 0; i < NumDMRGroups; i++) begin + for (genvar i = 0; i < NumDMRGroups; i++) begin : gen_dmr_groups hmr_dmr_ctrl #( .reg_req_t ( reg_req_t ), @@ -701,7 +701,7 @@ module HMR_wrap import recovery_pkg::*; #( = main_dmr_out[i]; end - if (RapidRecovery) begin + 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]) | @@ -798,7 +798,7 @@ module HMR_wrap import recovery_pkg::*; #( & ~dmr_backup_regfile_error_b [i] & ~dmr_backup_regfile_addr_error_b [i]; - end else begin + 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 @@ -822,7 +822,7 @@ module HMR_wrap import recovery_pkg::*; #( // RapidRecovery output signals if (RapidRecovery) begin : gen_rapid_recovery - for (genvar i = 0; i < NumBackupRegfiles; i++) begin + for (genvar i = 0; i < NumBackupRegfiles; i++) begin : gen_groups hmr_rapid_recovery_ctrl #( .RFAddrWidth( RFAddrWidth ) ) i_rapid_recovery_ctrl ( @@ -895,7 +895,7 @@ module HMR_wrap import recovery_pkg::*; #( end - always_comb begin + always_comb begin : proc_dmr_tmr_assignments backup_program_counter_int = '0; backup_program_counter_error = '0; backup_branch_int = '0; @@ -1067,7 +1067,12 @@ module HMR_wrap import recovery_pkg::*; #( core_fetch_en_o [i] = sys_fetch_en_i [TMRCoreIndex]; core_boot_addr_o [i] = sys_boot_addr_i [TMRCoreIndex]; - core_debug_req_o [i] = sys_debug_req_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 @@ -1089,7 +1094,12 @@ module HMR_wrap import recovery_pkg::*; #( core_data_err_o [i] = sys_data_err_i [TMRCoreIndex]; // Special signals - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + if (RapidRecovery) begin + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)] + | recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + end else begin + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + end end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode // CTRL core_core_id_o [i] = sys_core_id_i [DMRCoreIndex]; @@ -1099,7 +1109,12 @@ module HMR_wrap import recovery_pkg::*; #( core_fetch_en_o [i] = sys_fetch_en_i [DMRCoreIndex]; core_boot_addr_o [i] = sys_boot_addr_i [DMRCoreIndex]; - core_debug_req_o [i] = sys_debug_req_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 @@ -1121,7 +1136,11 @@ module HMR_wrap import recovery_pkg::*; #( core_data_err_o [i] = sys_data_err_i [DMRCoreIndex]; // Special signals - core_setback_o [i] = '0; + if (RapidRecovery) begin + core_setback_o [i] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + end else begin + core_setback_o [i] = '0; + end end else begin : independent_mode // CTRL core_core_id_o [i] = sys_core_id_i [i]; @@ -1281,7 +1300,12 @@ module HMR_wrap import recovery_pkg::*; #( core_fetch_en_o [i] = sys_fetch_en_i [SysCoreIndex]; core_boot_addr_o [i] = sys_boot_addr_i [SysCoreIndex]; - core_debug_req_o [i] = sys_debug_req_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 @@ -1303,7 +1327,13 @@ module HMR_wrap import recovery_pkg::*; #( core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; // Special signals - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + // Setback + if (RapidRecovery) begin + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)] + | recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + end else begin + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + end end else begin : independent_mode // CTRL core_core_id_o [i] = sys_core_id_i [i]; @@ -1460,38 +1490,24 @@ module HMR_wrap import recovery_pkg::*; #( for (genvar i = 0; i < NumCores; i++) begin : gen_core_inputs localparam SysCoreIndex = DMRFixed ? i/2 : dmr_core_id(dmr_group_id(i), 0); - localparam SysGroupId = DMRFixed ? i/2 : dmr_group_id(i); always_comb begin 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]; - // if (RapidRecovery) begin - // core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex] - // & dmr_ctrl_core_clk_en_out[SysGroupId]; - // end else begin - core_clock_en_o [i] = sys_clock_en_i [SysCoreIndex]; - // end + 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 [SysGroupId]; + | 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]; - // Setback - if (RapidRecovery) begin - core_setback_o [i] = recovery_setback_out [SysGroupId]; - end else begin - core_setback_o [i] = '0; - end - // IRQ core_irq_req_o [i] = sys_irq_req_i [SysCoreIndex]; core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; @@ -1510,6 +1526,12 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; + // Setback + if (RapidRecovery) begin + core_setback_o [i] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + end else begin + core_setback_o [i] = '0; + end end else begin : gen_independent_mode // CTRL core_core_id_o [i] = sys_core_id_i [i]; diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 85ec8771..5df0e9e0 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -77,8 +77,8 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( // 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; - assign dmr_hw2reg.dmr_config.rapid_recovery.d = rapid_recovery_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; /************************** @@ -90,26 +90,34 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( dmr_red_mode_d = dmr_red_mode_q; dmr_incr_mismatches_o = '0; recovery_request_o = 1'b0; + sw_resynch_req_o = 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) begin + 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) begin + 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; - recovery_request_o = 1'b1; + end + + if (dmr_error_i && (!RapidRecovery || !dmr_reg2hw.dmr_config.rapid_recovery.q)) begin + $display("[HMR-dual] %t - mismatch detected, SW trigger", $realtime); + sw_resynch_req_o = 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 diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 11e0b27d..6359ec8c 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -100,6 +100,7 @@ module hmr_tmr_ctrl #( tmr_setback_d = 1'b0; tmr_red_mode_d = tmr_red_mode_q; tmr_incr_mismatches_o = '0; + sw_resynch_req_o = 1'b0; tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; @@ -116,7 +117,7 @@ module hmr_tmr_ctrl #( // If error detected, do resynchronization if (tmr_single_mismatch_i) begin - $display("[ODRG] %t - mismatch detected", $realtime); + $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; @@ -129,6 +130,7 @@ module hmr_tmr_ctrl #( end TMR_UNLOAD: begin + sw_resynch_req_o = 1'b1; // If unload complete, go to reload (and reset) if (tmr_reg2hw.sp_store.q != '0) begin tmr_red_mode_d = TMR_RELOAD; @@ -141,7 +143,7 @@ module hmr_tmr_ctrl #( TMR_RELOAD: begin // If reload complete, finish (or reset if error happens during reload) if (tmr_reg2hw.sp_store.q == '0) begin - $display("[ODRG] %t - mismatch restored", $realtime); + $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 && From e7f79200a417c3e8efd121706b8770a09758f68a Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 1 Feb 2023 16:19:47 +0100 Subject: [PATCH 14/72] Generating correct offsets in RF address generator. --- rtl/HMR/DMR_address_generator.sv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtl/HMR/DMR_address_generator.sv b/rtl/HMR/DMR_address_generator.sv index 12e4d41d..e832de28 100644 --- a/rtl/HMR/DMR_address_generator.sv +++ b/rtl/HMR/DMR_address_generator.sv @@ -38,17 +38,17 @@ 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] <= '0; + addr_count [i] <= '1; else begin if (clear_i || addr_count_rst [i]) - addr_count [i] <= '0; + 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'b1 : 1'b0; + assign addr_count_rst [i] = ( addr_count [i] == NumAddr/2 - 1) ? 1'b1 : 1'b0; end endgenerate From d455d374742764dd71e1498dfbbaa008a6ccdc17 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Thu, 2 Feb 2023 18:39:30 +0100 Subject: [PATCH 15/72] Properly connecting rapid recovery controller signals to recovery PC. --- rtl/HMR/HMR_wrap.sv | 4 ++-- rtl/HMR/hmr_rapid_recovery_ctrl.sv | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 5fcb53fc..432ee0e1 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -851,9 +851,9 @@ module HMR_wrap import recovery_pkg::*; #( .clk_i, .rst_ni, .clear_i ( '0 ), - .read_enable_i ( backup_pc_enable_out [i] ), + .read_enable_i ( recovery_pc_enable_out [i] ), .write_enable_i ( ~backup_program_counter_error [i] - & recovery_pc_enable_out [i] ), + & backup_pc_enable_out [i] ), // Backup Ports .backup_program_counter_i ( backup_program_counter_int [i] ), .backup_branch_i ( backup_branch_int [i] ), diff --git a/rtl/HMR/hmr_rapid_recovery_ctrl.sv b/rtl/HMR/hmr_rapid_recovery_ctrl.sv index 5f409733..97a094e7 100644 --- a/rtl/HMR/hmr_rapid_recovery_ctrl.sv +++ b/rtl/HMR/hmr_rapid_recovery_ctrl.sv @@ -82,6 +82,8 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( IDLE: begin // If requested start the routine in the reset state if (start_recovery_i) begin + // Disable reading for the backup PC + backup_pc_enable_d = 1'b0; rec_mode_d = RESET; end end @@ -91,8 +93,6 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( setback_d = 1'b1; // Lock the instruction requests instr_lock_d = 1'b1; - // Disable reading for the backup PC - backup_pc_enable_d = 1'b0; // Go to request halt of the core rec_mode_d = HALT; end From ca1c5ed1865fdb62c56ccb8129f28ead15ac17b9 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 2 Feb 2023 17:03:18 +0100 Subject: [PATCH 16/72] Update shared_id selection for only TMR support Turneded max into function because Synopsys does not synthesize it. --- rtl/HMR/HMR_wrap.sv | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 432ee0e1..d3e08b9a 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -166,6 +166,11 @@ module HMR_wrap import recovery_pkg::*; #( // 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; @@ -178,7 +183,7 @@ module HMR_wrap import recovery_pkg::*; #( endfunction function int tmr_shared_id (int group_id); - if (InterleaveGrps) return group_id; + if (InterleaveGrps || !(DMRSupported || DMRFixed)) return group_id; else return group_id + group_id/2; endfunction @@ -205,8 +210,6 @@ module HMR_wrap import recovery_pkg::*; #( localparam int unsigned MainConcatWidth = SeparateData ? CtrlConcatWidth : CtrlConcatWidth + DataConcatWidth; - let max(a,b) = (a > b) ? a : b; - localparam int unsigned NumBackupRegfiles = max(DMRSupported || DMRFixed ? NumDMRGroups : 0, TMRSupported || TMRFixed ? NumTMRGroups : 0); localparam int unsigned RFAddrWidth = 6; logic [ NumCores-1:0][MainConcatWidth-1:0] main_concat_in; From f5785a609859f912b7d0226224947a86b589d799 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 3 Feb 2023 12:02:41 +0100 Subject: [PATCH 17/72] Add synch request signals Fix TMR synch request --- rtl/HMR/HMR_wrap.sv | 17 +++++++++++++++++ rtl/HMR/hmr_dmr_ctrl.sv | 2 ++ rtl/HMR/hmr_tmr_ctrl.sv | 16 +++++++++++----- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index d3e08b9a..b2ec1c5d 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -62,12 +62,14 @@ module HMR_wrap import recovery_pkg::*; #( 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'Program Counter @@ -465,6 +467,7 @@ module HMR_wrap import recovery_pkg::*; #( 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); @@ -487,6 +490,7 @@ module HMR_wrap import recovery_pkg::*; #( 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 @@ -519,6 +523,7 @@ module HMR_wrap import recovery_pkg::*; #( .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)]} ), @@ -529,6 +534,10 @@ module HMR_wrap import recovery_pkg::*; #( .cores_synch_i ( tmr_cores_synch_i[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]; @@ -594,6 +603,7 @@ module HMR_wrap import recovery_pkg::*; #( 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 /************************************************************ @@ -607,6 +617,7 @@ module HMR_wrap import recovery_pkg::*; #( 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); @@ -629,6 +640,7 @@ module HMR_wrap import recovery_pkg::*; #( 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 @@ -656,6 +668,7 @@ module HMR_wrap import recovery_pkg::*; #( .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)]} ), @@ -668,6 +681,9 @@ module HMR_wrap import recovery_pkg::*; #( .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 * *********************/ @@ -821,6 +837,7 @@ module HMR_wrap import recovery_pkg::*; #( 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 diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 5df0e9e0..e7ffed29 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -37,6 +37,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( // DMR control signals output logic 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 [1:0] dmr_incr_mismatches_o, @@ -60,6 +61,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( assign setback_o = dmr_setback_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 = dmr_reg2hw.dmr_enable.q & dmr_red_mode_q == NON_DMR; hmr_dmr_regs_reg_top #( .reg_req_t(reg_req_t), diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 6359ec8c..78ac5b90 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -43,6 +43,7 @@ module hmr_tmr_ctrl #( // TMR control signals output logic 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, @@ -65,7 +66,7 @@ module hmr_tmr_ctrl #( assign setback_o = tmr_setback_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 rapid_recovery_en_o = tmr_reg2hw.tmr_config.rapid_recovery.q & RapidRecovery; hmr_tmr_regs_reg_top #( .reg_req_t(reg_req_t), @@ -101,6 +102,7 @@ module hmr_tmr_ctrl #( tmr_red_mode_d = tmr_red_mode_q; tmr_incr_mismatches_o = '0; sw_resynch_req_o = 1'b0; + sw_synch_req_o = 1'b0; tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; @@ -109,7 +111,7 @@ module hmr_tmr_ctrl #( // 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.delay_resynch == 0) begin + 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 @@ -175,9 +177,13 @@ module hmr_tmr_ctrl #( end end // Set TMR mode on external signal that cores are synchronized - if (tmr_red_mode_q == NON_TMR && cores_synch_i) begin - if (tmr_reg2hw.tmr_enable.q == 1'b1) begin - tmr_red_mode_d = TMR_RUN; + if (tmr_red_mode_q == NON_TMR && tmr_reg2hw.tmr_enable.q == 1'b1) begin + sw_synch_req_o = 1'b1; + if (cores_synch_i) begin + tmr_red_mode_d = TMR_RELOAD; + if (tmr_reg2hw.tmr_config.setback.q) begin + tmr_setback_d = 1'b1; + end end end end From 819c5dab7101ad7502e177995f88b37aba1727c9 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 3 Feb 2023 13:52:38 +0100 Subject: [PATCH 18/72] Move SP store reg from tmr to core registers --- Makefile | 3 +- rtl/HMR/HMR_core_regs.hjson | 12 ++++++++ rtl/HMR/HMR_regs.hjson | 2 +- rtl/HMR/HMR_tmr_regs.hjson | 12 -------- rtl/HMR/HMR_wrap.sv | 11 ++++++-- rtl/HMR/hmr_core_regs_reg_pkg.sv | 23 +++++++++++----- rtl/HMR/hmr_core_regs_reg_top.sv | 47 +++++++++++++++++++++++++++++--- rtl/HMR/hmr_tmr_ctrl.sv | 8 ++++-- rtl/HMR/hmr_tmr_regs_reg_pkg.sv | 35 +++++++----------------- rtl/HMR/hmr_tmr_regs_reg_top.sv | 47 +++----------------------------- rtl/HMR/hmr_v1.h | 11 +++++--- 11 files changed, 109 insertions(+), 102 deletions(-) diff --git a/Makefile b/Makefile index 5afec358..afeed9ac 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,8 @@ define HMR_H_HEADER_STRING #define HMR_DMR_OFFSET 0x200 #define HMR_TMR_OFFSET 0x300 -#define HMR_CORE_INCREMENT 0x008 +#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 diff --git a/rtl/HMR/HMR_core_regs.hjson b/rtl/HMR/HMR_core_regs.hjson index b37d5499..c55f5ede 100644 --- a/rtl/HMR/HMR_core_regs.hjson +++ b/rtl/HMR/HMR_core_regs.hjson @@ -43,6 +43,18 @@ 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_regs.hjson b/rtl/HMR/HMR_regs.hjson index fb02cebc..c6a10cbc 100644 --- a/rtl/HMR/HMR_regs.hjson +++ b/rtl/HMR/HMR_regs.hjson @@ -12,7 +12,7 @@ param_list: [ { name: "NumCores", - default: "12" # Supports up to 32 cores + default: "12" # Supports up to 16 cores }, { name: "NumDMRGroups", default: "6" diff --git a/rtl/HMR/HMR_tmr_regs.hjson b/rtl/HMR/HMR_tmr_regs.hjson index e01825b9..8d6dab90 100644 --- a/rtl/HMR/HMR_tmr_regs.hjson +++ b/rtl/HMR/HMR_tmr_regs.hjson @@ -55,18 +55,6 @@ desc: "Forces a resynchronization routine" } ] - }, - { name: "sp_store", - desc: "Stack Pointer storage register", - swaccess: "rw", - hwaccess: "hrw", - hwqe: "true", - fields: [ - { bits: "31:0", - name: "SP", - desc: "Stack Pointer" - } - ] } ] } diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index b2ec1c5d..51f78e70 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -335,6 +335,9 @@ module HMR_wrap import recovery_pkg::*; #( 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; @@ -414,7 +417,7 @@ module HMR_wrap import recovery_pkg::*; #( reg_req_t [NumCores-1:0] core_register_reqs; reg_resp_t [NumCores-1:0] core_register_resps; - // 2 words per core + // 4 words per core reg_demux #( .NoPorts ( NumCores ), @@ -423,7 +426,7 @@ module HMR_wrap import recovery_pkg::*; #( ) i_core_reg_demux ( .clk_i, .rst_ni, - .in_select_i( top_register_reqs [1].addr[3+$clog2(NumCores)-1:3] ), + .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 ), @@ -455,6 +458,8 @@ module HMR_wrap import recovery_pkg::*; #( 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 @@ -530,6 +535,8 @@ module HMR_wrap import recovery_pkg::*; #( .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] ) ); diff --git a/rtl/HMR/hmr_core_regs_reg_pkg.sv b/rtl/HMR/hmr_core_regs_reg_pkg.sv index b594350c..602bd91a 100644 --- a/rtl/HMR/hmr_core_regs_reg_pkg.sv +++ b/rtl/HMR/hmr_core_regs_reg_pkg.sv @@ -7,7 +7,7 @@ package hmr_core_regs_reg_pkg; // Address widths within the block - parameter int BlockAw = 3; + parameter int BlockAw = 4; //////////////////////////// // Typedefs for registers // @@ -17,6 +17,11 @@ package hmr_core_regs_reg_pkg; 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; @@ -36,7 +41,8 @@ package hmr_core_regs_reg_pkg; // Register -> HW type typedef struct packed { - hmr_core_regs_reg2hw_mismatches_reg_t mismatches; // [31:0] + 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 @@ -46,8 +52,9 @@ package hmr_core_regs_reg_pkg; } hmr_core_regs_hw2reg_t; // Register offsets - parameter logic [BlockAw-1:0] HMR_CORE_REGS_CURRENT_MODE_OFFSET = 3'h 0; - parameter logic [BlockAw-1:0] HMR_CORE_REGS_MISMATCHES_OFFSET = 3'h 4; + 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; @@ -58,13 +65,15 @@ package hmr_core_regs_reg_pkg; // Register index typedef enum int { HMR_CORE_REGS_CURRENT_MODE, - HMR_CORE_REGS_MISMATCHES + 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 [2] = '{ + 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[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 index 39e65762..d9cf8ceb 100644 --- a/rtl/HMR/hmr_core_regs_reg_top.sv +++ b/rtl/HMR/hmr_core_regs_reg_top.sv @@ -10,7 +10,7 @@ module hmr_core_regs_reg_top #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, - parameter int AW = 3 + parameter int AW = 4 ) ( input logic clk_i, input logic rst_ni, @@ -77,6 +77,9 @@ module hmr_core_regs_reg_top #( 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) @@ -153,13 +156,41 @@ module hmr_core_regs_reg_top #( ); + // 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 [1:0] addr_hit; + + + 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 ; @@ -168,7 +199,8 @@ module hmr_core_regs_reg_top #( 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[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; @@ -180,6 +212,9 @@ module hmr_core_regs_reg_top #( 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; @@ -194,6 +229,10 @@ module hmr_core_regs_reg_top #( 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 @@ -216,7 +255,7 @@ endmodule module hmr_core_regs_reg_top_intf #( - parameter int AW = 3, + parameter int AW = 4, localparam int DW = 32 ) ( input logic clk_i, diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 78ac5b90..12f78194 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -50,6 +50,8 @@ module hmr_tmr_ctrl #( 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 ); @@ -134,7 +136,7 @@ module hmr_tmr_ctrl #( TMR_UNLOAD: begin sw_resynch_req_o = 1'b1; // If unload complete, go to reload (and reset) - if (tmr_reg2hw.sp_store.q != '0) begin + if (!sp_store_is_zero) begin tmr_red_mode_d = TMR_RELOAD; if (tmr_reg2hw.tmr_config.setback.q) begin tmr_setback_d = 1'b1; @@ -144,13 +146,13 @@ module hmr_tmr_ctrl #( TMR_RELOAD: begin // If reload complete, finish (or reset if error happens during reload) - if (tmr_reg2hw.sp_store.q == '0) begin + 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 && - !(tmr_reg2hw.sp_store.qe && reg_req_i.wdata == '0)) begin + !sp_store_will_be_zero) begin tmr_setback_d = 1'b1; end end diff --git a/rtl/HMR/hmr_tmr_regs_reg_pkg.sv b/rtl/HMR/hmr_tmr_regs_reg_pkg.sv index 148055e7..89eeca99 100644 --- a/rtl/HMR/hmr_tmr_regs_reg_pkg.sv +++ b/rtl/HMR/hmr_tmr_regs_reg_pkg.sv @@ -7,7 +7,7 @@ package hmr_tmr_regs_reg_pkg; // Address widths within the block - parameter int BlockAw = 4; + parameter int BlockAw = 3; //////////////////////////// // Typedefs for registers // @@ -41,11 +41,6 @@ package hmr_tmr_regs_reg_pkg; } force_resynch; } hmr_tmr_regs_reg2hw_tmr_config_reg_t; - typedef struct packed { - logic [31:0] q; - logic qe; - } hmr_tmr_regs_reg2hw_sp_store_reg_t; - typedef struct packed { logic d; logic de; @@ -74,42 +69,32 @@ package hmr_tmr_regs_reg_pkg; } force_resynch; } hmr_tmr_regs_hw2reg_tmr_config_reg_t; - typedef struct packed { - logic [31:0] d; - logic de; - } hmr_tmr_regs_hw2reg_sp_store_reg_t; - // Register -> HW type typedef struct packed { - hmr_tmr_regs_reg2hw_tmr_enable_reg_t tmr_enable; // [44:43] - hmr_tmr_regs_reg2hw_tmr_config_reg_t tmr_config; // [42:33] - hmr_tmr_regs_reg2hw_sp_store_reg_t sp_store; // [32:0] + 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; // [44:43] - hmr_tmr_regs_hw2reg_tmr_config_reg_t tmr_config; // [42:33] - hmr_tmr_regs_hw2reg_sp_store_reg_t sp_store; // [32:0] + 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 = 4'h 0; - parameter logic [BlockAw-1:0] HMR_TMR_REGS_TMR_CONFIG_OFFSET = 4'h 4; - parameter logic [BlockAw-1:0] HMR_TMR_REGS_SP_STORE_OFFSET = 4'h 8; + 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_SP_STORE + 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 [3] = '{ + 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 - 4'b 1111 // index[2] HMR_TMR_REGS_SP_STORE + 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 index 666d010a..1249580e 100644 --- a/rtl/HMR/hmr_tmr_regs_reg_top.sv +++ b/rtl/HMR/hmr_tmr_regs_reg_top.sv @@ -10,7 +10,7 @@ module hmr_tmr_regs_reg_top #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, - parameter int AW = 4 + parameter int AW = 3 ) ( input logic clk_i, input logic rst_ni, @@ -86,9 +86,6 @@ module hmr_tmr_regs_reg_top #( logic tmr_config_force_resynch_qs; logic tmr_config_force_resynch_wd; logic tmr_config_force_resynch_we; - logic [31:0] sp_store_qs; - logic [31:0] sp_store_wd; - logic sp_store_we; // Register instances // R[tmr_enable]: V(False) @@ -250,41 +247,13 @@ module hmr_tmr_regs_reg_top #( ); - // 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 (hw2reg.sp_store.de), - .d (hw2reg.sp_store.d ), - - // 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; + 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); - addr_hit[2] = (reg_addr == HMR_TMR_REGS_SP_STORE_OFFSET); end assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; @@ -293,8 +262,7 @@ module hmr_tmr_regs_reg_top #( 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))) | - (addr_hit[2] & (|(HMR_TMR_REGS_PERMIT[2] & ~reg_be))))); + (addr_hit[1] & (|(HMR_TMR_REGS_PERMIT[1] & ~reg_be))))); end assign tmr_enable_we = addr_hit[0] & reg_we & !reg_error; @@ -315,9 +283,6 @@ module hmr_tmr_regs_reg_top #( assign tmr_config_force_resynch_we = addr_hit[1] & reg_we & !reg_error; assign tmr_config_force_resynch_wd = reg_wdata[4]; - 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; @@ -334,10 +299,6 @@ module hmr_tmr_regs_reg_top #( reg_rdata_next[4] = tmr_config_force_resynch_qs; end - addr_hit[2]: begin - reg_rdata_next[31:0] = sp_store_qs; - end - default: begin reg_rdata_next = '1; end @@ -360,7 +321,7 @@ endmodule module hmr_tmr_regs_reg_top_intf #( - parameter int AW = 4, + parameter int AW = 3, localparam int DW = 32 ) ( input logic clk_i, diff --git a/rtl/HMR/hmr_v1.h b/rtl/HMR/hmr_v1.h index 92ed91bb..ec4f2d7e 100644 --- a/rtl/HMR/hmr_v1.h +++ b/rtl/HMR/hmr_v1.h @@ -24,7 +24,10 @@ #define HMR_DMR_OFFSET 0x200 #define HMR_TMR_OFFSET 0x300 -#define HMR_CORE_INCREMENT 0x008 +#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 @@ -112,6 +115,9 @@ extern "C" { // 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 @@ -170,9 +176,6 @@ extern "C" { #define HMR_TMR_REGS_TMR_CONFIG_RAPID_RECOVERY_BIT 3 #define HMR_TMR_REGS_TMR_CONFIG_FORCE_RESYNCH_BIT 4 -// Stack Pointer storage register -#define HMR_TMR_REGS_SP_STORE_REG_OFFSET 0x8 - #ifdef __cplusplus } // extern "C" #endif From 93f3effe596be98687147f2a3939f503ffda465c Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 8 May 2023 11:41:26 +0200 Subject: [PATCH 19/72] Merged CSRs backup and recovery. --- Bender.yml | 4 +- rtl/HMR/DMR_CSR_checker.sv | 51 ++++++++++ rtl/HMR/HMR_wrap.sv | 50 +++++++++- rtl/HMR/hmr_rapid_recovery_ctrl.sv | 13 +++ rtl/HMR/recovery_csr.sv | 151 +++++++++++++++++++++++++++++ rtl/HMR/recovery_pkg.sv | 34 +++++-- 6 files changed, 291 insertions(+), 12 deletions(-) create mode 100644 rtl/HMR/DMR_CSR_checker.sv create mode 100644 rtl/HMR/recovery_csr.sv diff --git a/Bender.yml b/Bender.yml index 5c1bb114..4ef1b8cb 100644 --- a/Bender.yml +++ b/Bender.yml @@ -94,9 +94,11 @@ sources: - files: - rtl/HMR/recovery_pkg.sv - - rtl/HMR/recovery_rf.sv + - rtl/HMR/recovery_csr.sv - rtl/HMR/recovery_pc.sv + - rtl/HMR/recovery_rf.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 diff --git a/rtl/HMR/DMR_CSR_checker.sv b/rtl/HMR/DMR_CSR_checker.sv new file mode 100644 index 00000000..0bcd067f --- /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 + * + */ + +import recovery_pkg::*; + +module DMR_CSR_checker ( + 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/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 51f78e70..5bedda40 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -72,6 +72,10 @@ module HMR_wrap import recovery_pkg::*; #( 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, @@ -261,7 +265,8 @@ module HMR_wrap import recovery_pkg::*; #( dmr_backup_regfile_wdata_a, dmr_backup_regfile_wdata_b, dmr_backup_branch_addr_int; - logic [ NumDMRGroups-1:0] dmr_backup_program_counter_error, + logic [ NumDMRGroups-1:0] dmr_backup_csr_error, + dmr_backup_program_counter_error, dmr_backup_branch_error, dmr_backup_branch_addr_error, dmr_backup_regfile_error_a, @@ -287,7 +292,9 @@ module HMR_wrap import recovery_pkg::*; #( backup_regfile_we_b, backup_program_counter_error, recovery_branch_out, + backup_csr_enable_out, backup_pc_enable_out, + recovery_csr_enable_out, recovery_pc_enable_out, recovery_debug_req_out, recovery_debug_halted_in, @@ -301,6 +308,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] dmr_backup_csr, recovery_csr_out; for (genvar i = 0; i < NumCores; i++) begin : gen_concat if (SeparateData) begin : gen_separate_data @@ -731,6 +739,7 @@ module HMR_wrap import recovery_pkg::*; #( assign dmr_failure [i] = (dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i]) : dmr_failure_main[i]) | + dmr_backup_csr_error [i] | dmr_backup_program_counter_error[i] | dmr_backup_branch_error [i] | dmr_backup_branch_addr_error [i] | @@ -739,6 +748,16 @@ module HMR_wrap import recovery_pkg::*; #( dmr_backup_regfile_addr_error_a [i] | dmr_backup_regfile_addr_error_b [i]; + /******************** + * DMR CSRs Checker * + ********************/ + DMR_CSR_checker dmr_csr_checker ( + .csr_a_i ( backup_csr_i[dmr_core_id(i, 0)] ), + .csr_b_i ( backup_csr_i[dmr_core_id(i, 1)] ), + .check_o ( dmr_backup_csr [i] ), + .error_o ( dmr_backup_csr_error [i] ) + ); + /****************** * DMR PC Checker * ******************/ @@ -863,11 +882,28 @@ module HMR_wrap import recovery_pkg::*; #( .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_csr_enable_o ( backup_csr_enable_out [i] ), .backup_pc_enable_o ( backup_pc_enable_out [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 ( ~dmr_backup_csr_error [i] + & backup_csr_enable_out [i] ), + .backup_csr_i ( dmr_backup_csr [i] ), + .recovery_csr_o ( recovery_csr_out [i] ) + ); + /**************************** * Recovery Program Counter * ****************************/ @@ -987,6 +1023,9 @@ module HMR_wrap import recovery_pkg::*; #( 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))]; @@ -1008,6 +1047,9 @@ module HMR_wrap import recovery_pkg::*; #( 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))]; @@ -1031,6 +1073,9 @@ module HMR_wrap import recovery_pkg::*; #( 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; @@ -1057,6 +1102,9 @@ module HMR_wrap import recovery_pkg::*; #( 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; diff --git a/rtl/HMR/hmr_rapid_recovery_ctrl.sv b/rtl/HMR/hmr_rapid_recovery_ctrl.sv index 97a094e7..3315e271 100644 --- a/rtl/HMR/hmr_rapid_recovery_ctrl.sv +++ b/rtl/HMR/hmr_rapid_recovery_ctrl.sv @@ -29,7 +29,9 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( output regfile_write_t recovery_regfile_waddr_o, // Signals to backup state + output logic backup_csr_enable_o, output logic backup_pc_enable_o, + output logic recover_csr_enable_o, output logic recover_pc_enable_o, output logic recover_rf_enable_o ); @@ -38,6 +40,7 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( recovery_mode_e rec_mode_d, rec_mode_q; logic instr_lock_d, instr_lock_q; + logic backup_csr_enable_d, backup_csr_enable_q; logic backup_pc_enable_d, backup_pc_enable_q; logic setback_d, setback_q; logic addr_gen_done; @@ -64,15 +67,18 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( assign instr_lock_o = instr_lock_q; + assign backup_csr_enable_o = backup_csr_enable_q; assign backup_pc_enable_o = backup_pc_enable_q; assign setback_o = setback_q; always_comb begin rec_mode_d = rec_mode_q; instr_lock_d = instr_lock_q; + backup_csr_enable_d = backup_csr_enable_q; backup_pc_enable_d = backup_pc_enable_q; 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; @@ -82,6 +88,8 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( IDLE: begin // If requested start the routine in the reset state if (start_recovery_i) begin + // Disable reading for the backup CSR + backup_csr_enable_d = 1'b0; // Disable reading for the backup PC backup_pc_enable_d = 1'b0; rec_mode_d = RESET; @@ -107,6 +115,8 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( 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 @@ -114,6 +124,7 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( // If recovery routine complete, continue if (addr_gen_done) begin instr_lock_d = 1'b0; + backup_csr_enable_d = 1'b1; backup_pc_enable_d = 1'b1; rec_mode_d = IDLE; debug_resume_o = 1'b1; @@ -127,11 +138,13 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( if (!rst_ni) begin instr_lock_q <= 1'b0; rec_mode_q <= IDLE; + backup_csr_enable_q <= 1'b1; backup_pc_enable_q <= 1'b1; setback_q <= 1'b0; end else begin instr_lock_q <= instr_lock_d; rec_mode_q <= rec_mode_d; + backup_csr_enable_q <= backup_csr_enable_d; backup_pc_enable_q <= backup_pc_enable_d; setback_q <= setback_d; end diff --git a/rtl/HMR/recovery_csr.sv b/rtl/HMR/recovery_csr.sv new file mode 100644 index 00000000..8ef95555 --- /dev/null +++ b/rtl/HMR/recovery_csr.sv @@ -0,0 +1,151 @@ +/* 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 + * + */ + +import recovery_pkg::*; + +module recovery_csr #( + parameter ECCEnabled = 0, + parameter NonProtectedWidth = 32, + parameter ProtectedWidth = 39, + localparam 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_pkg.sv b/rtl/HMR/recovery_pkg.sv index f3ec4ac5..68dfc77a 100644 --- a/rtl/HMR/recovery_pkg.sv +++ b/rtl/HMR/recovery_pkg.sv @@ -15,8 +15,13 @@ package 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 @@ -39,15 +44,24 @@ typedef struct packed { logic [DataWidth-1:0] rdata_b; } regfile_rdata_t; -typedef enum logic [RecoveryStateBits-1:0]{ - IDLE , - RESET , - HALT_REQ , - HALT_WAIT , - RESTORE_PC , - RESTORE_RF , - RESTORE_CSR, - EXIT -} recovery_routine_state_e; +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; endpackage From 6dbbd738ff14645a81443ae1b57326e3a56908fd Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 6 Feb 2023 14:15:31 +0100 Subject: [PATCH 20/72] Add multibit setback, enable ungroup setback --- rtl/HMR/HMR_wrap.sv | 20 +++++++++++++++----- rtl/HMR/hmr_dmr_ctrl.sv | 15 +++++++++------ rtl/HMR/hmr_tmr_ctrl.sv | 19 +++++++++++-------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 5bedda40..6ea3f327 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -193,6 +193,11 @@ module HMR_wrap import recovery_pkg::*; #( 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); @@ -203,10 +208,15 @@ module HMR_wrap import recovery_pkg::*; #( else return (group_id * 2) + core_offset; endfunction - function int dmr_shared_id(int group_id); + 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 / NumTMRGroups; + 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; @@ -335,11 +345,11 @@ module HMR_wrap import recovery_pkg::*; #( logic [NumCores-1:0] dmr_core_rapid_recovery_en; logic [NumCores-1:0] tmr_core_rapid_recovery_en; - logic [NumDMRGroups-1:0] dmr_setback_q; + 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] tmr_setback_q; + 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; @@ -1170,10 +1180,10 @@ module HMR_wrap import recovery_pkg::*; #( // Special signals if (RapidRecovery) begin - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)] + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)] | recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; end else begin - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]; end end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode // CTRL diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index e7ffed29..101d7daf 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -35,7 +35,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( input logic force_recovery_qe_i, // DMR control signals - output logic setback_o, + output logic [1:0] setback_o, output logic sw_resynch_req_o, output logic sw_synch_req_o, output logic grp_in_independent_o, @@ -56,12 +56,11 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( hmr_dmr_regs_reg_pkg::hmr_dmr_regs_hw2reg_t dmr_hw2reg; dmr_mode_e dmr_red_mode_d, dmr_red_mode_q; - logic dmr_setback_d, dmr_setback_q; + logic [1:0] dmr_setback_d, dmr_setback_q; assign setback_o = dmr_setback_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 = dmr_reg2hw.dmr_enable.q & dmr_red_mode_q == NON_DMR; hmr_dmr_regs_reg_top #( .reg_req_t(reg_req_t), @@ -88,11 +87,12 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( **************************/ always_comb begin : proc_fsm - dmr_setback_d = 1'b0; + dmr_setback_d = 2'b00; dmr_red_mode_d = dmr_red_mode_q; dmr_incr_mismatches_o = '0; recovery_request_o = 1'b0; sw_resynch_req_o = 1'b0; + sw_synch_req_o = 1'b0; dmr_hw2reg.dmr_config.force_recovery.de = force_recovery_qe_i; @@ -141,12 +141,15 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( if (dmr_red_mode_q == DMR_RUN) begin if (dmr_reg2hw.dmr_enable.q == 1'b0) begin dmr_red_mode_d = NON_DMR; + dmr_setback_d = 2'b10; end end // Set DMR mode on external signal that cores are synchronized - if (dmr_red_mode_q == NON_DMR && cores_synch_i) begin - if (dmr_reg2hw.dmr_enable.q == 1'b1) begin + if (dmr_red_mode_q == NON_DMR && dmr_reg2hw.dmr_enable.q == 1'b1) begin + sw_synch_req_o = 1'b1; + if (cores_synch_i == 1'b1) begin dmr_red_mode_d = DMR_RUN; + dmr_setback_d = 2'b11; end end end diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 12f78194..3aa64a66 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -41,7 +41,7 @@ module hmr_tmr_ctrl #( input logic force_resynch_qe_i, // TMR control signals - output logic setback_o, + output logic [2:0] setback_o, output logic sw_resynch_req_o, output logic sw_synch_req_o, output logic grp_in_independent_o, @@ -63,7 +63,7 @@ module hmr_tmr_ctrl #( hmr_tmr_regs_reg_pkg::hmr_tmr_regs_hw2reg_t tmr_hw2reg; tmr_mode_e tmr_red_mode_d, tmr_red_mode_q; - logic tmr_setback_d, tmr_setback_q; + logic [2:0] tmr_setback_d, tmr_setback_q; assign setback_o = tmr_setback_q; assign grp_in_independent_o = tmr_red_mode_q == NON_TMR; @@ -100,7 +100,7 @@ module hmr_tmr_ctrl #( * FSM for TMR lockstep * **************************/ always_comb begin : proc_fsm - tmr_setback_d = 1'b0; + tmr_setback_d = 3'b000; tmr_red_mode_d = tmr_red_mode_q; tmr_incr_mismatches_o = '0; sw_resynch_req_o = 1'b0; @@ -139,7 +139,7 @@ module hmr_tmr_ctrl #( if (!sp_store_is_zero) begin tmr_red_mode_d = TMR_RELOAD; if (tmr_reg2hw.tmr_config.setback.q) begin - tmr_setback_d = 1'b1; + tmr_setback_d = 3'b111; end end end @@ -153,7 +153,7 @@ module hmr_tmr_ctrl #( 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 - tmr_setback_d = 1'b1; + tmr_setback_d = 3'b111; end end end @@ -175,16 +175,19 @@ module hmr_tmr_ctrl #( // 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 + tmr_setback_d = 3'b110; + end tmr_red_mode_d = NON_TMR; end end // 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 sw_synch_req_o = 1'b1; - if (cores_synch_i) begin + if (cores_synch_i == 1'b1) begin tmr_red_mode_d = TMR_RELOAD; - if (tmr_reg2hw.tmr_config.setback.q) begin - tmr_setback_d = 1'b1; + if (tmr_reg2hw.tmr_config.setback.q == 1'b1) begin + tmr_setback_d = 3'b111; end end end From cb58b145af9b9b03b1781a18dcc625e6b9f63efa Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 6 Feb 2023 19:04:14 +0100 Subject: [PATCH 21/72] Continually back up cores in interleaved mode --- rtl/HMR/HMR_wrap.sv | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 6ea3f327..8825180f 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -769,7 +769,7 @@ module HMR_wrap import recovery_pkg::*; #( ); /****************** - * DMR PC Checker * + * Recovery Checker * ******************/ DMR_checker # ( .DataWidth ( DataWidth ) @@ -983,6 +983,21 @@ module HMR_wrap import recovery_pkg::*; #( dmr_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_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_program_counter_int [dmr_shared_id(i)] = dmr_backup_program_counter [i]; From 03f71e92f9bd9ef249163428ebed843e58ec59ea Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 6 Feb 2023 19:05:08 +0100 Subject: [PATCH 22/72] Fix setback signals for proper ungrouping Squashing all DMR checkers into only one. Small cleanup. --- rtl/HMR/HMR_wrap.sv | 322 ++++++++++++----------------- rtl/HMR/hmr_dmr_ctrl.sv | 10 +- rtl/HMR/hmr_rapid_recovery_ctrl.sv | 23 +-- rtl/HMR/hmr_tmr_ctrl.sv | 14 +- 4 files changed, 146 insertions(+), 223 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 8825180f..7d397534 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -221,10 +221,13 @@ module HMR_wrap import recovery_pkg::*; #( 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 = SeparateData ? CtrlConcatWidth : - CtrlConcatWidth + DataConcatWidth; + localparam int unsigned MainConcatWidth = RapidRecoveryConcatWidth + + (SeparateData ? CtrlConcatWidth + : CtrlConcatWidth + DataConcatWidth); localparam int unsigned RFAddrWidth = 6; @@ -270,24 +273,16 @@ module HMR_wrap import recovery_pkg::*; #( 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_csr_error, - dmr_backup_program_counter_error, - dmr_backup_branch_error, - dmr_backup_branch_addr_error, - dmr_backup_regfile_error_a, - dmr_backup_regfile_error_b, - dmr_backup_regfile_addr_error_a, - dmr_backup_regfile_addr_error_b, - dmr_backup_branch_int, - dmr_start_recovery, - dmr_backup_regfile_we_a, - dmr_backup_regfile_we_b, - dmr_recovery_finished; + 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][ DataWidth-1:0] tmr_backup_program_counter; logic [NumBackupRegfiles-1:0][RFAddrWidth-1:0] backup_regfile_waddr_a, backup_regfile_waddr_b; @@ -302,34 +297,66 @@ module HMR_wrap import recovery_pkg::*; #( backup_regfile_we_b, backup_program_counter_error, recovery_branch_out, - backup_csr_enable_out, - backup_pc_enable_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, // TODO: for regfile only?!? + 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] dmr_backup_csr, recovery_csr_out; + csrs_intf_t [NumBackupRegfiles-1:0] backup_csr_int, dmr_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]}; + 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]}; + 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]}; + 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 @@ -731,127 +758,53 @@ module HMR_wrap import recovery_pkg::*; #( ); 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] } - = main_dmr_out[i]; + = main_dmr_out[i][MainConcatWidth-1:MainConcatWidth-CtrlConcatWidth]; 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_error_data[i] = 3'b000; 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]} - = main_dmr_out[i]; + = main_dmr_out[i][MainConcatWidth-1:MainConcatWidth-(CtrlConcatWidth+DataConcatWidth)]; 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]) | - dmr_backup_csr_error [i] | - dmr_backup_program_counter_error[i] | - dmr_backup_branch_error [i] | - dmr_backup_branch_addr_error [i] | - dmr_backup_regfile_error_a [i] | - dmr_backup_regfile_error_b [i] | - dmr_backup_regfile_addr_error_a [i] | - dmr_backup_regfile_addr_error_b [i]; - - /******************** - * DMR CSRs Checker * - ********************/ - DMR_CSR_checker dmr_csr_checker ( - .csr_a_i ( backup_csr_i[dmr_core_id(i, 0)] ), - .csr_b_i ( backup_csr_i[dmr_core_id(i, 1)] ), - .check_o ( dmr_backup_csr [i] ), - .error_o ( dmr_backup_csr_error [i] ) - ); - - /****************** - * Recovery Checker * - ******************/ - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_pc_checker ( - .inp_a_i ( backup_program_counter_i[dmr_core_id(i, 0)] ), - .inp_b_i ( backup_program_counter_i[dmr_core_id(i, 1)] ), - .check_o ( dmr_backup_program_counter [i] ), - .error_o ( dmr_backup_program_counter_error [i] ) - ); - - /********************** - * DMR Branch Checker * - **********************/ - DMR_checker # ( - .DataWidth ( 1 ) - ) dmr_branch_checker ( - .inp_a_i ( backup_branch_i[dmr_core_id(i, 0)] ), - .inp_b_i ( backup_branch_i[dmr_core_id(i, 1)] ), - .check_o ( dmr_backup_branch_int [i] ), - .error_o ( dmr_backup_branch_error [i] ) - ); - - /***************************** - * DMR Branch Address Checker * - ******************************/ - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_branch_addr_checker ( - .inp_a_i ( backup_branch_addr_i[dmr_core_id(i, 0)] ), - .inp_b_i ( backup_branch_addr_i[dmr_core_id(i, 1)] ), - .check_o ( dmr_backup_branch_addr_int [i] ), - .error_o ( dmr_backup_branch_addr_error [i] ) - ); - - /******************* - * DMR RF Checkers * - *******************/ - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_rf_checker_port_a ( - .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_a ), - .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_a ), - .check_o ( dmr_backup_regfile_wdata_a [i] ), - .error_o ( dmr_backup_regfile_error_a [i] ) - ); - - DMR_checker # ( - .DataWidth ( RFAddrWidth ) - ) dmr_rf_checker_addr_port_a ( - .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_a ), - .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].waddr_a ), - .check_o ( dmr_backup_regfile_waddr_a [i] ), - .error_o ( dmr_backup_regfile_addr_error_a [i] ) - ); - - DMR_checker # ( - .DataWidth ( DataWidth ) - ) dmr_rf_checker_port_b ( - .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].wdata_b ), - .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].wdata_b ), - .check_o ( dmr_backup_regfile_wdata_b [i] ), - .error_o ( dmr_backup_regfile_error_b [i] ) - ); - - DMR_checker # ( - .DataWidth ( RFAddrWidth ) - ) dmr_rf_checker_addr_port_b ( - .inp_a_i ( backup_regfile_wport_i[dmr_core_id(i, 0)].waddr_b ), - .inp_b_i ( backup_regfile_wport_i[dmr_core_id(i, 1)].waddr_b ), - .check_o ( dmr_backup_regfile_waddr_b [i] ), - .error_o ( dmr_backup_regfile_addr_error_b [i] ) - ); + : dmr_failure_main[i]) ; + // Write Enable signal for backup registers + assign rapid_recovery_backup_enable[i] = tmr_core_rapid_recovery_en[i] ? backup_enable[i] // TMR mode + : dmr_core_rapid_recovery_en[i] ? (backup_enable[i] & ~dmr_failure[i] ) // DMR mode + : 1'b1; // Independent mode + // Building checked singals back from DMR checker + // CSRs + assign dmr_backup_csr[i].csr_mstatus = main_dmr_out[i][305:299]; + assign dmr_backup_csr[i].csr_mie = main_dmr_out[i][298:267]; + assign dmr_backup_csr[i].csr_mtvec = main_dmr_out[i][266:243]; + assign dmr_backup_csr[i].csr_mscratch = main_dmr_out[i][242:211]; + assign dmr_backup_csr[i].csr_mip = main_dmr_out[i][210:179]; + assign dmr_backup_csr[i].csr_mepc = main_dmr_out[i][178:147]; + assign dmr_backup_csr[i].csr_mcause = main_dmr_out[i][146:141]; + // PC + assign dmr_backup_program_counter[i] = main_dmr_out[i][140:109]; + assign dmr_backup_branch_int [i] = main_dmr_out[i][ 108]; + assign dmr_backup_branch_addr_int[i] = main_dmr_out[i][107: 76]; + // RF + assign dmr_backup_regfile_wdata_a[i] = main_dmr_out[i][75:44]; + assign dmr_backup_regfile_waddr_a[i] = main_dmr_out[i][43:38]; + assign dmr_backup_regfile_wdata_b[i] = main_dmr_out[i][37:6]; + assign dmr_backup_regfile_waddr_b[i] = main_dmr_out[i][5:0]; 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_backup_regfile_error_a [i] - & ~dmr_backup_regfile_addr_error_a [i]; + & ~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_backup_regfile_error_b [i] - & ~dmr_backup_regfile_addr_error_b [i]; + & ~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]) @@ -892,8 +845,7 @@ module HMR_wrap import recovery_pkg::*; #( .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_csr_enable_o ( backup_csr_enable_out [i] ), - .backup_pc_enable_o ( backup_pc_enable_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] ) @@ -905,13 +857,12 @@ module HMR_wrap import recovery_pkg::*; #( recovery_csr #( .ECCEnabled ( 1 ) ) RCSR ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .read_enable_i ( recovery_csr_enable_out [i] ), - .write_enable_i ( ~dmr_backup_csr_error [i] - & backup_csr_enable_out [i] ), - .backup_csr_i ( dmr_backup_csr [i] ), - .recovery_csr_o ( recovery_csr_out [i] ) + .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] ) ); /**************************** @@ -924,9 +875,8 @@ module HMR_wrap import recovery_pkg::*; #( .clk_i, .rst_ni, .clear_i ( '0 ), - .read_enable_i ( recovery_pc_enable_out [i] ), - .write_enable_i ( ~backup_program_counter_error [i] - & backup_pc_enable_out [i] ), + .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] ), @@ -957,18 +907,21 @@ module HMR_wrap import recovery_pkg::*; #( .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] & ~recovery_trigger_out[i] ), + .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] & ~recovery_trigger_out[i] ) + .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; @@ -1000,8 +953,9 @@ module HMR_wrap import recovery_pkg::*; #( 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_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]; @@ -1019,7 +973,8 @@ module HMR_wrap import recovery_pkg::*; #( 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_program_counter_int [tmr_shared_id(i)] = tmr_backup_program_counter [i]; + // 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_program_counter_error[tmr_shared_id(i)] = tmr_backup_program_counter_error[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]; @@ -1158,6 +1113,18 @@ module HMR_wrap import recovery_pkg::*; #( 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)] + | recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + end else begin + core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]; + end + if (i >= NumTMRCores && RapidRecovery) begin + core_setback_o [i] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + end else if (i >= NumTMRCores) begin + core_setback_o [i] = '0; + end if (i < NumTMRCores && core_in_tmr[i]) begin : tmr_mode // CTRL core_core_id_o [i] = sys_core_id_i [TMRCoreIndex]; @@ -1192,14 +1159,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [TMRCoreIndex]; core_data_r_valid_o [i] = sys_data_r_valid_i [TMRCoreIndex]; core_data_err_o [i] = sys_data_err_i [TMRCoreIndex]; - - // Special signals - if (RapidRecovery) begin - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)] - | recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; - end else begin - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)]; - end end else if (i < NumDMRCores && core_in_dmr[i]) begin : dmr_mode // CTRL core_core_id_o [i] = sys_core_id_i [DMRCoreIndex]; @@ -1234,13 +1193,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [DMRCoreIndex]; core_data_r_valid_o [i] = sys_data_r_valid_i [DMRCoreIndex]; core_data_err_o [i] = sys_data_err_i [DMRCoreIndex]; - - // Special signals - if (RapidRecovery) begin - core_setback_o [i] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; - end else begin - core_setback_o [i] = '0; - end end else begin : independent_mode // CTRL core_core_id_o [i] = sys_core_id_i [i]; @@ -1270,9 +1222,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [i]; core_data_r_valid_o [i] = sys_data_r_valid_i [i]; core_data_err_o [i] = sys_data_err_i [i]; - - // Special signals - core_setback_o [i] = '0; end end end @@ -1391,6 +1340,17 @@ module HMR_wrap import recovery_pkg::*; #( 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 [dmr_shared_id(dmr_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]; @@ -1425,15 +1385,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex]; core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; - - // Special signals - // Setback - if (RapidRecovery) begin - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)] - | recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; - end else begin - core_setback_o [i] = tmr_setback_q [tmr_group_id(i)]; - end end else begin : independent_mode // CTRL core_core_id_o [i] = sys_core_id_i [i]; @@ -1463,9 +1414,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [i]; core_data_r_valid_o [i] = sys_data_r_valid_i [i]; core_data_err_o [i] = sys_data_err_i [i]; - - // Special signals - core_setback_o [i] = '0; end end end @@ -1591,6 +1539,12 @@ module HMR_wrap import recovery_pkg::*; #( 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] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + end else 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]; @@ -1625,13 +1579,6 @@ module HMR_wrap import recovery_pkg::*; #( core_data_r_user_o [i] = sys_data_r_user_i [SysCoreIndex]; core_data_r_valid_o [i] = sys_data_r_valid_i [SysCoreIndex]; core_data_err_o [i] = sys_data_err_i [SysCoreIndex]; - - // Setback - if (RapidRecovery) begin - core_setback_o [i] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; - end else begin - core_setback_o [i] = '0; - end end else begin : gen_independent_mode // CTRL core_core_id_o [i] = sys_core_id_i [i]; @@ -1644,9 +1591,6 @@ module HMR_wrap import recovery_pkg::*; #( core_debug_req_o [i] = sys_debug_req_i [i]; core_perf_counters_o[i] = sys_perf_counters_i[i]; - // Setback - core_setback_o [i] = '0; - // IRQ core_irq_req_o [i] = sys_irq_req_i [i]; core_irq_id_o [i] = sys_irq_id_i [i]; diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 101d7daf..79388963 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -56,9 +56,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( hmr_dmr_regs_reg_pkg::hmr_dmr_regs_hw2reg_t dmr_hw2reg; dmr_mode_e dmr_red_mode_d, dmr_red_mode_q; - logic [1:0] dmr_setback_d, dmr_setback_q; - assign setback_o = dmr_setback_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; @@ -87,7 +85,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( **************************/ always_comb begin : proc_fsm - dmr_setback_d = 2'b00; + setback_o = 2'b00; dmr_red_mode_d = dmr_red_mode_q; dmr_incr_mismatches_o = '0; recovery_request_o = 1'b0; @@ -141,7 +139,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( if (dmr_red_mode_q == DMR_RUN) begin if (dmr_reg2hw.dmr_enable.q == 1'b0) begin dmr_red_mode_d = NON_DMR; - dmr_setback_d = 2'b10; + setback_o = 2'b10; end end // Set DMR mode on external signal that cores are synchronized @@ -149,7 +147,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( sw_synch_req_o = 1'b1; if (cores_synch_i == 1'b1) begin dmr_red_mode_d = DMR_RUN; - dmr_setback_d = 2'b11; + setback_o = 2'b11; end end end @@ -158,10 +156,8 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( always_ff @(posedge clk_i or negedge rst_ni) begin : proc_red_mode if(!rst_ni) begin dmr_red_mode_q <= DefaultDMRMode; - dmr_setback_q <= '0; end else begin dmr_red_mode_q <= dmr_red_mode_d; - dmr_setback_q <= dmr_setback_d; end end diff --git a/rtl/HMR/hmr_rapid_recovery_ctrl.sv b/rtl/HMR/hmr_rapid_recovery_ctrl.sv index 3315e271..e1205ea6 100644 --- a/rtl/HMR/hmr_rapid_recovery_ctrl.sv +++ b/rtl/HMR/hmr_rapid_recovery_ctrl.sv @@ -29,8 +29,7 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( output regfile_write_t recovery_regfile_waddr_o, // Signals to backup state - output logic backup_csr_enable_o, - output logic backup_pc_enable_o, + output logic backup_enable_o, output logic recover_csr_enable_o, output logic recover_pc_enable_o, output logic recover_rf_enable_o @@ -40,8 +39,6 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( recovery_mode_e rec_mode_d, rec_mode_q; logic instr_lock_d, instr_lock_q; - logic backup_csr_enable_d, backup_csr_enable_q; - logic backup_pc_enable_d, backup_pc_enable_q; logic setback_d, setback_q; logic addr_gen_done; logic [RFAddrWidth-1:0] addr_gen_result; @@ -67,15 +64,12 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( assign instr_lock_o = instr_lock_q; - assign backup_csr_enable_o = backup_csr_enable_q; - assign backup_pc_enable_o = backup_pc_enable_q; assign setback_o = setback_q; always_comb begin rec_mode_d = rec_mode_q; instr_lock_d = instr_lock_q; - backup_csr_enable_d = backup_csr_enable_q; - backup_pc_enable_d = backup_pc_enable_q; + backup_enable_o = 1'b0; setback_d = 1'b0; debug_req_o = 1'b0; recover_csr_enable_o = 1'b0; @@ -86,12 +80,11 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( 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 reading for the backup CSR - backup_csr_enable_d = 1'b0; - // Disable reading for the backup PC - backup_pc_enable_d = 1'b0; + // Disable all backups + backup_enable_o = 1'b0; rec_mode_d = RESET; end end @@ -124,8 +117,6 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( // If recovery routine complete, continue if (addr_gen_done) begin instr_lock_d = 1'b0; - backup_csr_enable_d = 1'b1; - backup_pc_enable_d = 1'b1; rec_mode_d = IDLE; debug_resume_o = 1'b1; recovery_finished_o = 1'b1; @@ -138,14 +129,10 @@ module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( if (!rst_ni) begin instr_lock_q <= 1'b0; rec_mode_q <= IDLE; - backup_csr_enable_q <= 1'b1; - backup_pc_enable_q <= 1'b1; setback_q <= 1'b0; end else begin instr_lock_q <= instr_lock_d; rec_mode_q <= rec_mode_d; - backup_csr_enable_q <= backup_csr_enable_d; - backup_pc_enable_q <= backup_pc_enable_d; setback_q <= setback_d; end end diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 3aa64a66..8ac9eaaa 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -63,9 +63,7 @@ module hmr_tmr_ctrl #( hmr_tmr_regs_reg_pkg::hmr_tmr_regs_hw2reg_t tmr_hw2reg; tmr_mode_e tmr_red_mode_d, tmr_red_mode_q; - logic [2:0] tmr_setback_d, tmr_setback_q; - assign setback_o = tmr_setback_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; @@ -100,7 +98,7 @@ module hmr_tmr_ctrl #( * FSM for TMR lockstep * **************************/ always_comb begin : proc_fsm - tmr_setback_d = 3'b000; + setback_o = 3'b000; tmr_red_mode_d = tmr_red_mode_q; tmr_incr_mismatches_o = '0; sw_resynch_req_o = 1'b0; @@ -139,7 +137,7 @@ module hmr_tmr_ctrl #( if (!sp_store_is_zero) begin tmr_red_mode_d = TMR_RELOAD; if (tmr_reg2hw.tmr_config.setback.q) begin - tmr_setback_d = 3'b111; + setback_o = 3'b111; end end end @@ -153,7 +151,7 @@ module hmr_tmr_ctrl #( 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 - tmr_setback_d = 3'b111; + setback_o = 3'b111; end end end @@ -176,7 +174,7 @@ module hmr_tmr_ctrl #( 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 - tmr_setback_d = 3'b110; + setback_o = 3'b110; end tmr_red_mode_d = NON_TMR; end @@ -187,7 +185,7 @@ module hmr_tmr_ctrl #( if (cores_synch_i == 1'b1) begin tmr_red_mode_d = TMR_RELOAD; if (tmr_reg2hw.tmr_config.setback.q == 1'b1) begin - tmr_setback_d = 3'b111; + setback_o = 3'b111; end end end @@ -197,10 +195,8 @@ module hmr_tmr_ctrl #( always_ff @(posedge clk_i or negedge rst_ni) begin : proc_red_mode if(!rst_ni) begin tmr_red_mode_q <= DefaultTMRMode; - tmr_setback_q <= '0; end else begin tmr_red_mode_q <= tmr_red_mode_d; - tmr_setback_q <= tmr_setback_d; end end From be1e9d29592c5ebe857fb24bb20b4bea15c2efce Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 8 Feb 2023 14:14:57 +0100 Subject: [PATCH 23/72] Making cleaner assignments for main_dmr_out bus. --- rtl/HMR/HMR_wrap.sv | 61 ++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 7d397534..fe6d931a 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -623,7 +623,8 @@ module HMR_wrap import recovery_pkg::*; #( ); 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]} = main_tmr_out[i]; + tmr_instr_req_out[i], tmr_instr_addr_out[i], tmr_data_req_out[i]} + = main_tmr_out[i][MainConcatWidth-1:MainConcatWidth-CtrlConcatWidth]; 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 @@ -757,8 +758,24 @@ module HMR_wrap import recovery_pkg::*; #( .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] } - = main_dmr_out[i][MainConcatWidth-1:MainConcatWidth-CtrlConcatWidth]; + 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]; @@ -767,8 +784,24 @@ module HMR_wrap import recovery_pkg::*; #( 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]} - = main_dmr_out[i][MainConcatWidth-1:MainConcatWidth-(CtrlConcatWidth+DataConcatWidth)]; + 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 @@ -779,24 +812,6 @@ module HMR_wrap import recovery_pkg::*; #( assign rapid_recovery_backup_enable[i] = tmr_core_rapid_recovery_en[i] ? backup_enable[i] // TMR mode : dmr_core_rapid_recovery_en[i] ? (backup_enable[i] & ~dmr_failure[i] ) // DMR mode : 1'b1; // Independent mode - // Building checked singals back from DMR checker - // CSRs - assign dmr_backup_csr[i].csr_mstatus = main_dmr_out[i][305:299]; - assign dmr_backup_csr[i].csr_mie = main_dmr_out[i][298:267]; - assign dmr_backup_csr[i].csr_mtvec = main_dmr_out[i][266:243]; - assign dmr_backup_csr[i].csr_mscratch = main_dmr_out[i][242:211]; - assign dmr_backup_csr[i].csr_mip = main_dmr_out[i][210:179]; - assign dmr_backup_csr[i].csr_mepc = main_dmr_out[i][178:147]; - assign dmr_backup_csr[i].csr_mcause = main_dmr_out[i][146:141]; - // PC - assign dmr_backup_program_counter[i] = main_dmr_out[i][140:109]; - assign dmr_backup_branch_int [i] = main_dmr_out[i][ 108]; - assign dmr_backup_branch_addr_int[i] = main_dmr_out[i][107: 76]; - // RF - assign dmr_backup_regfile_wdata_a[i] = main_dmr_out[i][75:44]; - assign dmr_backup_regfile_waddr_a[i] = main_dmr_out[i][43:38]; - assign dmr_backup_regfile_wdata_b[i] = main_dmr_out[i][37:6]; - assign dmr_backup_regfile_waddr_b[i] = main_dmr_out[i][5:0]; 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 From 8d1efa2f6fd319011efee89d94698d49d8912a63 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 8 Feb 2023 14:19:34 +0100 Subject: [PATCH 24/72] Adding first support for TMR rapid recovery (to be fixed). --- rtl/HMR/HMR_wrap.sv | 134 ++++++++++++++++++++++++++++++++-------- rtl/HMR/hmr_tmr_ctrl.sv | 23 +++++-- 2 files changed, 126 insertions(+), 31 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index fe6d931a..2cab24d6 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -283,7 +283,18 @@ module HMR_wrap import recovery_pkg::*; #( dmr_backup_regfile_we_a, dmr_backup_regfile_we_b, dmr_recovery_finished; - logic [ NumTMRGroups-1:0][ DataWidth-1:0] tmr_backup_program_counter; + 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, @@ -313,7 +324,7 @@ module HMR_wrap import recovery_pkg::*; #( 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, recovery_csr_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 @@ -550,7 +561,8 @@ module HMR_wrap import recovery_pkg::*; #( .reg_resp_t ( reg_resp_t ), .TMRFixed ( TMRFixed ), .InterleaveGrps ( InterleaveGrps ), - .DefaultInTMR ( 1'b0 ) + .DefaultInTMR ( 1'b0 ), + .RapidRecovery ( RapidRecovery ) ) i_tmr_ctrl ( .clk_i, .rst_ni, @@ -582,8 +594,12 @@ module HMR_wrap import recovery_pkg::*; #( .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] ) + .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]; @@ -623,8 +639,24 @@ module HMR_wrap import recovery_pkg::*; #( ); 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]} - = main_tmr_out[i][MainConcatWidth-1:MainConcatWidth-CtrlConcatWidth]; + 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 @@ -633,7 +665,54 @@ module HMR_wrap import recovery_pkg::*; #( 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]} = main_tmr_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 @@ -808,10 +887,6 @@ module HMR_wrap import recovery_pkg::*; #( assign dmr_failure [i] = (dmr_data_req_out [i] ? (dmr_failure_main[i] | dmr_failure_data[i]) : dmr_failure_main[i]) ; - // Write Enable signal for backup registers - assign rapid_recovery_backup_enable[i] = tmr_core_rapid_recovery_en[i] ? backup_enable[i] // TMR mode - : dmr_core_rapid_recovery_en[i] ? (backup_enable[i] & ~dmr_failure[i] ) // DMR mode - : 1'b1; // Independent mode 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 @@ -847,6 +922,11 @@ module HMR_wrap import recovery_pkg::*; #( // 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] = tmr_core_rapid_recovery_en[i] ? backup_enable[i] // TMR mode + : dmr_core_rapid_recovery_en[i] ? (backup_enable[i] & ~dmr_failure[i] ) // DMR mode + : 1'b1; // Independent mode + hmr_rapid_recovery_ctrl #( .RFAddrWidth( RFAddrWidth ) ) i_rapid_recovery_ctrl ( @@ -949,6 +1029,7 @@ module HMR_wrap import recovery_pkg::*; #( 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 @@ -988,22 +1069,21 @@ module HMR_wrap import recovery_pkg::*; #( 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_program_counter_error[tmr_shared_id(i)] = tmr_backup_program_counter_error[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)]; + 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 diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 8ac9eaaa..7db4f3ec 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -53,10 +53,12 @@ module hmr_tmr_ctrl #( input logic sp_store_is_zero, input logic sp_store_will_be_zero, input logic fetch_en_i, - input logic cores_synch_i + input logic cores_synch_i, + output logic recovery_request_o, + input logic recovery_finished_i ); - typedef enum logic [1:0] {NON_TMR, TMR_RUN, TMR_UNLOAD, TMR_RELOAD} tmr_mode_e; + 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; @@ -101,6 +103,7 @@ module hmr_tmr_ctrl #( setback_o = 3'b000; tmr_red_mode_d = tmr_red_mode_q; tmr_incr_mismatches_o = '0; + recovery_request_o = 1'b0; sw_resynch_req_o = 1'b0; sw_synch_req_o = 1'b0; @@ -111,7 +114,9 @@ module hmr_tmr_ctrl #( // 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.delay_resynch.q == '0) begin + if (tmr_reg2hw.tmr_config.rapid_recovery.q == 1'b1) 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 @@ -124,7 +129,9 @@ module hmr_tmr_ctrl #( 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.delay_resynch == 0) begin + if (tmr_reg2hw.tmr_config.rapid_recovery.q == 1'b1) 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 @@ -156,6 +163,14 @@ module hmr_tmr_ctrl #( 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 From 7f8679940b62471ae26f37de2933dc3667f9d6ba Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 8 Feb 2023 16:08:16 +0100 Subject: [PATCH 25/72] Ensure sw_synch interrupt stays 0 before boot --- rtl/HMR/hmr_dmr_ctrl.sv | 17 +++++++++-------- rtl/HMR/hmr_tmr_ctrl.sv | 21 +++++++++++---------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 79388963..ffbc5d41 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -127,11 +127,20 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( // 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 + sw_synch_req_o = 1'b1; + if (cores_synch_i == 1'b1) begin + dmr_red_mode_d = DMR_RUN; + setback_o = 2'b11; + 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 + sw_synch_req_o = 1'b0; dmr_red_mode_d = DMR_RUN; end end @@ -142,14 +151,6 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( setback_o = 2'b10; end end - // 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 - sw_synch_req_o = 1'b1; - if (cores_synch_i == 1'b1) begin - dmr_red_mode_d = DMR_RUN; - setback_o = 2'b11; - end - end end end diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 7db4f3ec..998f32db 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -177,12 +177,23 @@ module hmr_tmr_ctrl #( // 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 + sw_synch_req_o = 1'b1; + if (cores_synch_i == 1'b1) begin + tmr_red_mode_d = TMR_RELOAD; + if (tmr_reg2hw.tmr_config.setback.q == 1'b1) begin + setback_o = 3'b111; + 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; + sw_synch_req_o = 1'b0; end end // split tolerant mode to performance mode anytime (but require correct core state) @@ -194,16 +205,6 @@ module hmr_tmr_ctrl #( tmr_red_mode_d = NON_TMR; end end - // 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 - sw_synch_req_o = 1'b1; - if (cores_synch_i == 1'b1) 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 end From ce3ea38c38c3bb38b89a6481207f2d42bb611451 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 9 Feb 2023 16:20:48 +0100 Subject: [PATCH 26/72] Add response suppress module Add response filter to HMR --- Bender.yml | 1 + rtl/HMR/HMR_wrap.sv | 55 ++++++++++++++++++++++++++++------------ rtl/HMR/resp_suppress.sv | 52 +++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 rtl/HMR/resp_suppress.sv diff --git a/Bender.yml b/Bender.yml index 4ef1b8cb..e81fd859 100644 --- a/Bender.yml +++ b/Bender.yml @@ -24,6 +24,7 @@ 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 diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 2cab24d6..a14118ac 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -372,6 +372,29 @@ module HMR_wrap import recovery_pkg::*; #( end end + logic [NumSysCores-1:0] filt_instr_r_valid, filt_data_r_valid; + + for (genvar i = 0; i < NumSysCores; i++) begin + resp_suppress i_instr_suppress ( + .clk_i, + .rst_ni, + .setback_i (core_setback_o[i]), + .req_i (sys_instr_req_o[i]), + .gnt_i (sys_instr_gnt_i[i]), + .r_valid_i (sys_instr_r_valid_i[i]), + .r_valid_o (filt_instr_r_valid[i]) + ); + resp_suppress i_data_suppress ( + .clk_i, + .rst_ni, + .setback_i (core_setback_o[i]), + .req_i (sys_data_req_o[i]), + .gnt_i (sys_data_gnt_i[i]), + .r_valid_i (sys_data_r_valid_i[i]), + .r_valid_o (filt_data_r_valid[i]) + ); + end + /*************************** * HMR Control Registers * ***************************/ @@ -1244,7 +1267,7 @@ module HMR_wrap import recovery_pkg::*; #( // INSTR core_instr_gnt_o [i] = sys_instr_gnt_i [TMRCoreIndex]; core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[TMRCoreIndex]; - core_instr_r_valid_o[i] = sys_instr_r_valid_i[TMRCoreIndex]; + core_instr_r_valid_o[i] = filt_instr_r_valid[TMRCoreIndex]; core_instr_err_o [i] = sys_instr_err_i [TMRCoreIndex]; // DATA @@ -1252,7 +1275,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] = sys_data_r_valid_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 @@ -1278,7 +1301,7 @@ module HMR_wrap import recovery_pkg::*; #( // INSTR core_instr_gnt_o [i] = sys_instr_gnt_i [DMRCoreIndex]; core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[DMRCoreIndex]; - core_instr_r_valid_o[i] = sys_instr_r_valid_i[DMRCoreIndex]; + core_instr_r_valid_o[i] = filt_instr_r_valid[DMRCoreIndex]; core_instr_err_o [i] = sys_instr_err_i [DMRCoreIndex]; // DATA @@ -1286,7 +1309,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] = sys_data_r_valid_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 @@ -1307,7 +1330,7 @@ module HMR_wrap import recovery_pkg::*; #( // INSTR core_instr_gnt_o [i] = sys_instr_gnt_i [i]; core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; - core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; + core_instr_r_valid_o[i] = filt_instr_r_valid[i]; core_instr_err_o [i] = sys_instr_err_i [i]; // DATA @@ -1315,7 +1338,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] = sys_data_r_valid_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 @@ -1470,7 +1493,7 @@ module HMR_wrap import recovery_pkg::*; #( // INSTR core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[SysCoreIndex]; - core_instr_r_valid_o[i] = sys_instr_r_valid_i[SysCoreIndex]; + core_instr_r_valid_o[i] = filt_instr_r_valid[SysCoreIndex]; core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; // DATA @@ -1478,7 +1501,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] = sys_data_r_valid_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 @@ -1499,7 +1522,7 @@ module HMR_wrap import recovery_pkg::*; #( // INSTR core_instr_gnt_o [i] = sys_instr_gnt_i [i]; core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; - core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; + core_instr_r_valid_o[i] = filt_instr_r_valid[i]; core_instr_err_o [i] = sys_instr_err_i [i]; // DATA @@ -1507,7 +1530,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] = sys_data_r_valid_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 @@ -1664,7 +1687,7 @@ module HMR_wrap import recovery_pkg::*; #( // INSTR core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; core_instr_r_rdata_o[i] = sys_instr_r_rdata_i [SysCoreIndex]; - core_instr_r_valid_o[i] = sys_instr_r_valid_i [SysCoreIndex]; + core_instr_r_valid_o[i] = filt_instr_r_valid [SysCoreIndex]; core_instr_err_o [i] = sys_instr_err_i [SysCoreIndex]; // DATA @@ -1672,7 +1695,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] = sys_data_r_valid_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 @@ -1693,7 +1716,7 @@ module HMR_wrap import recovery_pkg::*; #( // INSTR core_instr_gnt_o [i] = sys_instr_gnt_i [i]; core_instr_r_rdata_o[i] = sys_instr_r_rdata_i[i]; - core_instr_r_valid_o[i] = sys_instr_r_valid_i[i]; + core_instr_r_valid_o[i] = filt_instr_r_valid[i]; core_instr_err_o [i] = sys_instr_err_i [i]; // DATA @@ -1701,7 +1724,7 @@ module HMR_wrap import recovery_pkg::*; #( 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] = sys_data_r_valid_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 @@ -1845,7 +1868,7 @@ module HMR_wrap import recovery_pkg::*; #( assign core_instr_gnt_o = sys_instr_gnt_i; assign sys_instr_addr_o = core_instr_addr_i; assign core_instr_r_rdata_o = sys_instr_r_rdata_i; - assign core_instr_r_valid_o = sys_instr_r_valid_i; + assign core_instr_r_valid_o = filt_instr_r_valid; assign core_instr_err_o = sys_instr_err_i; // DATA @@ -1859,7 +1882,7 @@ module HMR_wrap import recovery_pkg::*; #( 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 = sys_data_r_valid_i; + assign core_data_r_valid_o = filt_data_r_valid; assign core_data_err_o = sys_data_err_i; end diff --git a/rtl/HMR/resp_suppress.sv b/rtl/HMR/resp_suppress.sv new file mode 100644 index 00000000..1144373e --- /dev/null +++ b/rtl/HMR/resp_suppress.sv @@ -0,0 +1,52 @@ +// 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 +) ( + input logic clk_i, + input logic rst_ni, + + input logic setback_i, + input logic req_i, + input logic gnt_i, + input logic r_valid_i, + output logic r_valid_o +); + + logic [$clog2(NumOutstanding)-1:0] outstanding_d, outstanding_q; + logic block_d, block_q; + + assign outstanding_d = outstanding_q + (req_i & gnt_i ? 1 : 0) - (r_valid_i ? 1 : 0); + + assign r_valid_o = block_q ? 1'b0 : r_valid_i; + + always_comb begin + block_d = block_q; + if (setback_i) begin + block_d = 1'b1; + end else if (outstanding_q == 0) 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; + end else begin + outstanding_q <= outstanding_d; + block_q <= block_d; + end + end + +endmodule From 65583403dca63d0ce18818f356335c774fcfcb62 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 9 Feb 2023 17:27:06 +0100 Subject: [PATCH 27/72] TMR: only trigger a single interrupt --- rtl/HMR/HMR_wrap.sv | 2 +- rtl/HMR/hmr_tmr_ctrl.sv | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index a14118ac..9bdfb363 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -652,7 +652,7 @@ module HMR_wrap import recovery_pkg::*; #( bitwise_TMR_voter #( .DataWidth( DataConcatWidth ), .VoterType( 0 ) - ) i_main_voter ( + ) 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)] ), diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 998f32db..3a24356d 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -58,6 +58,9 @@ module hmr_tmr_ctrl #( 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; + 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; @@ -70,6 +73,11 @@ module hmr_tmr_ctrl #( 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) @@ -104,8 +112,8 @@ module hmr_tmr_ctrl #( tmr_red_mode_d = tmr_red_mode_q; tmr_incr_mismatches_o = '0; recovery_request_o = 1'b0; - sw_resynch_req_o = 1'b0; - sw_synch_req_o = 1'b0; + resynch_req = 1'b0; + synch_req = 1'b0; tmr_hw2reg.tmr_config.force_resynch.de = force_resynch_qe_i; @@ -139,7 +147,7 @@ module hmr_tmr_ctrl #( end TMR_UNLOAD: begin - sw_resynch_req_o = 1'b1; + resynch_req = 1'b1; // If unload complete, go to reload (and reset) if (!sp_store_is_zero) begin tmr_red_mode_d = TMR_RELOAD; @@ -179,7 +187,7 @@ module hmr_tmr_ctrl #( 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 - sw_synch_req_o = 1'b1; + synch_req = 1'b1; if (cores_synch_i == 1'b1) begin tmr_red_mode_d = TMR_RELOAD; if (tmr_reg2hw.tmr_config.setback.q == 1'b1) begin @@ -193,7 +201,7 @@ module hmr_tmr_ctrl #( tmr_red_mode_d = NON_TMR; end else begin tmr_red_mode_d = TMR_RUN; - sw_synch_req_o = 1'b0; + synch_req = 1'b0; end end // split tolerant mode to performance mode anytime (but require correct core state) @@ -211,8 +219,12 @@ module hmr_tmr_ctrl #( 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; 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; end end From eb0d05817f33d755d8f704a2eff30aa8ddabe651 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 9 Feb 2023 17:29:50 +0100 Subject: [PATCH 28/72] DMR: only trigger a single interrupt --- rtl/HMR/hmr_dmr_ctrl.sv | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index ffbc5d41..0de7c40f 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -49,6 +49,9 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( 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; + 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; @@ -60,6 +63,11 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( 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; + hmr_dmr_regs_reg_top #( .reg_req_t(reg_req_t), .reg_rsp_t(reg_resp_t) @@ -89,8 +97,8 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( dmr_red_mode_d = dmr_red_mode_q; dmr_incr_mismatches_o = '0; recovery_request_o = 1'b0; - sw_resynch_req_o = 1'b0; - sw_synch_req_o = 1'b0; + resynch_req = 1'b0; + synch_req = 1'b0; dmr_hw2reg.dmr_config.force_recovery.de = force_recovery_qe_i; @@ -110,7 +118,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( if (dmr_error_i && (!RapidRecovery || !dmr_reg2hw.dmr_config.rapid_recovery.q)) begin $display("[HMR-dual] %t - mismatch detected, SW trigger", $realtime); - sw_resynch_req_o = 1'b1; + resynch_req = 1'b1; end end @@ -129,7 +137,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( 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 - sw_synch_req_o = 1'b1; + synch_req = 1'b1; if (cores_synch_i == 1'b1) begin dmr_red_mode_d = DMR_RUN; setback_o = 2'b11; @@ -140,7 +148,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( if (dmr_reg2hw.dmr_enable.q == 1'b0) begin dmr_red_mode_d = NON_DMR; end else begin - sw_synch_req_o = 1'b0; + synch_req = 1'b0; dmr_red_mode_d = DMR_RUN; end end @@ -157,8 +165,12 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( 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; 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; end end From 4eed8a57c08580360c0256d70a02764e9d782c73 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 9 Feb 2023 19:22:29 +0100 Subject: [PATCH 29/72] TMR: buffer cores_synch signal DMR: buffer cores_synch signal --- rtl/HMR/hmr_dmr_ctrl.sv | 5 ++++- rtl/HMR/hmr_tmr_ctrl.sv | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 0de7c40f..3be7f7b3 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -51,6 +51,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( 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; @@ -138,7 +139,7 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( // 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_i == 1'b1) begin + if (cores_synch_q == 1'b1) begin dmr_red_mode_d = DMR_RUN; setback_o = 2'b11; end @@ -167,10 +168,12 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( 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 diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index 3a24356d..ef133d46 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -60,6 +60,7 @@ module hmr_tmr_ctrl #( 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; @@ -188,7 +189,7 @@ module hmr_tmr_ctrl #( // 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_i == 1'b1) begin + if (cores_synch_q == 1'b1) begin tmr_red_mode_d = TMR_RELOAD; if (tmr_reg2hw.tmr_config.setback.q == 1'b1) begin setback_o = 3'b111; @@ -221,10 +222,12 @@ module hmr_tmr_ctrl #( 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 From 638eada24763e51acc6c6cd6b160b6f764d8b64e Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 10 Feb 2023 11:17:07 +0100 Subject: [PATCH 30/72] Connect rapid recovery synch signals --- rtl/HMR/hmr_dmr_ctrl.sv | 8 ++++++-- rtl/HMR/hmr_tmr_ctrl.sv | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 3be7f7b3..ab7992e9 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -140,8 +140,12 @@ module hmr_dmr_ctrl import recovery_pkg::*; #( 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 - dmr_red_mode_d = DMR_RUN; - setback_o = 2'b11; + 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 diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index ef133d46..e915b9d9 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -190,9 +190,13 @@ module hmr_tmr_ctrl #( 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 - tmr_red_mode_d = TMR_RELOAD; - if (tmr_reg2hw.tmr_config.setback.q == 1'b1) begin - setback_o = 3'b111; + if (tmr_reg2hw.tmr_config.rapid_recovery.q == 1'b1) 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 From d6d211684684d99342f6027785e4457c85849b19 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 13 Feb 2023 14:16:44 +0100 Subject: [PATCH 31/72] HMR: fix minor DMR naming error --- rtl/HMR/HMR_dmr_regs.hjson | 4 ++-- rtl/HMR/hmr_v1.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rtl/HMR/HMR_dmr_regs.hjson b/rtl/HMR/HMR_dmr_regs.hjson index 682c4b5b..12e16d44 100644 --- a/rtl/HMR/HMR_dmr_regs.hjson +++ b/rtl/HMR/HMR_dmr_regs.hjson @@ -19,8 +19,8 @@ resval: "0", fields: [ { bits: "0", - name: "TMR_enable", - desc: "TMR configuration enable." + name: "DMR_enable", + desc: "DMR configuration enable." } ] }, diff --git a/rtl/HMR/hmr_v1.h b/rtl/HMR/hmr_v1.h index ec4f2d7e..7a4e0bfa 100644 --- a/rtl/HMR/hmr_v1.h +++ b/rtl/HMR/hmr_v1.h @@ -137,7 +137,7 @@ extern "C" { // DMR configuration enable. #define HMR_DMR_REGS_DMR_ENABLE_REG_OFFSET 0x0 -#define HMR_DMR_REGS_DMR_ENABLE_TMR_ENABLE_BIT 0 +#define HMR_DMR_REGS_DMR_ENABLE_DMR_ENABLE_BIT 0 // DMR configuration bits. #define HMR_DMR_REGS_DMR_CONFIG_REG_OFFSET 0x4 From e8694c787fea850d4c285a0c8249b463b8f96cab Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 15 Feb 2023 16:57:25 +0100 Subject: [PATCH 32/72] HMR: Fix DMR setback connections --- rtl/HMR/HMR_wrap.sv | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 9bdfb363..427c1695 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -213,7 +213,7 @@ module HMR_wrap import recovery_pkg::*; #( endfunction function int dmr_offset_id (int core_id); - if (InterleaveGrps) return core_id / NumTMRGroups; + if (InterleaveGrps) return core_id / NumDMRGroups; else return core_id % 2; endfunction @@ -1234,14 +1234,21 @@ module HMR_wrap import recovery_pkg::*; #( // Special signals if (RapidRecovery) begin core_setback_o [i] = tmr_setback_q [tmr_group_id(i)][tmr_offset_id(i)] - | recovery_setback_out [dmr_shared_id(dmr_group_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)]; + 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 && RapidRecovery) begin - core_setback_o [i] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; - end else if (i >= NumTMRCores) begin - core_setback_o [i] = '0; + 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 @@ -1462,7 +1469,7 @@ module HMR_wrap import recovery_pkg::*; #( // Setback if (RapidRecovery) begin core_setback_o [i] = tmr_setback_q [tmr_group_id(i)] - | recovery_setback_out [dmr_shared_id(dmr_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 @@ -1659,10 +1666,14 @@ module HMR_wrap import recovery_pkg::*; #( always_comb begin // Setback if (RapidRecovery) begin - core_setback_o [i] = recovery_setback_out [dmr_shared_id(dmr_group_id(i))]; + 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]; From 88fa97438d18c5f5f40218fe092aceda72704d1f Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 16 Feb 2023 17:01:00 +0100 Subject: [PATCH 33/72] Always backup when dmr/tmr is disabled Back up csr when dmr/tmr is disabled --- rtl/HMR/HMR_wrap.sv | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 427c1695..54ab72b4 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -946,9 +946,12 @@ module HMR_wrap import recovery_pkg::*; #( 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] = tmr_core_rapid_recovery_en[i] ? backup_enable[i] // TMR mode - : dmr_core_rapid_recovery_en[i] ? (backup_enable[i] & ~dmr_failure[i] ) // DMR mode - : 1'b1; // Independent mode + 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 ) @@ -1058,6 +1061,7 @@ module HMR_wrap import recovery_pkg::*; #( // 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]; From 91ebee3f92e4c9640bb8cdee841d35f312bbbfbd Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Sat, 18 Feb 2023 20:10:07 +0100 Subject: [PATCH 34/72] Update response suppression to keep req until gnt --- rtl/HMR/HMR_wrap.sv | 314 ++++++++++++++++++++++----------------- rtl/HMR/resp_suppress.sv | 66 ++++++-- 2 files changed, 232 insertions(+), 148 deletions(-) diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 54ab72b4..4dad449c 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -372,26 +372,64 @@ module HMR_wrap import recovery_pkg::*; #( 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 i_instr_suppress ( + resp_suppress #( + .AW (32), + .DW (DataWidth) + ) i_instr_suppress ( .clk_i, .rst_ni, - .setback_i (core_setback_o[i]), - .req_i (sys_instr_req_o[i]), - .gnt_i (sys_instr_gnt_i[i]), + + .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]), - .r_valid_o (filt_instr_r_valid[i]) + .we_o (), + .addr_o (sys_instr_addr_o[i]), + .data_o (), + .be_o () ); - resp_suppress i_data_suppress ( + resp_suppress #( + .AW (32), + .DW (DataWidth) + ) i_data_suppress ( .clk_i, .rst_ni, - .setback_i (core_setback_o[i]), - .req_i (sys_data_req_o[i]), - .gnt_i (sys_data_gnt_i[i]), + + .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]), - .r_valid_o (filt_data_r_valid[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 @@ -1276,13 +1314,13 @@ module HMR_wrap import recovery_pkg::*; #( core_irq_id_o [i] = sys_irq_id_i [TMRCoreIndex]; // INSTR - core_instr_gnt_o [i] = sys_instr_gnt_i [TMRCoreIndex]; + 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] = sys_data_gnt_i [TMRCoreIndex]; + 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]; @@ -1310,13 +1348,13 @@ module HMR_wrap import recovery_pkg::*; #( core_irq_id_o [i] = sys_irq_id_i [DMRCoreIndex]; // INSTR - core_instr_gnt_o [i] = sys_instr_gnt_i [DMRCoreIndex]; + 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] = sys_data_gnt_i [DMRCoreIndex]; + 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]; @@ -1339,13 +1377,13 @@ module HMR_wrap import recovery_pkg::*; #( core_irq_id_o [i] = sys_irq_id_i [i]; // INSTR - core_instr_gnt_o [i] = sys_instr_gnt_i [i]; + 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] = sys_data_gnt_i [i]; + 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]; @@ -1369,16 +1407,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = tmr_irq_ack_id_out[TMRCoreIndex]; // INSTR - sys_instr_req_o [i] = tmr_instr_req_out [TMRCoreIndex]; - sys_instr_addr_o [i] = tmr_instr_addr_out[TMRCoreIndex]; + filt_instr_req [i] = tmr_instr_req_out [TMRCoreIndex]; + filt_instr_addr [i] = tmr_instr_addr_out[TMRCoreIndex]; // DATA - sys_data_req_o [i] = tmr_data_req_out [TMRCoreIndex]; - sys_data_add_o [i] = tmr_data_add_out [TMRCoreIndex]; - sys_data_wen_o [i] = tmr_data_wen_out [TMRCoreIndex]; - sys_data_wdata_o [i] = tmr_data_wdata_out[TMRCoreIndex]; + 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]; - sys_data_be_o [i] = tmr_data_be_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; @@ -1388,16 +1426,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = '0; // INSTR - sys_instr_req_o [i] = '0; - sys_instr_addr_o [i] = '0; + filt_instr_req [i] = '0; + filt_instr_addr [i] = '0; // DATA - sys_data_req_o [i] = '0; - sys_data_add_o [i] = '0; - sys_data_wen_o [i] = '0; - sys_data_wdata_o [i] = '0; + 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; - sys_data_be_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 @@ -1409,16 +1447,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[DMRCoreIndex]; // INSTR - sys_instr_req_o [i] = dmr_instr_req_out [DMRCoreIndex]; - sys_instr_addr_o [i] = dmr_instr_addr_out[DMRCoreIndex]; + filt_instr_req [i] = dmr_instr_req_out [DMRCoreIndex]; + filt_instr_addr [i] = dmr_instr_addr_out[DMRCoreIndex]; // DATA - sys_data_req_o [i] = dmr_data_req_out [DMRCoreIndex]; - sys_data_add_o [i] = dmr_data_add_out [DMRCoreIndex]; - sys_data_wen_o [i] = dmr_data_wen_out [DMRCoreIndex]; - sys_data_wdata_o [i] = dmr_data_wdata_out[DMRCoreIndex]; + 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]; - sys_data_be_o [i] = dmr_data_be_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; @@ -1428,16 +1466,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = '0; // INSTR - sys_instr_req_o [i] = '0; - sys_instr_addr_o [i] = '0; + filt_instr_req [i] = '0; + filt_instr_addr [i] = '0; // DATA - sys_data_req_o [i] = '0; - sys_data_add_o [i] = '0; - sys_data_wen_o [i] = '0; - sys_data_wdata_o [i] = '0; + 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; - sys_data_be_o [i] = '0; + filt_data_be [i] = '0; end end else begin : independent_mode // CTRL @@ -1448,16 +1486,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = core_irq_ack_id_i[i]; // INSTR - sys_instr_req_o [i] = core_instr_req_i [i]; - sys_instr_addr_o [i] = core_instr_addr_i[i]; + filt_instr_req [i] = core_instr_req_i [i]; + filt_instr_addr [i] = core_instr_addr_i[i]; // DATA - sys_data_req_o [i] = core_data_req_i [i]; - sys_data_add_o [i] = core_data_add_i [i]; - sys_data_wen_o [i] = core_data_wen_i [i]; - sys_data_wdata_o [i] = core_data_wdata_i[i]; + 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]; - sys_data_be_o [i] = core_data_be_i [i]; + filt_data_be [i] = core_data_be_i [i]; end end end @@ -1502,13 +1540,13 @@ module HMR_wrap import recovery_pkg::*; #( core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; // INSTR - core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; + 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] = sys_data_gnt_i [SysCoreIndex]; + 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]; @@ -1531,13 +1569,13 @@ module HMR_wrap import recovery_pkg::*; #( core_irq_id_o [i] = sys_irq_id_i [i]; // INSTR - core_instr_gnt_o [i] = sys_instr_gnt_i [i]; + 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] = sys_data_gnt_i [i]; + 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]; @@ -1558,16 +1596,16 @@ module HMR_wrap import recovery_pkg::*; #( assign sys_irq_ack_id_o [i] = tmr_irq_ack_id_out[CoreCoreIndex]; // INSTR - assign sys_instr_req_o [i] = tmr_instr_req_out [CoreCoreIndex]; - assign sys_instr_addr_o [i] = tmr_instr_addr_out[CoreCoreIndex]; + assign filt_instr_req [i] = tmr_instr_req_out [CoreCoreIndex]; + assign filt_instr_addr [i] = tmr_instr_addr_out[CoreCoreIndex]; // DATA - assign sys_data_req_o [i] = tmr_data_req_out [CoreCoreIndex]; - assign sys_data_add_o [i] = tmr_data_add_out [CoreCoreIndex]; - assign sys_data_wen_o [i] = tmr_data_wen_out [CoreCoreIndex]; - assign sys_data_wdata_o [i] = tmr_data_wdata_out[CoreCoreIndex]; + 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 sys_data_be_o [i] = tmr_data_be_out [CoreCoreIndex]; + assign filt_data_be [i] = tmr_data_be_out [CoreCoreIndex]; end else begin if (i >= NumTMRCores) begin : independent_stragglers // CTRL @@ -1578,16 +1616,16 @@ module HMR_wrap import recovery_pkg::*; #( assign sys_irq_ack_id_o [i] = core_irq_ack_id_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; // INSTR - assign sys_instr_req_o [i] = core_instr_req_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_instr_addr_o [i] = core_instr_addr_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + 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 sys_data_req_o [i] = core_data_req_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_data_add_o [i] = core_data_add_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_data_wen_o [i] = core_data_wen_i [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_data_wdata_o [i] = core_data_wdata_i[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + 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 sys_data_be_o [i] = core_data_be_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 @@ -1600,16 +1638,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = tmr_irq_ack_id_out[CoreCoreIndex]; // INSTR - sys_instr_req_o [i] = tmr_instr_req_out [CoreCoreIndex]; - sys_instr_addr_o [i] = tmr_instr_addr_out[CoreCoreIndex]; + filt_instr_req [i] = tmr_instr_req_out [CoreCoreIndex]; + filt_instr_addr [i] = tmr_instr_addr_out[CoreCoreIndex]; // DATA - sys_data_req_o [i] = tmr_data_req_out [CoreCoreIndex]; - sys_data_add_o [i] = tmr_data_add_out [CoreCoreIndex]; - sys_data_wen_o [i] = tmr_data_wen_out [CoreCoreIndex]; - sys_data_wdata_o [i] = tmr_data_wdata_out[CoreCoreIndex]; + 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]; - sys_data_be_o [i] = tmr_data_be_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; @@ -1619,16 +1657,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = '0; // INSTR - sys_instr_req_o [i] = '0; - sys_instr_addr_o [i] = '0; + filt_instr_req [i] = '0; + filt_instr_addr [i] = '0; // DATA - sys_data_req_o [i] = '0; - sys_data_add_o [i] = '0; - sys_data_wen_o [i] = '0; - sys_data_wdata_o [i] = '0; + 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; - sys_data_be_o [i] = '0; + filt_data_be [i] = '0; end end else begin : independent_mode // CTRL @@ -1639,16 +1677,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = core_irq_ack_id_i[i]; // INSTR - sys_instr_req_o [i] = core_instr_req_i [i]; - sys_instr_addr_o [i] = core_instr_addr_i[i]; + filt_instr_req [i] = core_instr_req_i [i]; + filt_instr_addr [i] = core_instr_addr_i[i]; // DATA - sys_data_req_o [i] = core_data_req_i [i]; - sys_data_add_o [i] = core_data_add_i [i]; - sys_data_wen_o [i] = core_data_wen_i [i]; - sys_data_wdata_o [i] = core_data_wdata_i[i]; + 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]; - sys_data_be_o [i] = core_data_be_i [i]; + filt_data_be [i] = core_data_be_i [i]; end end end @@ -1700,13 +1738,13 @@ module HMR_wrap import recovery_pkg::*; #( core_irq_id_o [i] = sys_irq_id_i [SysCoreIndex]; // INSTR - core_instr_gnt_o [i] = sys_instr_gnt_i [SysCoreIndex]; + 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] = sys_data_gnt_i [SysCoreIndex]; + 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]; @@ -1729,13 +1767,13 @@ module HMR_wrap import recovery_pkg::*; #( core_irq_id_o [i] = sys_irq_id_i [i]; // INSTR - core_instr_gnt_o [i] = sys_instr_gnt_i [i]; + 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] = sys_data_gnt_i [i]; + 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]; @@ -1756,16 +1794,16 @@ module HMR_wrap import recovery_pkg::*; #( assign sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[CoreCoreIndex]; // INSTR - assign sys_instr_req_o [i] = dmr_instr_req_out [CoreCoreIndex]; - assign sys_instr_addr_o [i] = dmr_instr_addr_out[CoreCoreIndex]; + assign filt_instr_req [i] = dmr_instr_req_out [CoreCoreIndex]; + assign filt_instr_addr [i] = dmr_instr_addr_out[CoreCoreIndex]; // DATA - assign sys_data_req_o [i] = dmr_data_req_out [CoreCoreIndex]; - assign sys_data_add_o [i] = dmr_data_add_out [CoreCoreIndex]; - assign sys_data_wen_o [i] = dmr_data_wen_out [CoreCoreIndex]; - assign sys_data_wdata_o [i] = dmr_data_wdata_out[CoreCoreIndex]; + 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 sys_data_be_o [i] = dmr_data_be_out [CoreCoreIndex]; + assign filt_data_be [i] = dmr_data_be_out [CoreCoreIndex]; end else begin if (i >= NumDMRCores) begin : independent_stragglers // CTRL @@ -1776,16 +1814,16 @@ module HMR_wrap import recovery_pkg::*; #( assign sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; // INSTR - assign sys_instr_req_o [i] = dmr_instr_req_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_instr_addr_o [i] = dmr_instr_addr_out[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + 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 sys_data_req_o [i] = dmr_data_req_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_data_add_o [i] = dmr_data_add_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_data_wen_o [i] = dmr_data_wen_out [TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; - assign sys_data_wdata_o [i] = dmr_data_wdata_out[TMRFixed ? i-NumTMRGroups+NumTMRCores : i]; + 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 sys_data_be_o [i] = dmr_data_be_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 @@ -1798,16 +1836,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = dmr_irq_ack_id_out[CoreCoreIndex]; // INSTR - sys_instr_req_o [i] = dmr_instr_req_out [CoreCoreIndex]; - sys_instr_addr_o [i] = dmr_instr_addr_out[CoreCoreIndex]; + filt_instr_req [i] = dmr_instr_req_out [CoreCoreIndex]; + filt_instr_addr [i] = dmr_instr_addr_out[CoreCoreIndex]; // DATA - sys_data_req_o [i] = dmr_data_req_out [CoreCoreIndex]; - sys_data_add_o [i] = dmr_data_add_out [CoreCoreIndex]; - sys_data_wen_o [i] = dmr_data_wen_out [CoreCoreIndex]; - sys_data_wdata_o [i] = dmr_data_wdata_out[CoreCoreIndex]; + 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]; - sys_data_be_o [i] = dmr_data_be_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; @@ -1817,16 +1855,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = '0; // INSTR - sys_instr_req_o [i] = '0; - sys_instr_addr_o [i] = '0; + filt_instr_req [i] = '0; + filt_instr_addr [i] = '0; // DATA - sys_data_req_o [i] = '0; - sys_data_add_o [i] = '0; - sys_data_wen_o [i] = '0; - sys_data_wdata_o [i] = '0; + 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; - sys_data_be_o [i] = '0; + filt_data_be [i] = '0; end end else begin : independent_mode // CTRL @@ -1837,16 +1875,16 @@ module HMR_wrap import recovery_pkg::*; #( sys_irq_ack_id_o [i] = core_irq_ack_id_i[i]; // INSTR - sys_instr_req_o [i] = core_instr_req_i [i]; - sys_instr_addr_o [i] = core_instr_addr_i[i]; + filt_instr_req [i] = core_instr_req_i [i]; + filt_instr_addr [i] = core_instr_addr_i[i]; // DATA - sys_data_req_o [i] = core_data_req_i [i]; - sys_data_add_o [i] = core_data_add_i [i]; - sys_data_wen_o [i] = core_data_wen_i [i]; - sys_data_wdata_o [i] = core_data_wdata_i[i]; + 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]; - sys_data_be_o [i] = core_data_be_i [i]; + filt_data_be [i] = core_data_be_i [i]; end end end @@ -1879,21 +1917,21 @@ module HMR_wrap import recovery_pkg::*; #( assign sys_irq_ack_id_o = core_irq_ack_id_i; // INSTR - assign sys_instr_req_o = core_instr_req_i; - assign core_instr_gnt_o = sys_instr_gnt_i; - assign sys_instr_addr_o = core_instr_addr_i; + 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 sys_data_req_o = core_data_req_i; - assign sys_data_add_o = core_data_add_i; - assign sys_data_wen_o = core_data_wen_i; - assign sys_data_wdata_o = core_data_wdata_i; + 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 sys_data_be_o = core_data_be_i; - assign core_data_gnt_o = sys_data_gnt_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; diff --git a/rtl/HMR/resp_suppress.sv b/rtl/HMR/resp_suppress.sv index 1144373e..fa1b8f28 100644 --- a/rtl/HMR/resp_suppress.sv +++ b/rtl/HMR/resp_suppress.sv @@ -11,30 +11,66 @@ // Suppress the r_valid if set back module resp_suppress #( - parameter int unsigned NumOutstanding = 2 + 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 setback_i, - input logic req_i, - input logic gnt_i, - input logic r_valid_i, - output logic r_valid_o + 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 outstanding_d = outstanding_q + (req_i & 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 r_valid_o = block_q ? 1'b0 : r_valid_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; - if (setback_i) begin + 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; - end else if (outstanding_q == 0) begin + 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 @@ -43,9 +79,19 @@ module resp_suppress #( 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 From 925850788273a968ddc3a64686944ea78504b75d Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 10 May 2023 14:35:38 +0200 Subject: [PATCH 35/72] Add modular hmr unit --- Bender.yml | 1 + rtl/HMR/hmr_unit.sv | 774 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 775 insertions(+) create mode 100644 rtl/HMR/hmr_unit.sv diff --git a/Bender.yml b/Bender.yml index e81fd859..c84202c4 100644 --- a/Bender.yml +++ b/Bender.yml @@ -114,6 +114,7 @@ sources: - 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 diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv new file mode 100644 index 00000000..b8abcbec --- /dev/null +++ b/rtl/HMR/hmr_unit.sv @@ -0,0 +1,774 @@ +// 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_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, + /// Number of separate voters/checkers for individual buses + parameter int unsigned NumBusVoters = 1, + /// General core inputs wrapping struct + parameter type all_inputs_t = logic, + /// General core outputs wrapping struct + parameter type nominal_outputs_t = logic, + /// Bus outputs wrapping struct + parameter type bus_outputs_t = logic, + parameter type reg_req_t = logic, + parameter type reg_rsp_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 ? 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, + + 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, + input logic [NumSysCores-1:0] sys_fetch_en_i, + input logic [NumSysCores-1:0][NumBusVoters-1:0] enable_bus_vote_i, + + 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 +); + function int max(int a, int b); + return (a > b) ? a : b; + endfunction + + 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; + + 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; + logic [NumDMRGroups-1:0][NumBusVoters-1:0] dmr_failure_data; + + /*************************** + * 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_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,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 ( '0)//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 = '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_rsp_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_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 ) + ); + + 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 ), + .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 ( '0)//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 ( $bits(nominal_outputs_t) ) + ) dmr_core_checker_main ( + .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 (SeparateData) begin : gen_data_checker + for (genvar j = 0; j < NumBusVoters; j++) begin + DMR_checker # ( + .DataWidth ( $bits(bus_outputs_t) ) + ) dmr_core_checker_data ( + .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 + + if (RapidRecovery) begin : gen_rapid_recovery_connection + $error("UNIMPLEMENTED"); + end else begin : gen_standard_failure + always_comb begin + dmr_failure[i] = dmr_failure_main[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 = '0; + assign dmr_incr_mismatches = '0; + assign dmr_nominal_outputs = '0; + assign dmr_bus_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; + 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 + $error("UNIMPLEMENTED"); + // 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 + 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]; + end else begin : disable_core // Assign disable + sys_nominal_outputs_o[i] = '0; + sys_bus_outputs_o[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 + sys_nominal_outputs_o[i] = dmr_nominal_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; + 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 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 + $error("UNIMPLEMENTED"); + // 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 + 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]; + 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]; + 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 + 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; + 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 + // Setback + if (RapidRecovery) begin + $error("UNIMPLEMENTED"); + // 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 + 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]; + 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]; + 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]; + end else begin : disable_core // Assign disable + sys_nominal_outputs_o[i] = '0; + sys_bus_outputs_o [i] = '0; + 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 begin : gen_no_redundancy + /***************** + *** none *** + *****************/ + // Direct assignment, disable all + assign core_setback_o = '0; + 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; + end + +endmodule From 62c8c634fdc3937b8b38e87a2c964701e832bcce Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 11 May 2023 10:16:45 +0200 Subject: [PATCH 36/72] Fix lint error --- rtl/HMR/hmr_unit.sv | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index b8abcbec..96a71831 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -1,4 +1,4 @@ -// Copyright 2022 ETH Zurich and University of Bologna. +// 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 @@ -292,9 +292,6 @@ module hmr_unit #( assign sp_store_will_be_zero[i] = core_config_reg2hw[i].sp_store.qe && core_register_reqs[i].wdata == '0; end - - - /********************************************************** ******************** TMR Voters & Regs ******************* **********************************************************/ @@ -571,6 +568,7 @@ module hmr_unit #( 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 From d64f902011d297f619dcf55c0ab06d6e03e56f8f Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 22 Jun 2023 17:56:37 +0200 Subject: [PATCH 37/72] Fix ECC Manager configuration --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79f119b7..319512bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update `ecc_manager` for configurability - Update secded testbench to use correctors and fix error injection +### Changed +- Replace vendor.py script with bender vendor for ECC modules +- Update `ecc_manager` for configurability + ## 0.5.1 - 2023-04-12 ### Added - Add CI flow for linting From 1b48ee90be0330c72e6348c0cecdb8a4464da827 Mon Sep 17 00:00:00 2001 From: Luca Rufer Date: Fri, 2 Dec 2022 12:55:31 +0100 Subject: [PATCH 38/72] Add Corrector to generation script and update testbench --- Bender.yml | 13 ++ CHANGELOG.md | 7 +- rtl/lowrisc_ecc/prim_secded_13_8_cor.sv | 16 +- rtl/lowrisc_ecc/prim_secded_22_16_cor.sv | 44 +++--- rtl/lowrisc_ecc/prim_secded_28_22_cor.sv | 12 +- rtl/lowrisc_ecc/prim_secded_39_32_cor.sv | 76 +++++----- rtl/lowrisc_ecc/prim_secded_72_64_cor.sv | 32 ++-- .../prim_secded_hamming_22_16_cor.sv | 14 +- .../prim_secded_hamming_39_32_cor.sv | 30 ++-- .../prim_secded_hamming_72_64_cor.sv | 60 ++++---- test/tb_ecc_secded.sv | 140 ++++++++++++------ 11 files changed, 254 insertions(+), 190 deletions(-) diff --git a/Bender.yml b/Bender.yml index c84202c4..15494459 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 319512bf..074d5acc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add ECC correctors -### 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 - ### Changed - Replace vendor.py script with bender vendor for ECC modules - Update `ecc_manager` for configurability @@ -33,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/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 * From c65abf567cccf38f7496912029adde3c4560aca6 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 10 Jul 2023 10:44:26 +0200 Subject: [PATCH 39/72] Simplify sram wrap and add optional cut to RMW path --- rtl/ecc_wrap/ecc_sram_wrap.sv | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/rtl/ecc_wrap/ecc_sram_wrap.sv b/rtl/ecc_wrap/ecc_sram_wrap.sv index d053c11c..f21c9b98 100644 --- a/rtl/ecc_wrap/ecc_sram_wrap.sv +++ b/rtl/ecc_wrap/ecc_sram_wrap.sv @@ -132,14 +132,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 #( @@ -152,9 +149,7 @@ module ecc_sram_wrap #( assign tcdm_rdata_o = loaded; - assign to_store = store_state_q == NORMAL ? - tcdm_wdata_i : - (be_selector & input_buffer_q) | (~be_selector & loaded); + assign to_store = store_state_q == NORMAL ? tcdm_wdata_i : (be_selector & input_buffer_q) | (~be_selector & loaded); end else begin : gen_ecc_input @@ -164,12 +159,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 +183,6 @@ module ecc_sram_wrap #( .in ( (be_selector & intermediate_data_st) | (~be_selector & intermediate_data_ld) ), .out ( lns_wdata ) ); - end always_comb begin From 88202cb2c0f28066f24e36c92b2ce9faa4dd5df3 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 26 Jul 2023 21:04:10 +0200 Subject: [PATCH 40/72] WIP: integrated rapid recovery unit. --- Bender.yml | 3 +- rtl/HMR/DMR_CSR_checker.sv | 6 +- rtl/HMR/DMR_controller.sv | 4 +- rtl/HMR/HMR_wrap.sv | 4 +- rtl/HMR/hmr_dmr_ctrl.sv | 4 +- rtl/HMR/hmr_rapid_recovery_ctrl.sv | 7 +- rtl/HMR/hmr_unit.sv | 134 ++++++++++++--- ...{recovery_pkg.sv => rapid_recovery_pkg.sv} | 20 ++- rtl/HMR/rapid_recovery_unit.sv | 157 ++++++++++++++++++ rtl/HMR/recovery_csr.sv | 29 ++-- rtl/HMR/recovery_pc.sv | 11 +- rtl/HMR/recovery_rf.sv | 61 +++---- 12 files changed, 360 insertions(+), 80 deletions(-) rename rtl/HMR/{recovery_pkg.sv => rapid_recovery_pkg.sv} (78%) create mode 100644 rtl/HMR/rapid_recovery_unit.sv diff --git a/Bender.yml b/Bender.yml index 15494459..3f3700ae 100644 --- a/Bender.yml +++ b/Bender.yml @@ -107,10 +107,11 @@ sources: - test/tb_bitwise_tmr_voter.sv - files: - - rtl/HMR/recovery_pkg.sv + - 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 diff --git a/rtl/HMR/DMR_CSR_checker.sv b/rtl/HMR/DMR_CSR_checker.sv index 0bcd067f..c883b18d 100644 --- a/rtl/HMR/DMR_CSR_checker.sv +++ b/rtl/HMR/DMR_CSR_checker.sv @@ -12,9 +12,9 @@ * */ -import recovery_pkg::*; - -module DMR_CSR_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, diff --git a/rtl/HMR/DMR_controller.sv b/rtl/HMR/DMR_controller.sv index f6c83fd3..9272a769 100644 --- a/rtl/HMR/DMR_controller.sv +++ b/rtl/HMR/DMR_controller.sv @@ -13,7 +13,9 @@ * */ -module DMR_controller import recovery_pkg::*; #( +module DMR_controller + import rapid_recovery_pkg::*; +#( parameter int unsigned NumCores = 0, parameter bit DMRFixed = 1'b0, parameter bit RapidRecovery = 1'b0, diff --git a/rtl/HMR/HMR_wrap.sv b/rtl/HMR/HMR_wrap.sv index 4dad449c..ac19fb4a 100644 --- a/rtl/HMR/HMR_wrap.sv +++ b/rtl/HMR/HMR_wrap.sv @@ -10,7 +10,9 @@ // // Hybrid modular redundancy wrapping unit -module HMR_wrap import recovery_pkg::*; #( +module HMR_wrap + import rapid_recovery_pkg::*; +#( // Wrapper parameters /// Number of physical cores parameter int unsigned NumCores = 0, diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index ab7992e9..1b55311b 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -10,7 +10,9 @@ // // Hybrid modular redundancy DMR control unit -module hmr_dmr_ctrl import recovery_pkg::*; #( +module hmr_dmr_ctrl + import rapid_recovery_pkg::*; +#( parameter bit InterleaveGrps = 1'b0, parameter bit DMRFixed = 1'b0, parameter bit DefaultInDMR = DMRFixed ? 1'b1 : 1'b0, diff --git a/rtl/HMR/hmr_rapid_recovery_ctrl.sv b/rtl/HMR/hmr_rapid_recovery_ctrl.sv index e1205ea6..4f5b9f2f 100644 --- a/rtl/HMR/hmr_rapid_recovery_ctrl.sv +++ b/rtl/HMR/hmr_rapid_recovery_ctrl.sv @@ -10,8 +10,11 @@ // // Hybrid modular redundancy Rapid Recovery control unit -module hmr_rapid_recovery_ctrl import recovery_pkg::*; #( - parameter int unsigned RFAddrWidth = 6 +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, diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 96a71831..40daabe9 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -30,6 +30,9 @@ module hmr_unit #( parameter bit SeparateData = 1'b1, /// 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 @@ -38,6 +41,8 @@ module hmr_unit #( parameter type bus_outputs_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 = NumCores/3, @@ -75,6 +80,9 @@ module hmr_unit #( output logic [ NumCores-1:0] dmr_sw_synch_req_o, input logic [NumDMRGroups-1:0] dmr_cores_synch_i, + // Rapid recovery output bus + output rapid_recovery_t [NumSysCores-1:0] rapid_recovery_o, + 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, @@ -90,6 +98,8 @@ module hmr_unit #( 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); @@ -146,6 +156,17 @@ module hmr_unit #( logic [NumDMRGroups-1:0] dmr_failure, dmr_failure_main; logic [NumDMRGroups-1:0][NumBusVoters-1:0] dmr_failure_data; + /************************** + * 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; + nominal_outputs_t [NumBackupRegs-1:0] rapid_recovery_nominal; + /*************************** * HMR Control Registers * ***************************/ @@ -376,8 +397,8 @@ module hmr_unit #( .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 ( '0)//tmr_recovery_finished [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]; @@ -513,8 +534,8 @@ module hmr_unit #( .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 ( '0)//dmr_recovery_finished[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]; @@ -544,8 +565,41 @@ module hmr_unit #( end end - if (RapidRecovery) begin : gen_rapid_recovery_connection - $error("UNIMPLEMENTED"); + if (RapidRecovery) begin : gen_rapid_recovery_unit + + 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 ), + .regfile_write_i ( rapid_recovery_nominal[i].regfile_backup ), + .backup_csr_i ( rapid_recovery_nominal[i].csr_backup ), + .recovery_csr_o ( rapid_recovery_bus[i].csr_recovery ), + .backup_pc_i ( rapid_recovery_nominal[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 ) + ); end else begin : gen_standard_failure always_comb begin dmr_failure[i] = dmr_failure_main[i]; @@ -571,6 +625,35 @@ module hmr_unit #( assign dmr_grp_in_independent = '1; end + if (RapidRecovery) begin: gen_rapid_recovery_connection + always_comb begin + rapid_recovery_nominal = '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_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_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 // Assign output signals if (DMRSupported && TMRSupported) begin : gen_full_HMR @@ -586,11 +669,14 @@ module hmr_unit #( always_comb begin // Special signals if (RapidRecovery) begin - $error("UNIMPLEMENTED"); - // 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)); + // $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)]; @@ -598,11 +684,11 @@ module hmr_unit #( 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); + 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] ? recovery_setback_out [dmr_shared_id(dmr_group_id(i))] : '0) : '0); + 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]; @@ -632,7 +718,7 @@ module hmr_unit #( 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 + end else begin : disable_core // Assign disable sys_nominal_outputs_o[i] = '0; sys_bus_outputs_o[i] = '0; end @@ -653,9 +739,11 @@ module hmr_unit #( // Special signals // Setback if (RapidRecovery) begin - $error("UNIMPLEMENTED"); - // core_setback_o [i] = tmr_setback_q [tmr_group_id(i)] - // | recovery_setback_out [tmr_shared_id(tmr_group_id(i))]; + // $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 @@ -713,9 +801,11 @@ module hmr_unit #( always_comb begin // Setback if (RapidRecovery) begin - $error("UNIMPLEMENTED"); - // 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))]; + // $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] = '0; end diff --git a/rtl/HMR/recovery_pkg.sv b/rtl/HMR/rapid_recovery_pkg.sv similarity index 78% rename from rtl/HMR/recovery_pkg.sv rename to rtl/HMR/rapid_recovery_pkg.sv index 68dfc77a..123f39ef 100644 --- a/rtl/HMR/recovery_pkg.sv +++ b/rtl/HMR/rapid_recovery_pkg.sv @@ -12,7 +12,7 @@ * */ -package recovery_pkg; +package rapid_recovery_pkg; localparam int unsigned DataWidth = 32; localparam int unsigned ProtectedWidth = 39; @@ -64,4 +64,22 @@ typedef struct packed { logic [ProtectedWidth-1:0] csr_mcause; } ecc_csrs_intf_t; +typedef struct packed { + 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..18661a1d --- /dev/null +++ b/rtl/HMR/rapid_recovery_unit.sv @@ -0,0 +1,157 @@ +// 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, + /* 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 ) +); + +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_pc_i.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, + .test_en_i ( '0 ), + //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 index 8ef95555..6cf78126 100644 --- a/rtl/HMR/recovery_csr.sv +++ b/rtl/HMR/recovery_csr.sv @@ -13,21 +13,22 @@ * */ -import recovery_pkg::*; - -module recovery_csr #( - parameter ECCEnabled = 0, - parameter NonProtectedWidth = 32, - parameter ProtectedWidth = 39, - localparam DataWidth = ( ECCEnabled ) ? ProtectedWidth - : NonProtectedWidth +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 + 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, diff --git a/rtl/HMR/recovery_pc.sv b/rtl/HMR/recovery_pc.sv index 8b5fdf53..51f62347 100644 --- a/rtl/HMR/recovery_pc.sv +++ b/rtl/HMR/recovery_pc.sv @@ -14,11 +14,12 @@ */ module recovery_pc #( - parameter ECCEnabled = 0, - parameter NonProtectedWidth = 32, - parameter ProtectedWidth = 39, - localparam DataWidth = ( ECCEnabled ) ? ProtectedWidth - : NonProtectedWidth + 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, diff --git a/rtl/HMR/recovery_rf.sv b/rtl/HMR/recovery_rf.sv index 9572d26d..3bc572a7 100644 --- a/rtl/HMR/recovery_rf.sv +++ b/rtl/HMR/recovery_rf.sv @@ -30,42 +30,45 @@ //////////////////////////////////////////////////////////////////////////////// module recovery_rf #( - parameter ECCEnabled = 0, - parameter ADDR_WIDTH = 5, - parameter NonProtectedWidth = 32, - parameter ProtectedWidth = 39, - parameter FPU = 0, - parameter PULP_ZFINX = 0, - localparam DataWidth = ( ECCEnabled ) ? ProtectedWidth - : NonProtectedWidth + 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, + // Clock and Reset + input logic clk_i, + input logic rst_ni, - input logic test_en_i, + 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 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 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, + //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 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 + // 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 From a027dbc7946f277b8eace78f2acf81e660c34482 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 2 Oct 2023 19:26:18 +0200 Subject: [PATCH 41/72] Fix no-RR case --- rtl/HMR/hmr_tmr_ctrl.sv | 6 +++--- rtl/HMR/hmr_unit.sv | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/rtl/HMR/hmr_tmr_ctrl.sv b/rtl/HMR/hmr_tmr_ctrl.sv index e915b9d9..6f05db62 100644 --- a/rtl/HMR/hmr_tmr_ctrl.sv +++ b/rtl/HMR/hmr_tmr_ctrl.sv @@ -123,7 +123,7 @@ module hmr_tmr_ctrl #( // 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) begin + 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; @@ -138,7 +138,7 @@ module hmr_tmr_ctrl #( 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) begin + 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; @@ -190,7 +190,7 @@ module hmr_tmr_ctrl #( 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) 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; diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 40daabe9..7dd16cbc 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -653,6 +653,11 @@ module hmr_unit #( end end end + end else begin + assign rapid_recovery_nominal = '0; + assign rapid_recovery_start = '0; + assign tmr_recovery_finished = '1; + assign dmr_recovery_finished = '1; end // Assign output signals From b063115a25a7eecb2d770ffc23c70d161ea7715e Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Fri, 6 Oct 2023 16:20:17 +0200 Subject: [PATCH 42/72] Fixed assignment for default status backup if cores are not grouped. --- rtl/HMR/hmr_unit.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 7dd16cbc..49f4281c 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -633,7 +633,7 @@ module hmr_unit #( 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_nominal[i] = core_nominal_outputs_i[i]; rapid_recovery_start[i] = dmr_recovery_start[i]; dmr_recovery_finished[i] = rapid_recovery_finished[i]; end From 0f4a9b49500565b19eb6860b95eebe74dec8c300 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Tue, 10 Oct 2023 07:03:03 +0200 Subject: [PATCH 43/72] Made recovery RF FF-based. --- rtl/HMR/rapid_recovery_unit.sv | 1 - rtl/HMR/recovery_rf.sv | 190 +++++++++--------------- rtl/HMR/recovery_rf_latch.sv | 260 +++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+), 118 deletions(-) create mode 100644 rtl/HMR/recovery_rf_latch.sv diff --git a/rtl/HMR/rapid_recovery_unit.sv b/rtl/HMR/rapid_recovery_unit.sv index 18661a1d..16b89a22 100644 --- a/rtl/HMR/rapid_recovery_unit.sv +++ b/rtl/HMR/rapid_recovery_unit.sv @@ -134,7 +134,6 @@ recovery_rf #( ) i_recovery_rf ( .clk_i, .rst_ni, - .test_en_i ( '0 ), //Read port A .raddr_a_i ( regfile_recovery_wdata_o.waddr_a ), .rdata_a_o ( regfile_recovery_rdata_o.rdata_a ), diff --git a/rtl/HMR/recovery_rf.sv b/rtl/HMR/recovery_rf.sv index 3bc572a7..b546087c 100644 --- a/rtl/HMR/recovery_rf.sv +++ b/rtl/HMR/recovery_rf.sv @@ -9,10 +9,9 @@ // specific language governing permissions and limitations under the License. //////////////////////////////////////////////////////////////////////////////// -// Engineer: Antonio Pullini - pullinia@iis.ee.ethz.ch // +// Engineer: Francesco Conti - f.conti@unibo.it // // // // Additional contributions by: // -// Sven Stucki - svstucki@student.ethz.ch // // Michael Gautschi - gautschi@iis.ee.ethz.ch // // Davide Schiavone - pschiavo@iis.ee.ethz.ch // // // @@ -21,8 +20,7 @@ // 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. // +// 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 // @@ -41,13 +39,11 @@ module recovery_rf #( 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, @@ -57,8 +53,8 @@ module recovery_rf #( 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, + 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, @@ -78,51 +74,35 @@ module recovery_rf #( 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; + 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; - 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; + // 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_ecc) + .in ( wdata_a_i ), + .out ( wdata_a ) ); - assign wdata_a = wdata_a_ecc; prim_secded_39_32_enc b_port_ecc_encoder ( - .in ( wdata_b_i ), - .out ( wdata_b_ecc) + .in ( wdata_b_i ), + .out ( wdata_b ) ); - assign wdata_b = wdata_b_ecc; for (genvar index = 0; index < NUM_WORDS; index++) begin prim_secded_39_32_dec internal_memory_decoder ( @@ -145,9 +125,7 @@ module recovery_rf #( 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]; @@ -160,101 +138,79 @@ module recovery_rf #( //----------------------------------------------------------------------------- //-- 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; + 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 - 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 = 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); + 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 - //----------------------------------------------------------------------------- - //-- WRITE : Clock gating (if integrated clock-gating cells are available) - //----------------------------------------------------------------------------- + genvar i, l; 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; + //----------------------------------------------------------------------------- + //-- 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 - 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; + // 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 - 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; + 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 - 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 From 136434958e0b3f1e7b3c16168a937e24cfac3856 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 11 Oct 2023 22:56:39 +0200 Subject: [PATCH 44/72] Use pipelined checker for core's backup bus. --- rtl/HMR/DMR_checker.sv | 23 ++++++++++-- rtl/HMR/hmr_unit.sv | 79 ++++++++++++++++++++++++++++++------------ 2 files changed, 76 insertions(+), 26 deletions(-) diff --git a/rtl/HMR/DMR_checker.sv b/rtl/HMR/DMR_checker.sv index 21842bdb..c28b893d 100644 --- a/rtl/HMR/DMR_checker.sv +++ b/rtl/HMR/DMR_checker.sv @@ -15,8 +15,11 @@ */ module DMR_checker #( - parameter int unsigned DataWidth = 41 + parameter int unsigned DataWidth = 41, + parameter int unsigned Pipeline = 0 )( + input logic clk_i, + input logic rst_ni, input logic [DataWidth-1:0] inp_a_i, input logic [DataWidth-1:0] inp_b_i, output logic [DataWidth-1:0] check_o, @@ -25,10 +28,24 @@ module DMR_checker #( logic error; logic [DataWidth-1:0] compare; +logic [DataWidth-1:0] inp_q; -assign compare = inp_a_i ^ inp_b_i; +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; -assign check_o = (!error) ? inp_a_i : '0; +assign check_o = (error) ? '0 : inp_q; assign error_o = error; endmodule : DMR_checker diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 49f4281c..5fc22ef6 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -37,6 +37,8 @@ module hmr_unit #( 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, parameter type reg_req_t = logic, @@ -80,8 +82,9 @@ module hmr_unit #( output logic [ NumCores-1:0] dmr_sw_synch_req_o, input logic [NumDMRGroups-1:0] dmr_cores_synch_i, - // Rapid recovery output bus - output rapid_recovery_t [NumSysCores-1:0] rapid_recovery_o, + // Rapid recovery buses + output rapid_recovery_t [NumSysCores-1:0] rapid_recovery_o, + input core_backup_t [NumCores-1:0] core_backup_i, input all_inputs_t [NumSysCores-1:0] sys_inputs_i, output nominal_outputs_t [NumSysCores-1:0] sys_nominal_outputs_o, @@ -146,6 +149,7 @@ module hmr_unit #( nominal_outputs_t [NumDMRGroups-1:0] dmr_nominal_outputs; bus_outputs_t [NumDMRGroups-1:0][NumBusVoters-1:0] dmr_bus_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; @@ -153,7 +157,7 @@ module hmr_unit #( 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; + logic [NumDMRGroups-1:0] dmr_failure, dmr_failure_main, dmr_failure_backup; logic [NumDMRGroups-1:0][NumBusVoters-1:0] dmr_failure_data; /************************** @@ -165,6 +169,7 @@ module hmr_unit #( 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; nominal_outputs_t [NumBackupRegs-1:0] rapid_recovery_nominal; /*************************** @@ -547,6 +552,8 @@ module hmr_unit #( DMR_checker #( .DataWidth ( $bits(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 ] ), @@ -557,6 +564,8 @@ module hmr_unit #( DMR_checker # ( .DataWidth ( $bits(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] ), @@ -567,6 +576,18 @@ module hmr_unit #( if (RapidRecovery) begin : gen_rapid_recovery_unit + DMR_checker #( + .DataWidth ( $bits(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 @@ -579,27 +600,36 @@ module hmr_unit #( .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 ), - .regfile_write_i ( rapid_recovery_nominal[i].regfile_backup ), - .backup_csr_i ( rapid_recovery_nominal[i].csr_backup ), - .recovery_csr_o ( rapid_recovery_bus[i].csr_recovery ), - .backup_pc_i ( rapid_recovery_nominal[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 ) + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .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]; + 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]; @@ -628,12 +658,14 @@ module hmr_unit #( if (RapidRecovery) begin: gen_rapid_recovery_connection 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] = core_nominal_outputs_i[i]; + rapid_recovery_backup_bus[i] = core_backup_i[i]; rapid_recovery_start[i] = dmr_recovery_start[i]; dmr_recovery_finished[i] = rapid_recovery_finished[i]; end @@ -641,6 +673,7 @@ module hmr_unit #( 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 From 7577fac03f075d0909137e5f625268bcaf384803 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Mon, 30 Oct 2023 22:20:18 +0100 Subject: [PATCH 45/72] Store PR coming from IF stage if cores are in independent. --- rtl/HMR/hmr_unit.sv | 1 + rtl/HMR/rapid_recovery_pkg.sv | 1 + rtl/HMR/rapid_recovery_unit.sv | 15 ++++++++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 5fc22ef6..39d575f7 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -602,6 +602,7 @@ module hmr_unit #( ) 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 ), diff --git a/rtl/HMR/rapid_recovery_pkg.sv b/rtl/HMR/rapid_recovery_pkg.sv index 123f39ef..6a1e1044 100644 --- a/rtl/HMR/rapid_recovery_pkg.sv +++ b/rtl/HMR/rapid_recovery_pkg.sv @@ -65,6 +65,7 @@ typedef struct packed { } 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; diff --git a/rtl/HMR/rapid_recovery_unit.sv b/rtl/HMR/rapid_recovery_unit.sv index 16b89a22..77bcf453 100644 --- a/rtl/HMR/rapid_recovery_unit.sv +++ b/rtl/HMR/rapid_recovery_unit.sv @@ -24,6 +24,8 @@ module rapid_recovery_unit )( 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 */ @@ -105,6 +107,13 @@ recovery_csr #( .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 ) @@ -116,9 +125,9 @@ recovery_pc #( .read_enable_i ( enable_pc_recovery_o ), .write_enable_i ( backup_enable_i ), // Backup Ports - .backup_program_counter_i ( backup_pc_i.program_counter ), - .backup_branch_i ( backup_pc_i.is_branch ), - .backup_branch_addr_i ( backup_pc_i.branch_addr ), + .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 ), From 4eeb79b53d910c713d589358512c26062b4fc71e Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 15 Nov 2023 17:35:38 +0100 Subject: [PATCH 46/72] [HMR] Fix mismatch count indexing --- rtl/HMR/hmr_unit.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 39d575f7..e6b209de 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -392,7 +392,7 @@ module hmr_unit #( .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_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] ), @@ -533,7 +533,7 @@ module hmr_unit #( .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_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)] ), From 51824c375f187d2f605718a75518101e0bae72af Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Thu, 23 Nov 2023 21:42:01 +0100 Subject: [PATCH 47/72] Create redundant groups only if redundant modes are supported. --- rtl/HMR/hmr_unit.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index e6b209de..fdaf3410 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -47,13 +47,13 @@ module hmr_unit #( parameter type rapid_recovery_t = logic, // Local parameters depending on the above ones /// Number of TMR groups (virtual TMR cores) - localparam int unsigned NumTMRGroups = NumCores/3, + 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 = NumCores/2, + 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 From 85bab760d8385bc18b0ebd5e86eba6c10aa4e42b Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Thu, 30 Nov 2023 15:34:43 +0100 Subject: [PATCH 48/72] Fix out-of-range indices when with a single DMR group. --- rtl/HMR/hmr_unit.sv | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index fdaf3410..42fd9fdd 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -486,19 +486,24 @@ module hmr_unit #( /*************** * Registers * ***************/ - 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 ) - ); + 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; From 9d6e2520ccd92968e74e4f3c8bc4a548f8da7197 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Tue, 12 Dec 2023 22:06:12 +0100 Subject: [PATCH 49/72] Enable usage of checkpoint register for DMR synchronization. --- rtl/HMR/hmr_dmr_ctrl.sv | 3 +++ rtl/HMR/hmr_unit.sv | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 1b55311b..47159a3d 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -14,6 +14,7 @@ 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, @@ -40,6 +41,7 @@ module hmr_dmr_ctrl 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, @@ -70,6 +72,7 @@ module hmr_dmr_ctrl 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), diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 42fd9fdd..b2dd235d 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -86,12 +86,16 @@ module hmr_unit #( 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, 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, @@ -159,6 +163,7 @@ module hmr_unit #( logic [NumDMRGroups-1:0] dmr_failure, dmr_failure_main, 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 * @@ -515,6 +520,7 @@ module hmr_unit #( hmr_dmr_ctrl #( .reg_req_t ( reg_req_t ), .reg_resp_t ( reg_rsp_t ), + .DataWidth ( SysDataWidth ), .InterleaveGrps( InterleaveGrps ), .DMRFixed ( DMRFixed ), .RapidRecovery ( RapidRecovery ), @@ -536,6 +542,7 @@ module hmr_unit #( .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)]} ), @@ -712,6 +719,8 @@ module hmr_unit #( 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))] : @@ -781,6 +790,8 @@ module hmr_unit #( 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"); @@ -843,6 +854,8 @@ module hmr_unit #( 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"); @@ -851,7 +864,7 @@ module hmr_unit #( 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] = '0; + 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; @@ -898,6 +911,7 @@ module hmr_unit #( *****************/ // 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; From 0b385da3fff7bac803901f1d12fc3d20510f289c Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Tue, 12 Dec 2023 22:49:19 +0100 Subject: [PATCH 50/72] Properly rename DMR registers in hmr_dmr_ctrl. --- rtl/HMR/hmr_dmr_ctrl.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/HMR/hmr_dmr_ctrl.sv b/rtl/HMR/hmr_dmr_ctrl.sv index 47159a3d..35b638ba 100644 --- a/rtl/HMR/hmr_dmr_ctrl.sv +++ b/rtl/HMR/hmr_dmr_ctrl.sv @@ -77,7 +77,7 @@ module hmr_dmr_ctrl hmr_dmr_regs_reg_top #( .reg_req_t(reg_req_t), .reg_rsp_t(reg_resp_t) - ) i_tmr_regs ( + ) i_dmr_regs ( .clk_i, .rst_ni, .reg_req_i(reg_req_i), From dff8abdc786964dc7b1c362447b62d69281c6c49 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Tue, 7 May 2024 10:03:00 +0200 Subject: [PATCH 51/72] Extend checker for separate AXI bus. --- rtl/HMR/DMR_checker.sv | 79 ++++++++++++++++++++++++++++++------------ rtl/HMR/hmr_unit.sv | 58 +++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 33 deletions(-) diff --git a/rtl/HMR/DMR_checker.sv b/rtl/HMR/DMR_checker.sv index c28b893d..7ea6f881 100644 --- a/rtl/HMR/DMR_checker.sv +++ b/rtl/HMR/DMR_checker.sv @@ -15,36 +15,69 @@ */ module DMR_checker #( - parameter int unsigned DataWidth = 41, - parameter int unsigned Pipeline = 0 + parameter type check_bus_t = logic, + parameter int unsigned Pipeline = 0, + parameter bit AxiBus = 1'b0 )( - input logic clk_i, - input logic rst_ni, - input logic [DataWidth-1:0] inp_a_i, - input logic [DataWidth-1:0] inp_b_i, - output logic [DataWidth-1:0] check_o, - output logic error_o + 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 ); -logic error; -logic [DataWidth-1:0] compare; -logic [DataWidth-1:0] inp_q; +check_bus_t compare; +check_bus_t inp_q; -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; +if (AxiBus == 1) begin: gen_axi_checker + logic error, error_aw, error_w, error_ar, error_r, error_b; + 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.w <= inp_a_i.w ^ inp_b_i.w; + compare.ar <= inp_a_i.ar ^ inp_b_i.ar; + compare.r <= inp_a_i.r ^ inp_b_i.r; + compare.b <= inp_a_i.b ^ inp_b_i.b; + inp_q <= inp_a_i; + end end + end else begin + assign compare.aw = inp_a_i.aw ^ inp_b_i.aw; + assign compare.w = inp_a_i.w ^ inp_b_i.w; + assign compare.ar = inp_a_i.ar ^ inp_b_i.ar; + assign compare.r = inp_a_i.r ^ inp_b_i.r; + assign compare.b = inp_a_i.b ^ inp_b_i.b; + assign inp_q = inp_a_i; end -end else begin - assign compare = inp_a_i ^ inp_b_i; - assign inp_q = inp_a_i; + assign error_aw = |compare.aw; + assign error_w = |compare.w; + assign error_ar = |compare.ar; + assign error_r = |compare.r; + assign error_b = |compare.b; + assign error = error_aw | error_w | error_ar | error_r | error_b; +end else begin: gen_generic_checker + logic error; + 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 error = |compare; assign check_o = (error) ? '0 : inp_q; assign error_o = error; diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index b2dd235d..bcbb7d3e 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -28,6 +28,8 @@ module hmr_unit #( 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, /// 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) @@ -41,6 +43,8 @@ module hmr_unit #( 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 @@ -91,6 +95,7 @@ module hmr_unit #( 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, @@ -99,7 +104,8 @@ module hmr_unit #( 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 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; @@ -153,6 +159,7 @@ module hmr_unit #( 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; @@ -161,7 +168,7 @@ module hmr_unit #( 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_backup; + 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; @@ -562,7 +569,7 @@ module hmr_unit #( * DMR Core Checkers * *********************/ DMR_checker #( - .DataWidth ( $bits(nominal_outputs_t) ) + .check_bus_t ( nominal_outputs_t ) ) dmr_core_checker_main ( .clk_i ( ), .rst_ni ( ), @@ -571,13 +578,28 @@ module hmr_unit #( .check_o ( dmr_nominal_outputs [ i ] ), .error_o ( dmr_failure_main [ i ] ) ); + if (SeparateAxiBus) begin: gen_axi_checker + DMR_axi_checker #( + .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 = '0; + assign dmr_failure_axi = '0; + end if (SeparateData) begin : gen_data_checker for (genvar j = 0; j < NumBusVoters; j++) begin DMR_checker # ( - .DataWidth ( $bits(bus_outputs_t) ) + .check_bus_t ( bus_outputs_t ) ) dmr_core_checker_data ( - .clk_i ( ), - .rst_ni ( ), + .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] ), @@ -589,7 +611,7 @@ module hmr_unit #( if (RapidRecovery) begin : gen_rapid_recovery_unit DMR_checker #( - .DataWidth ( $bits(core_backup_t) ), + .check_bus_t ( core_backup_t ), .Pipeline ( 1 ) ) dmr_core_checker_backup ( .clk_i ( clk_i ), @@ -636,7 +658,7 @@ module hmr_unit #( ); always_comb begin - dmr_failure[i] = dmr_failure_main[i] | dmr_failure_backup[i]; + 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]; @@ -645,7 +667,7 @@ module hmr_unit #( end end else begin : gen_standard_failure always_comb begin - dmr_failure[i] = dmr_failure_main[i]; + 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]; @@ -657,10 +679,12 @@ module hmr_unit #( 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; @@ -760,24 +784,29 @@ module hmr_unit #( 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_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; 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; 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 @@ -818,12 +847,15 @@ module hmr_unit #( 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]; @@ -882,23 +914,28 @@ module hmr_unit #( 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; 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 @@ -915,6 +952,7 @@ module hmr_unit #( 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 From c44ff73521186d2bc1dd77a17664539a3b3e2406 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 22 May 2024 13:51:53 +0200 Subject: [PATCH 52/72] Fix AXI DMR checker. --- rtl/HMR/DMR_checker.sv | 42 ++++++++++++++++++++++++------------------ rtl/HMR/hmr_unit.sv | 7 ++++--- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/rtl/HMR/DMR_checker.sv b/rtl/HMR/DMR_checker.sv index 7ea6f881..e8695978 100644 --- a/rtl/HMR/DMR_checker.sv +++ b/rtl/HMR/DMR_checker.sv @@ -29,39 +29,45 @@ module DMR_checker #( check_bus_t compare; check_bus_t inp_q; +logic error; if (AxiBus == 1) begin: gen_axi_checker - logic error, error_aw, error_w, error_ar, error_r, error_b; + logic error_aw, error_w, error_ar, error_r, error_b; 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.w <= inp_a_i.w ^ inp_b_i.w; - compare.ar <= inp_a_i.ar ^ inp_b_i.ar; - compare.r <= inp_a_i.r ^ inp_b_i.r; - compare.b <= inp_a_i.b ^ inp_b_i.b; - inp_q <= inp_a_i; + 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; + inp_q <= inp_a_i; end end end else begin - assign compare.aw = inp_a_i.aw ^ inp_b_i.aw; - assign compare.w = inp_a_i.w ^ inp_b_i.w; - assign compare.ar = inp_a_i.ar ^ inp_b_i.ar; - assign compare.r = inp_a_i.r ^ inp_b_i.r; - assign compare.b = inp_a_i.b ^ inp_b_i.b; + 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; assign inp_q = inp_a_i; end - assign error_aw = |compare.aw; - assign error_w = |compare.w; - assign error_ar = |compare.ar; - assign error_r = |compare.r; - assign error_b = |compare.b; + 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; assign error = error_aw | error_w | error_ar | error_r | error_b; end else begin: gen_generic_checker - logic error; if (Pipeline) begin always_ff @(posedge clk_i, negedge rst_ni) begin if (~rst_ni) begin diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index bcbb7d3e..27988fe6 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -579,7 +579,8 @@ module hmr_unit #( .error_o ( dmr_failure_main [ i ] ) ); if (SeparateAxiBus) begin: gen_axi_checker - DMR_axi_checker #( + DMR_checker #( + .AxiBus ( SeparateAxiBus ), .check_bus_t ( axi_req_t ) ) dmr_core_checker_axi ( .clk_i ( ), @@ -590,8 +591,8 @@ module hmr_unit #( .error_o ( dmr_failure_axi [ i ] ) ); end else begin: gen_no_axi_checker - assign dmr_axi_outputs = '0; - assign dmr_failure_axi = '0; + 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 From 5f7a22c8223a6d1e811ab197d6faef3848712cd0 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 29 May 2024 14:56:28 +0200 Subject: [PATCH 53/72] Fix undefined assign if bus voters are not there. --- rtl/HMR/hmr_unit.sv | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 27988fe6..e84b944e 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -607,6 +607,9 @@ module hmr_unit #( .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 From d08dc33f97379ab7cae614c3b70729effb6d5cc6 Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Wed, 17 Apr 2024 01:14:18 +0200 Subject: [PATCH 54/72] Add sram update when a sram read finds a correctable error and corrects it. --- rtl/ecc_wrap/ecc_sram_wrap.sv | 82 ++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/rtl/ecc_wrap/ecc_sram_wrap.sv b/rtl/ecc_wrap/ecc_sram_wrap.sv index f21c9b98..7b3b8b0b 100644 --- a/rtl/ecc_wrap/ecc_sram_wrap.sv +++ b/rtl/ecc_wrap/ecc_sram_wrap.sv @@ -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; @@ -149,7 +161,16 @@ module ecc_sram_wrap #( assign tcdm_rdata_o = loaded; - assign to_store = store_state_q == NORMAL ? tcdm_wdata_i : (be_selector & input_buffer_q) | (~be_selector & loaded); + 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 @@ -195,27 +216,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 != 4'b1111) & ~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 From 0c0b2da41398554ea59e3f8c6c954a75e35256d5 Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Mon, 6 May 2024 17:02:00 +0200 Subject: [PATCH 55/72] Add the outer scrubber to manage both tag and data sram scrubbing simultaneously --- Bender.yml | 1 + rtl/ecc_wrap/ecc_scrubber_out.sv | 227 +++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 rtl/ecc_wrap/ecc_scrubber_out.sv diff --git a/Bender.yml b/Bender.yml index 3f3700ae..53568b8a 100644 --- a/Bender.yml +++ b/Bender.yml @@ -43,6 +43,7 @@ sources: - 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: diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv new file mode 100644 index 00000000..f1e57daa --- /dev/null +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -0,0 +1,227 @@ +// 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 axi_llc_pkg::llc_cfg_t Cfg = axi_llc_pkg::llc_cfg_t'{default: '0}, + parameter int unsigned TagWidth = 32, + parameter int unsigned DataWidth = 128, + parameter int unsigned TagDepth = 256, + parameter int unsigned DataDepth = 2048, + 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 bit_corrected_o, + output logic uncorrectable_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 [ TagWidth-1:0] tag_intc_wdata_i, + output logic [ TagWidth-1:0] tag_intc_rdata_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 logic [(Cfg.BlockSize + 8 - 32'd1) / 8] 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 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 [ TagWidth-1:0] tag_bank_wdata_o, + input logic [ TagWidth-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 logic [(Cfg.BlockSize + 8 - 32'd1) / 8] data_bank_be_o, + output logic [$clog2(DataDepth)-1:0] data_bank_add_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 single_error; + logic multi_error; + + + logic scrub_req; + logic scrub_we; + logic [$clog2(DataDepth)-1:0] scrub_add; + // logic [ DataWidth-1:0] scrub_wdata; + logic [ TagWidth-1:0] scrub_tag_rdata; + logic [ DataWidth-1:0] scrub_data_rdata; + + typedef enum logic [2:0] {Idle, Read, Check} scrub_state_e; + + scrub_state_e state_d, state_q; + + logic [$clog2(DataDepth)-1:0] working_add_d, working_add_q; // use data addr as it should be >= tag addr size, because the block number per index + + logic tag_rdata_en, tag_rdata_en_q; + logic data_rdata_en, data_rdata_en_q; + logic [TagWidth-1:0] tag_rdata_q; + logic [DataWidth-1:0] data_rdata_q; + + assign tag_rdata_en = tag_intc_req_i & tag_bank_gnt_i & ~tag_intc_we_i; + assign data_rdata_en = data_intc_req_i & data_bank_gnt_i & ~data_intc_we_i; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if(~rst_ni) begin + tag_rdata_q <= '0; + end else if (tag_rdata_en_q) begin + tag_rdata_q <= tag_bank_rdata_i; + 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 + tag_rdata_en_q <= 1'b0; + data_rdata_en_q <= 1'b0; + end else begin + tag_rdata_en_q <= tag_rdata_en; + data_rdata_en_q <= data_rdata_en; + end + end + + + assign scrub_add = working_add_q; + + assign tag_bank_req_o = tag_intc_req_i || scrub_req; + assign tag_intc_rdata_o = tag_rdata_en_q ? tag_bank_rdata_i : tag_rdata_q; + assign tag_intc_gnt_o = tag_bank_gnt_i; + + assign data_bank_req_o = data_intc_req_i || scrub_req; + assign data_intc_rdata_o = data_rdata_en_q ? data_bank_rdata_i : data_rdata_q; + assign data_intc_gnt_o = data_bank_gnt_i; + + 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 ( (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_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; + working_add_d = working_add_q; + bit_corrected_o = 1'b0; + uncorrectable_o = 1'b0; + + if (state_q == Idle) begin + // Switch to read state if triggered to scrub + if (scrub_trigger_i) begin + state_d = Read; + end + + end else if (state_q == 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 else if (state_q == Check) begin + // Return to idle state + state_d = Idle; + working_add_d = (working_add_q + 1) % DataDepth; // increment address + bit_corrected_o = single_error; + uncorrectable_o = multi_error; + end + end + + // TODO: tag sram has uncorrectable error, interrupt + // TODO: data sram has uncorrectable error, interrupt, has addr info + + + assign single_error = ecc_err_i.tag_sram_single_error | ecc_err_i.data_sram_single_error; + assign multi_error = ecc_err_i.tag_sram_multi_error | ecc_err_i.data_sram_multi_error; + + + 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 + +endmodule From b560369bc3257acb137d7759533c37aafa7e64ab Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Sun, 12 May 2024 22:05:06 +0200 Subject: [PATCH 56/72] 1.Add multi error info propagation path in the ecc_scrubber_out; 2.Modify the starting offset of ecc manager regs --- rtl/ecc_wrap/ECC.h | 12 +++++------ rtl/ecc_wrap/ecc_manager_reg_pkg.sv | 17 ++++++++------- rtl/ecc_wrap/ecc_manager_reg_top.sv | 4 ++-- rtl/ecc_wrap/ecc_scrubber_out.sv | 32 +++++++++++++++++++++++++---- rtl/ecc_wrap/ecc_sram_wrapper.hjson | 9 ++++++++ 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/rtl/ecc_wrap/ECC.h b/rtl/ecc_wrap/ECC.h index 33567315..4e112a5a 100644 --- a/rtl/ecc_wrap/ECC.h +++ b/rtl/ecc_wrap/ECC.h @@ -10,22 +10,22 @@ extern "C" { #define ECC_MANAGER_PARAM_REG_WIDTH 32 // Correctable mismatches caught by ecc on access -#define ECC_MANAGER_MISMATCH_COUNT_REG_OFFSET 0x0 +#define ECC_MANAGER_MISMATCH_COUNT_REG_OFFSET 0x100 // Interval between scrubs -#define ECC_MANAGER_SCRUB_INTERVAL_REG_OFFSET 0x4 +#define ECC_MANAGER_SCRUB_INTERVAL_REG_OFFSET 0x104 // Correctable mismatches caught by ecc on scrub -#define ECC_MANAGER_SCRUB_FIX_COUNT_REG_OFFSET 0x8 +#define ECC_MANAGER_SCRUB_FIX_COUNT_REG_OFFSET 0x108 // Uncorrectable mismatches caught by ecc on scrub -#define ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_REG_OFFSET 0xc +#define ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_REG_OFFSET 0x10c // Testing: Inverted write mask for data bits -#define ECC_MANAGER_WRITE_MASK_DATA_N_REG_OFFSET 0x10 +#define ECC_MANAGER_WRITE_MASK_DATA_N_REG_OFFSET 0x110 // Testing: Inverted write mask for ECC bits -#define ECC_MANAGER_WRITE_MASK_ECC_N_REG_OFFSET 0x14 +#define ECC_MANAGER_WRITE_MASK_ECC_N_REG_OFFSET 0x114 #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_MASK 0x7f #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_OFFSET 0 #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_FIELD \ diff --git a/rtl/ecc_wrap/ecc_manager_reg_pkg.sv b/rtl/ecc_wrap/ecc_manager_reg_pkg.sv index 6c6b88df..d26d7007 100644 --- a/rtl/ecc_wrap/ecc_manager_reg_pkg.sv +++ b/rtl/ecc_wrap/ecc_manager_reg_pkg.sv @@ -6,8 +6,11 @@ package ecc_manager_reg_pkg; + // Param list + parameter OffsetStart = 'h100; + // Address widths within the block - parameter int BlockAw = 5; + parameter int BlockAw = 9; //////////////////////////// // Typedefs for registers // @@ -70,12 +73,12 @@ package ecc_manager_reg_pkg; } ecc_manager_hw2reg_t; // Register offsets - parameter logic [BlockAw-1:0] ECC_MANAGER_MISMATCH_COUNT_OFFSET = 5'h 0; - parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_INTERVAL_OFFSET = 5'h 4; - parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_FIX_COUNT_OFFSET = 5'h 8; - parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_OFFSET = 5'h c; - parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_DATA_N_OFFSET = 5'h 10; - parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_ECC_N_OFFSET = 5'h 14; + parameter logic [BlockAw-1:0] ECC_MANAGER_MISMATCH_COUNT_OFFSET = 9'h 100; + parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_INTERVAL_OFFSET = 9'h 104; + parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_FIX_COUNT_OFFSET = 9'h 108; + parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_OFFSET = 9'h 10c; + parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_DATA_N_OFFSET = 9'h 110; + parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_ECC_N_OFFSET = 9'h 114; // Register index typedef enum int { diff --git a/rtl/ecc_wrap/ecc_manager_reg_top.sv b/rtl/ecc_wrap/ecc_manager_reg_top.sv index eea5ba55..f3d765aa 100644 --- a/rtl/ecc_wrap/ecc_manager_reg_top.sv +++ b/rtl/ecc_wrap/ecc_manager_reg_top.sv @@ -10,7 +10,7 @@ module ecc_manager_reg_top #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, - parameter int AW = 5 + parameter int AW = 9 ) ( input logic clk_i, input logic rst_ni, @@ -344,7 +344,7 @@ endmodule module ecc_manager_reg_top_intf #( - parameter int AW = 5, + parameter int AW = 9, localparam int DW = 32 ) ( input logic clk_i, diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv index f1e57daa..5355a5f1 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -39,15 +39,17 @@ module ecc_scrubber_out #( input logic [$clog2(TagDepth)-1:0] tag_intc_add_i, input logic [ TagWidth-1:0] tag_intc_wdata_i, output logic [ TagWidth-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 logic [(Cfg.BlockSize + 8 - 32'd1) / 8] data_intc_be_i, + input logic [(Cfg.BlockSize + 8 - 32'd1) / 8-1:0] 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, @@ -62,7 +64,7 @@ module ecc_scrubber_out #( output logic data_bank_req_o, input logic data_bank_gnt_i, output logic data_bank_we_o, - output logic [(Cfg.BlockSize + 8 - 32'd1) / 8] data_bank_be_o, + output logic [(Cfg.BlockSize + 8 - 32'd1) / 8-1:0] data_bank_be_o, output logic [$clog2(DataDepth)-1:0] data_bank_add_o, output logic [ DataWidth-1:0] data_bank_wdata_o, input logic [ DataWidth-1:0] data_bank_rdata_i, @@ -90,17 +92,25 @@ module ecc_scrubber_out #( 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 [TagWidth-1:0] tag_rdata_q; logic [DataWidth-1:0] data_rdata_q; + logic tag_intc_multi_err_q; + logic data_intc_multi_err_q; assign tag_rdata_en = tag_intc_req_i & tag_bank_gnt_i & ~tag_intc_we_i; assign data_rdata_en = data_intc_req_i & data_bank_gnt_i & ~data_intc_we_i; + assign data_wdata_en = data_intc_req_i & data_bank_gnt_i & 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 @@ -112,13 +122,24 @@ module ecc_scrubber_out #( 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 @@ -126,12 +147,15 @@ module ecc_scrubber_out #( assign scrub_add = working_add_q; assign tag_bank_req_o = tag_intc_req_i || scrub_req; - assign tag_intc_rdata_o = tag_rdata_en_q ? tag_bank_rdata_i : tag_rdata_q; assign tag_intc_gnt_o = tag_bank_gnt_i; + 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_rdata_o = data_rdata_en_q ? data_bank_rdata_i : data_rdata_q; 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; diff --git a/rtl/ecc_wrap/ecc_sram_wrapper.hjson b/rtl/ecc_wrap/ecc_sram_wrapper.hjson index b635caf2..983e0018 100644 --- a/rtl/ecc_wrap/ecc_sram_wrapper.hjson +++ b/rtl/ecc_wrap/ecc_sram_wrapper.hjson @@ -9,8 +9,17 @@ ], regwidth: "32", + param_list: [ + { name: "OffsetStart", + desc: "Starting offset of this reg set", + type: "", + default: "'h100", + local: "true" + }, + ], registers: [ + { skipto: "0x100" } { name: "mismatch_count", desc: "Correctable mismatches caught by ecc on access", swaccess: "rw0c", From b62b4be59f81b17694f3018c247a7983ad0092ce Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Sun, 12 May 2024 23:11:19 +0200 Subject: [PATCH 57/72] decouple the parameter with axi_llc --- rtl/ecc_wrap/ecc_scrubber_out.sv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv index 5355a5f1..5ad4697d 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -13,7 +13,7 @@ // - 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 axi_llc_pkg::llc_cfg_t Cfg = axi_llc_pkg::llc_cfg_t'{default: '0}, + parameter type data_be_t = logic, parameter int unsigned TagWidth = 32, parameter int unsigned DataWidth = 128, parameter int unsigned TagDepth = 256, @@ -45,7 +45,7 @@ module ecc_scrubber_out #( input logic data_intc_req_i, output logic data_intc_gnt_o, input logic data_intc_we_i, - input logic [(Cfg.BlockSize + 8 - 32'd1) / 8-1:0] data_intc_be_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, @@ -64,7 +64,7 @@ module ecc_scrubber_out #( output logic data_bank_req_o, input logic data_bank_gnt_i, output logic data_bank_we_o, - output logic [(Cfg.BlockSize + 8 - 32'd1) / 8-1:0] data_bank_be_o, + output data_be_t data_bank_be_o, output logic [$clog2(DataDepth)-1:0] data_bank_add_o, output logic [ DataWidth-1:0] data_bank_wdata_o, input logic [ DataWidth-1:0] data_bank_rdata_i, From 47d730608207afd6d811d7c06d7bcdd1f8c9e8da Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Mon, 13 May 2024 03:36:52 +0200 Subject: [PATCH 58/72] Modify ecc_sram_wrap for parameterizable data width --- rtl/ecc_wrap/ecc_sram_wrap.sv | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/rtl/ecc_wrap/ecc_sram_wrap.sv b/rtl/ecc_wrap/ecc_sram_wrap.sv index 7b3b8b0b..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) @@ -114,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; @@ -219,7 +222,7 @@ module ecc_sram_wrap #( in_update_corrected_data_mode = 1'b0; case (store_state_q) NORMAL: begin - if (tcdm_req_i & (tcdm_be_i != 4'b1111) & ~tcdm_wen_i) 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; @@ -277,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, From eba1154ecb66b0b1b6e7dd189204d1231044fbad Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Wed, 22 May 2024 04:25:21 +0200 Subject: [PATCH 59/72] 1.Re-generate ecc_manager_reg, test access to the regs; 2.Add more ecc info output to the ecc_scrubber_out --- rtl/ecc_wrap/ecc_manager_reg_pkg.sv | 14 +++--- rtl/ecc_wrap/ecc_manager_reg_top.sv | 66 +++-------------------------- rtl/ecc_wrap/ecc_scrubber_out.sv | 50 ++++++++++++++++------ rtl/ecc_wrap/ecc_sram_wrapper.hjson | 1 - 4 files changed, 51 insertions(+), 80 deletions(-) diff --git a/rtl/ecc_wrap/ecc_manager_reg_pkg.sv b/rtl/ecc_wrap/ecc_manager_reg_pkg.sv index d26d7007..cb741759 100644 --- a/rtl/ecc_wrap/ecc_manager_reg_pkg.sv +++ b/rtl/ecc_wrap/ecc_manager_reg_pkg.sv @@ -10,7 +10,7 @@ package ecc_manager_reg_pkg; parameter OffsetStart = 'h100; // Address widths within the block - parameter int BlockAw = 9; + parameter int BlockAw = 5; //////////////////////////// // Typedefs for registers // @@ -73,12 +73,12 @@ package ecc_manager_reg_pkg; } ecc_manager_hw2reg_t; // Register offsets - parameter logic [BlockAw-1:0] ECC_MANAGER_MISMATCH_COUNT_OFFSET = 9'h 100; - parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_INTERVAL_OFFSET = 9'h 104; - parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_FIX_COUNT_OFFSET = 9'h 108; - parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_OFFSET = 9'h 10c; - parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_DATA_N_OFFSET = 9'h 110; - parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_ECC_N_OFFSET = 9'h 114; + parameter logic [BlockAw-1:0] ECC_MANAGER_MISMATCH_COUNT_OFFSET = 5'h 0; + parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_INTERVAL_OFFSET = 5'h 4; + parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_FIX_COUNT_OFFSET = 5'h 8; + parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_OFFSET = 5'h c; + parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_DATA_N_OFFSET = 5'h 10; + parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_ECC_N_OFFSET = 5'h 14; // Register index typedef enum int { diff --git a/rtl/ecc_wrap/ecc_manager_reg_top.sv b/rtl/ecc_wrap/ecc_manager_reg_top.sv index f3d765aa..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 = 9 + 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 = 9, - 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 index 5ad4697d..e12967b2 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -28,8 +28,15 @@ module ecc_scrubber_out #( input logic rst_ni, input logic scrub_trigger_i, // Set to 1'b0 to disable - output logic bit_corrected_o, - output logic uncorrectable_o, + 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, // Input signals from others accessing tag memory bank input logic tag_intc_req_i, @@ -46,7 +53,7 @@ module ecc_scrubber_out #( 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 [$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, @@ -73,10 +80,6 @@ module ecc_scrubber_out #( input error_info_per_way_t ecc_err_i ); - logic single_error; - logic multi_error; - - logic scrub_req; logic scrub_we; logic [$clog2(DataDepth)-1:0] scrub_add; @@ -194,8 +197,10 @@ module ecc_scrubber_out #( state_d = state_q; scrub_req = 1'b0; working_add_d = working_add_q; - bit_corrected_o = 1'b0; - uncorrectable_o = 1'b0; + 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; if (state_q == Idle) begin // Switch to read state if triggered to scrub @@ -219,8 +224,11 @@ module ecc_scrubber_out #( // Return to idle state state_d = Idle; working_add_d = (working_add_q + 1) % DataDepth; // increment address - bit_corrected_o = single_error; - uncorrectable_o = multi_error; + + 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 end @@ -228,8 +236,10 @@ module ecc_scrubber_out #( // TODO: data sram has uncorrectable error, interrupt, has addr info - assign single_error = ecc_err_i.tag_sram_single_error | ecc_err_i.data_sram_single_error; - assign multi_error = ecc_err_i.tag_sram_multi_error | ecc_err_i.data_sram_multi_error; + 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; always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bank_add @@ -248,4 +258,18 @@ module ecc_scrubber_out #( 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_wrapper.hjson b/rtl/ecc_wrap/ecc_sram_wrapper.hjson index 983e0018..b7026c45 100644 --- a/rtl/ecc_wrap/ecc_sram_wrapper.hjson +++ b/rtl/ecc_wrap/ecc_sram_wrapper.hjson @@ -19,7 +19,6 @@ ], registers: [ - { skipto: "0x100" } { name: "mismatch_count", desc: "Correctable mismatches caught by ecc on access", swaccess: "rw0c", From f95ca1a036987cec23a6957f6ee7f9c2a9b706ce Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Tue, 28 May 2024 11:26:07 +0200 Subject: [PATCH 60/72] Add valid, dirty, and addr info output on ecc_scrubber_out for uncorrectable ecc error reports --- rtl/ecc_wrap/ecc_scrubber_out.sv | 48 +++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv index e12967b2..c457d5b2 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -14,7 +14,8 @@ module ecc_scrubber_out #( parameter type data_be_t = logic, - parameter int unsigned TagWidth = 32, + 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, @@ -38,14 +39,17 @@ module ecc_scrubber_out #( 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 [ TagWidth-1:0] tag_intc_wdata_i, - output logic [ TagWidth-1:0] tag_intc_rdata_o, + 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 @@ -64,8 +68,9 @@ module ecc_scrubber_out #( output logic tag_bank_we_o, output logic tag_bank_be_o, output logic [$clog2(TagDepth)-1:0] tag_bank_add_o, - output logic [ TagWidth-1:0] tag_bank_wdata_o, - input logic [ TagWidth-1:0] tag_bank_rdata_i, + 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, @@ -73,6 +78,7 @@ module ecc_scrubber_out #( 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, @@ -84,7 +90,7 @@ module ecc_scrubber_out #( logic scrub_we; logic [$clog2(DataDepth)-1:0] scrub_add; // logic [ DataWidth-1:0] scrub_wdata; - logic [ TagWidth-1:0] scrub_tag_rdata; + logic [ TagSramWidth-1:0] scrub_tag_rdata; logic [ DataWidth-1:0] scrub_data_rdata; typedef enum logic [2:0] {Idle, Read, Check} scrub_state_e; @@ -93,18 +99,24 @@ module ecc_scrubber_out #( logic [$clog2(DataDepth)-1:0] working_add_d, working_add_q; // 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 [TagWidth-1:0] tag_rdata_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_intc_req_i & tag_bank_gnt_i & ~tag_intc_we_i; - assign data_rdata_en = data_intc_req_i & data_bank_gnt_i & ~data_intc_we_i; - assign data_wdata_en = data_intc_req_i & data_bank_gnt_i & data_intc_we_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 @@ -178,6 +190,18 @@ module ecc_scrubber_out #( end end + always_ff @(posedge clk_i) begin + if(tag_rwdata_en) begin + tag_bank_add_q <= tag_bank_add_o; + end + if(data_rwdata_en) begin + data_bank_add_q <= data_bank_add_o; + 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; @@ -241,6 +265,10 @@ module ecc_scrubber_out #( 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]; + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bank_add if(!rst_ni) begin From 304295f29c35404fa68eb9427efbff34813bf740 Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Sat, 1 Jun 2024 18:56:35 +0200 Subject: [PATCH 61/72] Add sram update when a sram read finds a correctable error and corrects it to the ecc_sram --- rtl/ecc_wrap/ecc_sram.sv | 77 +++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/rtl/ecc_wrap/ecc_sram.sv b/rtl/ecc_wrap/ecc_sram.sv index 15df7b02..d3a521f3 100644 --- a/rtl/ecc_wrap/ecc_sram.sv +++ b/rtl/ecc_wrap/ecc_sram.sv @@ -45,17 +45,28 @@ module ecc_sram #( 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 = 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; @@ -80,7 +91,7 @@ module ecc_sram #( 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; @@ -144,8 +155,15 @@ module ecc_sram #( assign to_store = store_state_q == NORMAL ? 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 = rdata_o; + + end else begin : gen_ecc_input logic [ ProtectedWidth-1:0] lns_wdata; @@ -194,27 +212,46 @@ 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(valid_load_q && single_error_o) begin + store_state_d = UPDATE_CORRECTED_DATA; + gnt_o = 1'b0; + addr_buffer_d = addr_buffer_q; + bank_req = 1'b0; + 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_req = 1'b1; + bank_we = 1'b1; + bank_addr = addr_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_read_modify_write_ff From 0a62f8f76d388ca664a110f5f6d744057377eb5f Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Thu, 6 Jun 2024 04:59:18 +0200 Subject: [PATCH 62/72] [CUT TIMING] Try to add a timing cut after tag ram read --- rtl/ecc_wrap/ecc_scrubber_out.sv | 2 +- rtl/ecc_wrap/ecc_sram.sv | 31 +++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv index c457d5b2..d31bbd0a 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -210,7 +210,7 @@ module ecc_scrubber_out #( 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 + 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; diff --git a/rtl/ecc_wrap/ecc_sram.sv b/rtl/ecc_wrap/ecc_sram.sv index d3a521f3..2145df08 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 @@ -50,6 +51,9 @@ module ecc_sram #( logic corrected_data_raw_en; 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; @@ -85,8 +89,8 @@ 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; @@ -151,17 +155,17 @@ module ecc_sram #( .out ( bank_wdata ) ); - assign rdata_o = loaded; + assign rdata = loaded; assign to_store = store_state_q == NORMAL ? wdata_i : - in_update_corrected_data_mode ? - corrected_data_raw_q : - (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; // 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 = rdata_o; + assign corrected_data_raw_d = rdata; end else begin : gen_ecc_input @@ -170,7 +174,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), @@ -321,4 +325,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 From d1c35a7fde92328f5cf6d96f88239b1d4dbda0d0 Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Thu, 6 Jun 2024 18:24:04 +0200 Subject: [PATCH 63/72] [RTL] Add correct data buffer, so for continuous read, the corrected data update won't stall the flow, also cut the gnt_o timing path relies on the ecc decode result. --- rtl/ecc_wrap/ecc_sram.sv | 44 ++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/rtl/ecc_wrap/ecc_sram.sv b/rtl/ecc_wrap/ecc_sram.sv index 2145df08..836eca63 100644 --- a/rtl/ecc_wrap/ecc_sram.sv +++ b/rtl/ecc_wrap/ecc_sram.sv @@ -44,11 +44,19 @@ 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; - logic [DataInWidth-1:0] corrected_data_raw_d, corrected_data_raw_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; @@ -57,6 +65,7 @@ module ecc_sram #( 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; @@ -64,10 +73,23 @@ module ecc_sram #( end always_ff @(posedge clk_i) begin : proc_corrected_data_update - if(corrected_data_raw_en) begin + 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; @@ -161,11 +183,14 @@ module ecc_sram #( wdata_i : store_state_q == READ_MODIFY_WRITE ? (be_selector & input_buffer_q) | (~be_selector & loaded) : - corrected_data_raw_q; + 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 = rdata; + 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 @@ -224,11 +249,8 @@ module ecc_sram #( bank_we = 1'b0; rmw_count_d = rmw_count_t'(NumRMWCuts); end - if(valid_load_q && single_error_o) begin + if(~req_i & corrected_data_raw_valid_q) begin store_state_d = UPDATE_CORRECTED_DATA; - gnt_o = 1'b0; - addr_buffer_d = addr_buffer_q; - bank_req = 1'b0; end end READ_MODIFY_WRITE: begin @@ -248,9 +270,9 @@ module ecc_sram #( end UPDATE_CORRECTED_DATA: begin gnt_o = 1'b0; - bank_req = 1'b1; + bank_addr = corrected_data_raw_q.bank_addr; bank_we = 1'b1; - bank_addr = addr_buffer_q; + bank_req = 1'b1; in_update_corrected_data_mode = 1'b1; store_state_d = NORMAL; end From f41308f0d9afbcc309592783b0b982a2edbe217a Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Fri, 7 Jun 2024 05:15:51 +0200 Subject: [PATCH 64/72] [RTL] Add support to multi-cycle delay sram to ecc_scrubber_out --- rtl/ecc_wrap/ecc_scrubber_out.sv | 55 +++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv index d31bbd0a..09615cfe 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -19,6 +19,8 @@ module ecc_scrubber_out #( 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 @@ -146,18 +148,47 @@ module ecc_scrubber_out #( 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 - + // 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; From 9cf639bbbd2ec25bbe9a6d31ed420205d3a7f633 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Sat, 8 Jun 2024 16:51:48 +0200 Subject: [PATCH 65/72] Add output signal to manifest that redundancy enabled. --- rtl/HMR/hmr_unit.sv | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index e84b944e..49ad7bf1 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -85,6 +85,7 @@ module hmr_unit #( 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, @@ -206,6 +207,8 @@ module hmr_unit #( 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; @@ -474,7 +477,7 @@ module hmr_unit #( 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_grp_in_independent = '1; assign tmr_setback_q = '0; assign tmr_resynch_req_o = '0; assign tmr_sw_synch_req_o = '0; From 12ab2675f0abdd84125f7781de1de0493c86d5a1 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Sun, 9 Jun 2024 00:22:47 +0200 Subject: [PATCH 66/72] Pipeline in independend backup bus whem Rapid Recovery is enabled. --- rtl/HMR/hmr_unit.sv | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 49ad7bf1..39dd7e0b 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -182,7 +182,7 @@ module hmr_unit #( 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_t [NumBackupRegs-1:0] rapid_recovery_backup_bus, core_backup_q; nominal_outputs_t [NumBackupRegs-1:0] rapid_recovery_nominal; /*************************** @@ -671,7 +671,6 @@ module hmr_unit #( 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]; @@ -700,6 +699,17 @@ module hmr_unit #( 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; @@ -708,8 +718,8 @@ module hmr_unit #( tmr_recovery_finished = '0; if (InterleaveGrps) begin for (int i = 0; i < NumBackupRegs; i++) begin - rapid_recovery_nominal[i] = core_nominal_outputs_i[i]; - rapid_recovery_backup_bus[i] = core_backup_i[i]; + 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 @@ -731,6 +741,7 @@ module hmr_unit #( 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; From 49e714b97a19a7aaddf064ae2757c8f02d1f62dc Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Sun, 9 Jun 2024 09:18:57 +0200 Subject: [PATCH 67/72] Fix always comb. --- rtl/HMR/hmr_unit.sv | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 39dd7e0b..fba709ab 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -664,11 +664,12 @@ module hmr_unit #( .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]; + 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 From efa5d0c42ec319d0cadc5fe3f5d030f74a550714 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 19 Jun 2024 13:49:52 +0200 Subject: [PATCH 68/72] Add ACE buses to DMR checkers. --- rtl/HMR/DMR_checker.sv | 32 ++++++++++++++++++++++++++++---- rtl/HMR/hmr_unit.sv | 2 ++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/rtl/HMR/DMR_checker.sv b/rtl/HMR/DMR_checker.sv index e8695978..ec4d9ceb 100644 --- a/rtl/HMR/DMR_checker.sv +++ b/rtl/HMR/DMR_checker.sv @@ -17,7 +17,8 @@ module DMR_checker #( parameter type check_bus_t = logic, parameter int unsigned Pipeline = 0, - parameter bit AxiBus = 1'b0 + parameter bit AxiBus = 1'b0, + parameter bit AxiHasAce = 1'b0 )( input logic clk_i, input logic rst_ni, @@ -32,7 +33,7 @@ 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; + 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 @@ -47,7 +48,14 @@ if (AxiBus == 1) begin: gen_axi_checker 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; - inp_q <= inp_a_i; + 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 @@ -59,6 +67,13 @@ if (AxiBus == 1) begin: gen_axi_checker 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; @@ -66,7 +81,16 @@ if (AxiBus == 1) begin: gen_axi_checker assign error_ar = (|compare.ar) | compare.ar_valid; assign error_r = compare.r_ready; assign error_b = compare.b_ready; - assign error = error_aw | error_w | error_ar | error_r | error_b; + 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 diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index fba709ab..8022fbd4 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -30,6 +30,7 @@ module hmr_unit #( 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) @@ -584,6 +585,7 @@ module hmr_unit #( if (SeparateAxiBus) begin: gen_axi_checker DMR_checker #( .AxiBus ( SeparateAxiBus ), + .AxiHasAce ( AxiHasAce ), .check_bus_t ( axi_req_t ) ) dmr_core_checker_axi ( .clk_i ( ), From 78aff2115bddcbb6970c37d19da50e6bc59e5c8a Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 19 Jun 2024 14:10:23 +0200 Subject: [PATCH 69/72] Drive r/b_ready signals to default 1 for helper cores when DMR is enabled. --- rtl/HMR/hmr_unit.sv | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rtl/HMR/hmr_unit.sv b/rtl/HMR/hmr_unit.sv index 8022fbd4..a03d997f 100644 --- a/rtl/HMR/hmr_unit.sv +++ b/rtl/HMR/hmr_unit.sv @@ -811,6 +811,8 @@ module hmr_unit #( 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 @@ -823,6 +825,8 @@ module hmr_unit #( 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]; @@ -884,6 +888,8 @@ module hmr_unit #( 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]; @@ -952,6 +958,8 @@ module hmr_unit #( 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]; From 6e7a0315e5aeb478416110e1585240c2bb3d45e6 Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Mon, 24 Jun 2024 22:11:31 +0200 Subject: [PATCH 70/72] [RTL] Uncorrectable error handling: When the external scrubber finds uncorrectable errors in a valid and clean data line, and there is no uncorrectable error in its tag info, set the cache line invalid. --- rtl/ecc_wrap/ecc_scrubber_out.sv | 116 ++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 40 deletions(-) diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv index 09615cfe..b4564153 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -50,8 +50,8 @@ module ecc_scrubber_out #( 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, + 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 @@ -71,16 +71,16 @@ module ecc_scrubber_out #( 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 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 [$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, @@ -89,17 +89,18 @@ module ecc_scrubber_out #( ); logic scrub_req; + logic scrub_taginv; logic scrub_we; - logic [$clog2(DataDepth)-1:0] scrub_add; + logic [$clog2(DataDepth)-1:0]scrub_add; // logic [ DataWidth-1:0] scrub_wdata; - logic [ TagSramWidth-1:0] scrub_tag_rdata; + logic [ TagSramWidth-1:0] scrub_tag_rdata; logic [ DataWidth-1:0] scrub_data_rdata; - typedef enum logic [2:0] {Idle, Read, Check} scrub_state_e; + 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; // use data addr as it should be >= tag addr size, because the block number per index + 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; @@ -192,8 +193,8 @@ module ecc_scrubber_out #( assign scrub_add = working_add_q; - assign tag_bank_req_o = tag_intc_req_i || scrub_req; - assign tag_intc_gnt_o = tag_bank_gnt_i; + 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; @@ -214,7 +215,12 @@ module ecc_scrubber_out #( tag_bank_wdata_o = tag_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 + 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)]; @@ -251,40 +257,70 @@ module ecc_scrubber_out #( 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; - if (state_q == Idle) begin - // Switch to read state if triggered to scrub - if (scrub_trigger_i) begin - state_d = Read; + case (state_q) + Idle: begin + // Switch to read state if triggered to scrub + if (scrub_trigger_i) begin + state_d = Read; + end end - - end else if (state_q == 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; + 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 - - end else if (state_q == Check) begin - // Return to idle state - state_d = Idle; - working_add_d = (working_add_q + 1) % DataDepth; // increment address - - 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 + 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 @@ -300,7 +336,7 @@ module ecc_scrubber_out #( 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; From ee50d57b2518d9bd6973389be31ab15d1bb7b767 Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Wed, 10 Jul 2024 12:25:02 +0200 Subject: [PATCH 71/72] Fix the ECC reg address mapping. --- rtl/ecc_wrap/ECC.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rtl/ecc_wrap/ECC.h b/rtl/ecc_wrap/ECC.h index 4e112a5a..33567315 100644 --- a/rtl/ecc_wrap/ECC.h +++ b/rtl/ecc_wrap/ECC.h @@ -10,22 +10,22 @@ extern "C" { #define ECC_MANAGER_PARAM_REG_WIDTH 32 // Correctable mismatches caught by ecc on access -#define ECC_MANAGER_MISMATCH_COUNT_REG_OFFSET 0x100 +#define ECC_MANAGER_MISMATCH_COUNT_REG_OFFSET 0x0 // Interval between scrubs -#define ECC_MANAGER_SCRUB_INTERVAL_REG_OFFSET 0x104 +#define ECC_MANAGER_SCRUB_INTERVAL_REG_OFFSET 0x4 // Correctable mismatches caught by ecc on scrub -#define ECC_MANAGER_SCRUB_FIX_COUNT_REG_OFFSET 0x108 +#define ECC_MANAGER_SCRUB_FIX_COUNT_REG_OFFSET 0x8 // Uncorrectable mismatches caught by ecc on scrub -#define ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_REG_OFFSET 0x10c +#define ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_REG_OFFSET 0xc // Testing: Inverted write mask for data bits -#define ECC_MANAGER_WRITE_MASK_DATA_N_REG_OFFSET 0x110 +#define ECC_MANAGER_WRITE_MASK_DATA_N_REG_OFFSET 0x10 // Testing: Inverted write mask for ECC bits -#define ECC_MANAGER_WRITE_MASK_ECC_N_REG_OFFSET 0x114 +#define ECC_MANAGER_WRITE_MASK_ECC_N_REG_OFFSET 0x14 #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_MASK 0x7f #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_OFFSET 0 #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_FIELD \ From fce76115c6648ab764e8c4c34d9b1d1106b739f9 Mon Sep 17 00:00:00 2001 From: Zexin Fu Date: Thu, 18 Jul 2024 22:43:28 +0200 Subject: [PATCH 72/72] [RTL] Properly reset the FFs. --- rtl/ecc_wrap/ecc_scrubber_out.sv | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/rtl/ecc_wrap/ecc_scrubber_out.sv b/rtl/ecc_wrap/ecc_scrubber_out.sv index b4564153..513d378d 100644 --- a/rtl/ecc_wrap/ecc_scrubber_out.sv +++ b/rtl/ecc_wrap/ecc_scrubber_out.sv @@ -227,12 +227,24 @@ module ecc_scrubber_out #( end end - always_ff @(posedge clk_i) begin - if(tag_rwdata_en) begin - tag_bank_add_q <= tag_bank_add_o; + 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 - if(data_rwdata_en) begin - data_bank_add_q <= data_bank_add_o; + 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