├── .github ├── waiver.verible └── workflows │ └── ci.yml ├── .gitignore ├── .gitlab-ci.yml ├── Bender.yml ├── CHANGELOG.md ├── LICENSE.md ├── Makefile ├── README.md ├── include └── redundancy_cells │ └── voters.svh ├── requirements.txt ├── rtl ├── BUS_enc_dec │ ├── AXI_bus_ecc_dec.sv │ ├── AXI_bus_ecc_enc.sv │ ├── PE_XBAR_bus_ecc_dec.sv │ ├── PE_XBAR_bus_ecc_enc.sv │ ├── TCDM_XBAR_bus_ecc_dec.sv │ ├── TCDM_XBAR_bus_ecc_enc.sv │ ├── XBAR_DEMUX_BUS_ecc_dec.sv │ ├── XBAR_DEMUX_BUS_ecc_enc.sv │ ├── hci_core_intf_ecc_dec.sv │ ├── hci_core_intf_ecc_enc.sv │ ├── hci_mem_intf_ecc_dec.sv │ └── hci_mem_intf_ecc_enc.sv ├── ODRG_unit │ ├── ODRG.h │ ├── ODRG_unit.hjson │ ├── ODRG_unit.sv │ ├── doc.md │ ├── odrg_manager_reg_pkg.sv │ ├── odrg_manager_reg_top.sv │ └── triple_core_barrier.sv ├── TMR_voter.sv ├── TMR_voter_detect.sv ├── TMR_voter_fail.sv ├── TMR_word_voter.sv ├── bitwise_TMR_voter.sv ├── bitwise_TMR_voter_fail.sv ├── ecc_concat_32_64.sv ├── ecc_wrap │ ├── ECC.h │ ├── doc.md │ ├── ecc_manager.sv │ ├── ecc_manager_reg_pkg.sv │ ├── ecc_manager_reg_top.sv │ ├── ecc_scrubber.sv │ ├── ecc_sram.sv │ ├── ecc_sram_wrap.sv │ └── ecc_sram_wrapper.hjson ├── hsiao_ecc │ ├── hsiao_ecc_cor.sv │ ├── hsiao_ecc_dec.sv │ ├── hsiao_ecc_enc.sv │ └── hsiao_ecc_pkg.sv ├── lowrisc_ecc │ ├── prim_secded_13_8_cor.sv │ ├── prim_secded_13_8_dec.sv │ ├── prim_secded_13_8_enc.sv │ ├── prim_secded_22_16_cor.sv │ ├── prim_secded_22_16_dec.sv │ ├── prim_secded_22_16_enc.sv │ ├── prim_secded_28_22_cor.sv │ ├── prim_secded_28_22_dec.sv │ ├── prim_secded_28_22_enc.sv │ ├── prim_secded_39_32_cor.sv │ ├── prim_secded_39_32_dec.sv │ ├── prim_secded_39_32_enc.sv │ ├── prim_secded_64_57_cor.sv │ ├── prim_secded_64_57_dec.sv │ ├── prim_secded_64_57_enc.sv │ ├── prim_secded_72_64_cor.sv │ ├── prim_secded_72_64_dec.sv │ ├── prim_secded_72_64_enc.sv │ ├── prim_secded_hamming_22_16_cor.sv │ ├── prim_secded_hamming_22_16_dec.sv │ ├── prim_secded_hamming_22_16_enc.sv │ ├── prim_secded_hamming_39_32_cor.sv │ ├── prim_secded_hamming_39_32_dec.sv │ ├── prim_secded_hamming_39_32_enc.sv │ ├── prim_secded_hamming_72_64_cor.sv │ ├── prim_secded_hamming_72_64_dec.sv │ ├── prim_secded_hamming_72_64_enc.sv │ └── prim_secded_pkg.sv └── pulpissimo_tcls │ ├── TCLS.h │ ├── TCLS_unit.hjson │ ├── TCLS_unit.sv │ ├── doc.md │ ├── tcls_manager_reg_pkg.sv │ └── tcls_manager_reg_top.sv ├── run_tests.sh ├── src_files.yml ├── test ├── ecc_sram_fault_injection.tcl ├── tb_bitwise_tmr_voter.sv ├── tb_bitwise_tmr_voter_fail.sv ├── tb_ecc_scrubber.sv ├── tb_ecc_secded.sv ├── tb_ecc_sram.sv ├── tb_tmr_voter.sv ├── tb_tmr_voter_detect.sv ├── tb_tmr_voter_fail.sv ├── tb_tmr_word_voter.sv └── tb_voter_macros.sv └── util ├── lowrisc_opentitan └── util │ └── design │ ├── data │ └── secded_cfg.hjson │ └── secded_gen.py └── patches ├── lowrisc_data_dir └── 0001-edit-cfg.patch └── lowrisc_secded_gen ├── 0001-Add-Corrector-to-generation-script-and-update-testbe.patch ├── 0002-Update-SECDED-Encoder-modules-to-prevent-circular-de.patch └── 0003-secded-add-iterative-algorithm-for-secded-Hsiao-matr.patch /.github/waiver.verible: -------------------------------------------------------------------------------- 1 | # Copyright 2024 ETH Zurich and University of Bologna. 2 | # Solderpad Hardware License, Version 0.51, see LICENSE for details. 3 | # SPDX-License-Identifier: SHL-0.51 4 | 5 | waive --rule=explicit-parameter-storage-type --location="./rtl/ecc_wrap/ecc_sram.sv" 6 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 ETH Zurich and University of Bologna. 2 | # Solderpad Hardware License, Version 0.51, see LICENSE for details. 3 | # SPDX-License-Identifier: SHL-0.51 4 | 5 | # Author: Michael Rogenmoser 6 | 7 | name: ci 8 | 9 | on: 10 | push: 11 | branches: [ master ] 12 | pull_request: 13 | branches: [ master ] 14 | workflow_dispatch: 15 | 16 | jobs: 17 | check-stale: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | - uses: actions/setup-python@v4 22 | with: 23 | python-version: '3.9' 24 | cache: 'pip' 25 | - name: Install Bender 26 | run: make bender 27 | - name: Python Requirements 28 | run: pip install -r requirements.txt 29 | - name: Check clean make targets 30 | run: | 31 | make -B gen_ODRG gen_TCLS gen_ecc_registers gen_ECC 32 | git status && test -z "$(git status --porcelain)" 33 | lint-verilog: 34 | runs-on: ubuntu-latest 35 | needs: [check-stale] 36 | steps: 37 | - uses: actions/checkout@v3 38 | - uses: chipsalliance/verible-linter-action@main 39 | with: 40 | paths: | 41 | ./rtl 42 | exclude_paths: | 43 | ./test 44 | ./rtl/*/*_reg_pkg.sv 45 | ./rtl/*/*_reg_top.sv 46 | ./rtl/ecc_wrap/ecc_manager_2_reg_pkg.sv 47 | ./rtl/ecc_wrap/ecc_manager_2_reg_top.sv 48 | ./rtl/ecc_wrap/ecc_manager_8_reg_pkg.sv 49 | ./rtl/ecc_wrap/ecc_manager_8_reg_top.sv 50 | ./rtl/ecc_wrap/ecc_manager_reg_pkg.sv 51 | ./rtl/ecc_wrap/ecc_manager_reg_top.sv 52 | ./rtl/ODRG_unit/odrg_manager_reg_pkg.sv 53 | ./rtl/ODRG_unit/odrg_manager_reg_top.sv 54 | ./rtl/pulpissimo_tcls/tcls_manager_reg_pkg.sv 55 | ./rtl/pulpissimo_tcls/tcls_manager_reg_top.sv 56 | extra_args: "--rules=-interface-name-style --lint_fatal --parse_fatal --waiver_files .github/waiver.verible" 57 | github_token: ${{ secrets.GITHUB_TOKEN }} 58 | reviewdog_reporter: github-check 59 | gitlab-ci: 60 | runs-on: ubuntu-latest 61 | steps: 62 | - name: Mirror and check 63 | uses: pulp-platform/pulp-actions/gitlab-ci@v2 64 | # Skip on forks or pull requests from forks due to missing secrets. 65 | if: > 66 | github.repository == 'pulp-platform/redundancy_cells' && 67 | (github.event_name != 'pull_request' || 68 | github.event.pull_request.head.repo.full_name == github.repository) 69 | with: 70 | domain: iis-git.ee.ethz.ch 71 | repo: github-mirror/redundancy_cells 72 | token: ${{ secrets.GITLAB_TOKEN }} 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bender 2 | /Bender.lock 3 | /bender 4 | compile.tcl 5 | modelsim.ini 6 | /working_dir 7 | /work 8 | vsim.log 9 | vcom.log 10 | transcript 11 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 ETH Zurich and University of Bologna. 2 | # Solderpad Hardware License, Version 0.51, see LICENSE for details. 3 | # SPDX-License-Identifier: SHL-0.51 4 | 5 | # Author: Michael Rogenmoser 6 | 7 | stages: 8 | - test 9 | 10 | test: 11 | variables: 12 | VSIM: "questa-2023.4 vsim" 13 | stage: test 14 | script: ./run_tests.sh 15 | artifacts: 16 | paths: 17 | - vcom.log 18 | - vsim.log 19 | -------------------------------------------------------------------------------- /Bender.yml: -------------------------------------------------------------------------------- 1 | package: 2 | name: redundancy_cells 3 | authors: 4 | - "Michael Rogenmoser " 5 | 6 | dependencies: 7 | tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.13 } 8 | common_verification: { git: "https://github.com/pulp-platform/common_verification.git", version: 0.2.0 } 9 | register_interface: { git: "https://github.com/pulp-platform/register_interface.git", version: 0.4.4 } 10 | common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.35.0 } 11 | 12 | export_include_dirs: 13 | - include 14 | 15 | sources: 16 | # Source files grouped in levels. Files in level 0 have no dependencies on files in this 17 | # package. Files in level 1 only depend on files in level 0, files in level 2 on files in 18 | # levels 1 and 0, etc. Files within a level are ordered alphabetically. 19 | # Level 0 20 | - rtl/ODRG_unit/odrg_manager_reg_pkg.sv 21 | - rtl/ecc_wrap/ecc_manager_reg_pkg.sv 22 | - rtl/pulpissimo_tcls/tcls_manager_reg_pkg.sv 23 | - rtl/ODRG_unit/triple_core_barrier.sv 24 | - rtl/hsiao_ecc/hsiao_ecc_pkg.sv 25 | - rtl/hsiao_ecc/hsiao_ecc_enc.sv 26 | - rtl/hsiao_ecc/hsiao_ecc_dec.sv 27 | - rtl/hsiao_ecc/hsiao_ecc_cor.sv 28 | - rtl/TMR_voter.sv 29 | - rtl/TMR_voter_fail.sv 30 | - rtl/TMR_word_voter.sv 31 | # Level 1 32 | - rtl/ODRG_unit/odrg_manager_reg_top.sv 33 | - rtl/ecc_wrap/ecc_manager_reg_top.sv 34 | - rtl/pulpissimo_tcls/tcls_manager_reg_top.sv 35 | - rtl/ecc_wrap/ecc_scrubber.sv 36 | 37 | - target: any(deprecated, axi_ecc, hci_ecc, pulp_ecc, test) 38 | files: 39 | - rtl/ecc_concat_32_64.sv 40 | - rtl/lowrisc_ecc/prim_secded_pkg.sv 41 | - rtl/lowrisc_ecc/prim_secded_13_8_cor.sv 42 | - rtl/lowrisc_ecc/prim_secded_13_8_dec.sv 43 | - rtl/lowrisc_ecc/prim_secded_13_8_enc.sv 44 | - rtl/lowrisc_ecc/prim_secded_22_16_cor.sv 45 | - rtl/lowrisc_ecc/prim_secded_22_16_dec.sv 46 | - rtl/lowrisc_ecc/prim_secded_22_16_enc.sv 47 | - rtl/lowrisc_ecc/prim_secded_39_32_cor.sv 48 | - rtl/lowrisc_ecc/prim_secded_39_32_dec.sv 49 | - rtl/lowrisc_ecc/prim_secded_39_32_enc.sv 50 | - rtl/lowrisc_ecc/prim_secded_72_64_cor.sv 51 | - rtl/lowrisc_ecc/prim_secded_72_64_dec.sv 52 | - rtl/lowrisc_ecc/prim_secded_72_64_enc.sv 53 | 54 | - target: axi_ecc # custom ECC for PULP AXI IPs, make sure to include interface IPs when adding this target 55 | files: 56 | - rtl/BUS_enc_dec/AXI_bus_ecc_dec.sv 57 | - rtl/BUS_enc_dec/AXI_bus_ecc_enc.sv 58 | - target: hci_ecc # custom ECC for PULP HCI IPs, make sure to include interface IPs when adding this target 59 | files: 60 | - rtl/BUS_enc_dec/hci_core_intf_ecc_dec.sv 61 | - rtl/BUS_enc_dec/hci_core_intf_ecc_enc.sv 62 | - rtl/BUS_enc_dec/hci_mem_intf_ecc_dec.sv 63 | - rtl/BUS_enc_dec/hci_mem_intf_ecc_enc.sv 64 | - target: pulp_ecc # custom ECC for PULP (pulp_soc) interface IPs, make sure to include interface IPs when adding this target 65 | files: 66 | - rtl/BUS_enc_dec/PE_XBAR_bus_ecc_dec.sv 67 | - rtl/BUS_enc_dec/PE_XBAR_bus_ecc_enc.sv 68 | - rtl/BUS_enc_dec/TCDM_XBAR_bus_ecc_dec.sv 69 | - rtl/BUS_enc_dec/TCDM_XBAR_bus_ecc_enc.sv 70 | - rtl/BUS_enc_dec/XBAR_DEMUX_BUS_ecc_dec.sv 71 | - rtl/BUS_enc_dec/XBAR_DEMUX_BUS_ecc_enc.sv 72 | - rtl/TMR_voter_detect.sv 73 | # Level 2 74 | - rtl/bitwise_TMR_voter.sv 75 | - rtl/bitwise_TMR_voter_fail.sv 76 | - rtl/ecc_wrap/ecc_manager.sv 77 | - target: deprecated 78 | files: 79 | - rtl/ecc_wrap/ecc_sram_wrap.sv 80 | - rtl/ecc_wrap/ecc_sram.sv 81 | # Level 3 82 | - include_dirs: 83 | - rtl/ODRG_unit 84 | files: 85 | - rtl/ODRG_unit/ODRG_unit.sv 86 | - include_dirs: 87 | - rtl/pulpissimo_tcls 88 | files: 89 | - rtl/pulpissimo_tcls/TCLS_unit.sv 90 | - target: test 91 | files: 92 | - test/tb_ecc_scrubber.sv 93 | - test/tb_ecc_secded.sv 94 | - test/tb_ecc_sram.sv 95 | - test/tb_tmr_voter.sv 96 | - test/tb_tmr_voter_fail.sv 97 | - test/tb_tmr_voter_detect.sv 98 | - test/tb_tmr_word_voter.sv 99 | - test/tb_bitwise_tmr_voter.sv 100 | - test/tb_bitwise_tmr_voter_fail.sv 101 | - test/tb_voter_macros.sv 102 | 103 | vendor_package: 104 | - name: lowrisc_opentitan 105 | target_dir: "util/lowrisc_opentitan" 106 | upstream: { git: "https://github.com/lowRISC/opentitan.git", rev: "cfcfbce85e182c127b8c4be5cd8bf531e0a4d927" } 107 | patch_dir: "util/patches" 108 | mapping: 109 | - {from: 'util/design/secded_gen.py', to: 'util/design/secded_gen.py', patch_dir: 'lowrisc_secded_gen'} 110 | - {from: 'util/design/data/', to: 'util/design/data/', patch_dir: 'lowrisc_data_dir'} 111 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## Unreleased 8 | ### Added 9 | - Add ECC correctors 10 | 11 | ### Changed 12 | - Replace vendor.py script with bender vendor for ECC modules 13 | - Update `ecc_manager` for configurability 14 | - Update secded testbench to use correctors and fix error injection 15 | 16 | ## 0.5.1 - 2023-04-12 17 | ### Added 18 | - Add CI flow for linting 19 | 20 | ### Fixed 21 | - Fix ECC SRAM wrap 22 | 23 | ## 0.5.0 - 2022-12-21 24 | 25 | ### Added 26 | - Add `pulpissimo_tcls` permanently voted TCLS configuration 27 | - Add `ecc_manager` to log and errors 28 | - Add resynchronization to ODRG and TCLS 29 | - Expose additional error logging signals 30 | - Add scrubber to ECC SRAM wrap 31 | - Add testing signals for tapeout 32 | 33 | ### Changed 34 | - Expose `ecc_sram` ecc error signals 35 | - Rename cTCLS to ODRG 36 | - Hide bus ecc behind bender targets, remove related dependencies 37 | 38 | ## 0.4.0 - 2022-03-31 39 | 40 | ### Changed 41 | - Clean up interface of `cTCLS_unit` 42 | 43 | ## 0.3.0 - 2022-01-04 44 | 45 | ### Added 46 | - Add secded ECC for 64 bit datawidth 47 | - Add ECC encoder for XBAR_DEMUX_BUS 48 | - Add ECC encoder for AXI_BUS 49 | - Add cTCLS unit 50 | - Add initial ECC scrubber 51 | 52 | ### Changed 53 | - Updated `axi` version 54 | - Updated `hci` version 55 | - Updatad `register_interface` version and aligned to new reggen_tool format 56 | 57 | ## 0.2.0 - 2021-01-12 58 | 59 | ### Added 60 | - ECC encoder and decoder for XBAR_bus (PE, TCDM) 61 | - Added TMR majority voters 62 | 63 | ## 0.1.0 - 2020-12-30 64 | 65 | ### Added 66 | - lowrisc `secded_gen.py` script, along with generated modules for 8, 16, and 32 bit with minimum redundancy bits. 67 | - initial wrapper for sram to include ecc 68 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 ETH Zurich and University of Bologna 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | SHELL=bash 16 | 17 | BENDER ?= ./bender 18 | REG_PATH = $(shell $(BENDER) path register_interface) 19 | # use if you need to hardcode location of regtool 20 | # REG_PATH = ../register_interface 21 | REG_TOOL = $(REG_PATH)/vendor/lowrisc_opentitan/util/regtool.py 22 | 23 | HJSON_ODRG = rtl/ODRG_unit/ODRG_unit.hjson 24 | HJSON_TCLS = rtl/pulpissimo_tcls/TCLS_unit.hjson 25 | HJSON_ECC = rtl/ecc_wrap/ecc_sram_wrapper.hjson 26 | 27 | TARGET_DIR_ODRG = rtl/ODRG_unit 28 | TARGET_DIR_TCLS = rtl/pulpissimo_tcls 29 | TARGET_DIR_ECC = rtl/ecc_wrap 30 | 31 | .PHONY: gen_ODRG gen_TCLS gen_ecc_registers gen_ECC 32 | gen_ODRG: 33 | python $(REG_TOOL) $(HJSON_ODRG) -t $(TARGET_DIR_ODRG) -r 34 | python $(REG_TOOL) $(HJSON_ODRG) -d > $(TARGET_DIR_ODRG)/doc.md 35 | python $(REG_TOOL) $(HJSON_ODRG) -D > $(TARGET_DIR_ODRG)/ODRG.h 36 | 37 | gen_TCLS: 38 | python $(REG_TOOL) $(HJSON_TCLS) -t $(TARGET_DIR_TCLS) -r 39 | python $(REG_TOOL) $(HJSON_TCLS) -d > $(TARGET_DIR_TCLS)/doc.md 40 | python $(REG_TOOL) $(HJSON_TCLS) -D > $(TARGET_DIR_TCLS)/TCLS.h 41 | 42 | gen_ecc_registers: 43 | python $(REG_TOOL) $(HJSON_ECC) -t $(TARGET_DIR_ECC) -r 44 | python $(REG_TOOL) $(HJSON_ECC) -d > $(TARGET_DIR_ECC)/doc.md 45 | python $(REG_TOOL) $(HJSON_ECC) -D > $(TARGET_DIR_ECC)/ECC.h 46 | 47 | gen_ECC: 48 | $(BENDER) vendor init 49 | cd util/lowrisc_opentitan && ./util/design/secded_gen.py --no_fpv --outdir ../../rtl/lowrisc_ecc 50 | 51 | bender: 52 | ifeq (,$(wildcard ./bender)) 53 | curl --proto '=https' --tlsv1.2 -sSf https://pulp-platform.github.io/bender/init \ 54 | | bash -s -- 0.27.1 55 | touch bender 56 | endif 57 | 58 | .PHONY: bender-rm 59 | bender-rm: 60 | rm -f bender 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redundancy Cells 2 | 3 | This repository contains various modules used to add redundancy. 4 | 5 | ## On-Demand Redundancy Grouping (ODRG_unit) 6 | The `ODRG_unit` is designed as a configurable bridge between three ibex cores, allowing for independent operation or lock-step operation with majority voting, triggering an interrupt in case a mismatch is detected. It uses lowrisc's reggen tool to generate the required configuration registers. 7 | 8 | ### Testing 9 | ODRG is integrated in the [PULP cluster](https://github.com/pulp-platform/pulp_cluster/tree/space_pulp) and the [PULP](https://github.com/pulp-platform/pulp/tree/space_pulp) system. To test, please use the `space_pulp` branch. 10 | 11 | ### Citing 12 | If you are using ODRG in your academic work you can cite us: 13 | ```BibTeX 14 | @INPROCEEDINGS{9912026, 15 | author={Rogenmoser, Michael and Wistoff, Nils and Vogel, Pirmin and Gürkaynak, Frank and Benini, Luca}, 16 | booktitle={2022 IEEE Computer Society Annual Symposium on VLSI (ISVLSI)}, 17 | title={On-Demand Redundancy Grouping: Selectable Soft-Error Tolerance for a Multicore Cluster}, 18 | year={2022}, 19 | volume={}, 20 | number={}, 21 | pages={398-401}, 22 | doi={10.1109/ISVLSI54635.2022.00089} 23 | } 24 | ``` 25 | 26 | ### Maintenance 27 | 28 | To re-generate regfile, run following command in the root directory of this repo. 29 | ```bash 30 | make gen_ODRG 31 | ``` 32 | This will generate the register file SV-code, its corresponding C-code and documentation using lowrisc's reggen tool via the pulp register-interface repository. 33 | 34 | ## ECC encoders and decoders 35 | The hsiao_ecc encoder, decoder, and corrector are based on lowRISC's Hsiao ECC implementation, with an adapted algorithm to deterministically find an appropriate Hsiao matrix. They are implemented in SystemVerilog for efficient parametrization, replacing the generated lowRISC modules. 36 | 37 | The lowRISC ECC encoders and decoders are imported using [`bender`'s `vendor` command](https://github.com/pulp-platform/bender#vendor-----copy-files-from-dependencies-that-do-not-support-bender). To re-import and re-generate the `prim_secded_` modules run 38 | ```bash 39 | make gen_ECC 40 | ``` 41 | 42 | ## ECC wrapper for SRAM 43 | `ecc_sram_wrap.sv` is a wrapper for the tc_sram tech_cell to add ecc in a customizable fashion. It interfaces a modified `TCDM_BANK_MEM_BUS.Slave` defined in pulp_soc with the memory, implementing a load-and-store architecture for writes where not the full word is written. As this requires an additional cycle, a gnt signal is exposed, delaying the subsequent transaction if necessary. 44 | 45 | ## ECC scrubber 46 | `ecc_scrubber.sv` is a scrubber unit to attach to an ecc-protected memory bank. When triggered, read the next address to detect if a fault has occurred, correcting it if required and logging the number of corrections. It will always give way to other memory accesses and stall to avoid increased latency. 47 | 48 | ## ECC translators for data bus interfaces 49 | The `BUS_enc_dec` encoders and decoders add or remove ECC to the parametrized `XBAR_TCDM_BUS`, `XBAR_PE_BUS`, and `XBAR_DEMUX_BUS`, defined in [pulp_interfaces.sv](https://github.com/micprog/pulp_soc/blob/ibex_update/rtl/components/pulp_interfaces.sv), as well as [`AXI_BUS`](https://github.com/pulp-platform/axi). 50 | 51 | The `DropECC` parameter allows for a faster signal along the decode data path, not correcting the errors but still calculating if an error exists. 52 | 53 | ## Triple Modular Redundancy majority voters 54 | The `TMR_voter`s are Triple Modular Redundancy majority voters, based on research indicated in the corresponding files. To detect the failing module, additional signals are implemented in higher-level modules. 55 | 56 | ## Voting Macros 57 | For quickly instantiating voters, the following macros might be useful. They can be used via bender with: 58 | ``` 59 | `include "redundancy_cells/voters.svh" 60 | ``` 61 | All Macros use the following naming scheme: 62 | `VOTE{Inputs}{Outputs}{Flags}` 63 | 64 | - For size `1` outputs can be arbitrarily sized arrays (denoted as size `[K:0]` below), 65 | - For size `3` inputs and outputs should be arrays of length 3 at the top level which at lower levels can again be arbitrarily (`K`) sized. 66 | - The size `X` allows for a parameter to determine how many duplicates are used, which allows to make designs which have compile-time switchable redundancy. 67 | The parameter should have a value of 1 (no redundancy), 2 (fault detection) or 3 (fault correction). 68 | 69 | Available Flags are: 70 | - `F` Fault Detection: Additional 1-bit output signal which is one if voting was not unanimous 71 | - `W` Fault Location: Additional 3-bit output signal which specifies which input was different and 1-bit signal if all bits where different 72 | 73 | Voters work with enumerated types, but there is no guarantee when multiple faults occur at once that the output is a valid enum entry. 74 | Enumerated types that consist of a single bit are not supported. 75 | 76 | All availabe voters are: 77 | 78 | | Macro | Arguments | Description | 79 | |------------|-----------------------------------------------------------------------------------|--------------------------------------------------| 80 | | `VOTE31` | `input_signal[2:0][K:0], output_signal[K:0]` | 3 -> 1 Voter | 81 | | `VOTE31F` | `input_signal[2:0][K:0], output_signal[K:0], fault_any` | 3 -> 1 Voter with fault detection | 82 | | `VOTE31W` | `input_signal[2:0][K:0], output_signal[K:0], fault_210[2:0], fault_multiple` | 3 -> 1 Voter with fault location | 83 | | `VOTE33` | `input_signal[2:0][K:0], output_signal[2:0][K:0]` | 3 -> 3 Voters | 84 | | `VOTE33F` | `input_signal[2:0][K:0], output_signal[2:0][K:0], fault_any` | 3 -> 3 Voters with fault detection | 85 | | `VOTE33W` | `input_signal[2:0][K:0], output_signal[2:0][K:0], fault_210[2:0], fault_multiple` | 3 -> 3 Voters with fault location | 86 | | `VOTEX1` | `replicas, input_signal[REP:0][K:0], output_signal[K:0]` | replicas -> 1 Voter | 87 | | `VOTEX1F` | `replicas, input_signal[REP:0][K:0], output_signal[K:0], fault_any` | replicas -> 1 Voter with fault detection | 88 | | `VOTEXX` | `replicas, input_signal[REP:0][K:0], output_signal[REP:0][K:0]` | replicas -> replicas Voters | 89 | | `VOTEXXF` | `replicas, input_signal[REP:0][K:0], output_signal[REP:0][K:0], fault_any` | replicas -> replicas Voters with fault detection | 90 | 91 | ## Testing 92 | To run tests, execute the following command: 93 | ```bash 94 | ./run_tests.sh 95 | ``` 96 | 97 | A bender installation >=v0.27 is required. 98 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | hjson 2 | mako 3 | pyyaml 4 | tabulate 5 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/AXI_bus_ecc_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Removes SECDED ECC from AXI_BUS 12 | 13 | module AXI_bus_ecc_dec #( 14 | parameter bit DropECC = 0, 15 | parameter int unsigned AxiAddrWidth = 0, // irrelevant here 16 | parameter int unsigned AxiDataWidth = 32, // currently only 32 or 64 bit supported 17 | parameter int unsigned AxiIdWidth = 0, // irrelevant here 18 | parameter int unsigned AxiUserWidth = 1, // USER width excluding ECC bits 19 | localparam int unsigned NbEccBits = ( AxiDataWidth == 32 ) ? 7 : 8 // 7bit for DW=32 20 | // 8bit for DW=64 21 | ) ( 22 | AXI_BUS.Slave bus_in, // data_width=AXI_DW, user_width+=NbEccBits 23 | AXI_BUS.Master bus_out, // data_width=AXI_DW 24 | output logic [NbEccBits-1:0] syndrome_o, 25 | output logic [ 1:0] err_o 26 | ); 27 | // ECC is added to the higher bits of USER signals, calculated from data bits. 28 | // No management of failed ECC correction is done here. 29 | `ifndef TARGET_SYNTHESIS 30 | if (bus_in.AXI_USER_WIDTH != bus_out.AXI_USER_WIDTH+NbEccBits) 31 | $fatal(1, "Ensure bus_in AXI_USER_WIDTH"); 32 | `endif 33 | 34 | logic [AxiDataWidth-1:0] data_corrected; 35 | 36 | localparam int unsigned EccUserWidth = AxiUserWidth + NbEccBits; 37 | 38 | assign bus_out.aw_id = bus_in.aw_id; 39 | assign bus_out.aw_addr = bus_in.aw_addr; 40 | assign bus_out.aw_len = bus_in.aw_len; 41 | assign bus_out.aw_size = bus_in.aw_size; 42 | assign bus_out.aw_burst = bus_in.aw_burst; 43 | assign bus_out.aw_lock = bus_in.aw_lock; 44 | assign bus_out.aw_cache = bus_in.aw_cache; 45 | assign bus_out.aw_prot = bus_in.aw_prot; 46 | assign bus_out.aw_qos = bus_in.aw_qos; 47 | assign bus_out.aw_region = bus_in.aw_region; 48 | assign bus_out.aw_atop = bus_in.aw_atop; 49 | assign bus_out.aw_user = bus_in.aw_user[AxiUserWidth-1:0]; 50 | assign bus_out.aw_valid = bus_in.aw_valid; 51 | assign bus_in.aw_ready = bus_out.aw_ready; 52 | 53 | 54 | if (DropECC) begin : gen_drop_ecc 55 | assign bus_out.w_data = bus_in.w_data; 56 | end else begin : gen_full_ecc 57 | assign bus_out.wdata = data_corrected; // remove ECC below 58 | end 59 | assign bus_out.w_strb = bus_in.w_strb; 60 | assign bus_out.w_last = bus_in.w_last; 61 | assign bus_out.w_user = bus_in.w_user[AxiUserWidth-1:0]; // remove ECC below 62 | assign bus_out.w_valid = bus_in.w_valid; 63 | assign bus_in.w_ready = bus_out.w_ready; 64 | 65 | assign bus_in.b_id = bus_out.b_id; 66 | assign bus_in.b_resp = bus_out.b_resp; 67 | assign bus_in.b_user = { {NbEccBits{1'b0}}, bus_out.b_user }; 68 | assign bus_in.b_valid = bus_out.b_valid; 69 | assign bus_out.b_ready = bus_in.b_ready; 70 | 71 | assign bus_out.ar_id = bus_in.ar_id; 72 | assign bus_out.ar_addr = bus_in.ar_addr; 73 | assign bus_out.ar_len = bus_in.ar_len; 74 | assign bus_out.ar_size = bus_in.ar_size; 75 | assign bus_out.ar_burst = bus_in.ar_burst; 76 | assign bus_out.ar_lock = bus_in.ar_lock; 77 | assign bus_out.ar_cache = bus_in.ar_cache; 78 | assign bus_out.ar_prot = bus_in.ar_prot; 79 | assign bus_out.ar_qos = bus_in.ar_qos; 80 | assign bus_out.ar_region = bus_in.ar_region; 81 | assign bus_out.ar_user = bus_in.ar_user[AxiUserWidth-1:0]; 82 | assign bus_out.ar_valid = bus_in.ar_valid; 83 | assign bus_in.ar_ready = bus_out.ar_ready; 84 | 85 | assign bus_in.r_id = bus_out.r_id; 86 | // assign bus_in.r_data = bus_out.r_data; // add ECC below 87 | assign bus_in.r_resp = bus_out.r_resp; 88 | assign bus_in.r_last = bus_out.r_last; 89 | assign bus_in.r_user[AxiUserWidth-1:0] = bus_out.r_user[AxiUserWidth-1:0]; // add ECC below 90 | assign bus_in.r_valid = bus_out.r_valid; 91 | assign bus_out.r_ready = bus_in.r_ready; 92 | 93 | if (AxiDataWidth == 32) begin : gen_DW32 94 | prim_secded_39_32_enc ecc_encode ( 95 | .in ( bus_out.r_data ), 96 | .out ( {bus_in.r_user[EccUserWidth-1:AxiUserWidth], bus_in.r_data} ) 97 | ); 98 | 99 | prim_secded_39_32_dec ecc_decode ( 100 | .in ( {bus_in.w_user[EccUserWidth-1:AxiUserWidth], bus_in.w_data} ), 101 | .d_o ( data_corrected ), 102 | .syndrome_o ( syndrome_o ), 103 | .err_o ( err_o ) 104 | ); 105 | end else if (AxiDataWidth == 64) begin : gen_DW64 106 | prim_secded_72_64_enc ecc_encode ( 107 | .in ( bus_out.r_data ), 108 | .out ( {bus_in.r_user[EccUserWidth-1:AxiUserWidth], bus_in.r_data} ) 109 | ); 110 | 111 | prim_secded_72_64_dec ecc_decode ( 112 | .in ( {bus_in.w_user[EccUserWidth-1:AxiUserWidth], bus_in.w_data} ), 113 | .d_o ( data_corrected ), 114 | .syndrome_o ( syndrome_o ), 115 | .err_o ( err_o ) 116 | ); 117 | end else begin : gen_err 118 | $fatal(1, "please choose appropriate AxiDataWidth or update the code."); 119 | end 120 | 121 | endmodule 122 | 123 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/AXI_bus_ecc_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Adds SECDED ECC to AXI_BUS 12 | 13 | module AXI_bus_ecc_enc #( 14 | parameter bit DropECC = 0, 15 | parameter int unsigned AxiAddrWidth = 0, // irrelevant here 16 | parameter int unsigned AxiDataWidth = 32, // currently only 32 or 64 bit supported 17 | parameter int unsigned AxiIdWidth = 0, // irrelevant here 18 | parameter int unsigned AxiUserWidth = 1, // USER width excluding ECC bits 19 | localparam int unsigned NbEccBits = ( AxiDataWidth == 32 ) ? 7 : 8 // 7bit for DW=32 20 | // 8bit for DW=64 21 | ) ( 22 | AXI_BUS.Slave bus_in, // data_width=32 23 | AXI_BUS.Master bus_out, // data_width=32, user_width+=NbEccBits 24 | output logic [NbEccBits-1:0] syndrome_o, 25 | output logic [ 1:0] err_o 26 | ); 27 | // ECC is added to the higher bits of USER signals, calculated from data bits. 28 | // No management of failed ECC correction is done here. 29 | `ifndef TARGET_SYNTHESIS 30 | if (bus_out.AXI_USER_WIDTH != bus_in.AXI_USER_WIDTH+NbEccBits) 31 | $fatal(1, "Ensure bus_out AXI_USER_WIDTH"); 32 | `endif 33 | 34 | logic [AxiDataWidth-1:0] data_corrected; 35 | 36 | localparam int unsigned EccUserWidth = AxiUserWidth + NbEccBits; 37 | 38 | assign bus_out.aw_id = bus_in.aw_id; 39 | assign bus_out.aw_addr = bus_in.aw_addr; 40 | assign bus_out.aw_len = bus_in.aw_len; 41 | assign bus_out.aw_size = bus_in.aw_size; 42 | assign bus_out.aw_burst = bus_in.aw_burst; 43 | assign bus_out.aw_lock = bus_in.aw_lock; 44 | assign bus_out.aw_cache = bus_in.aw_cache; 45 | assign bus_out.aw_prot = bus_in.aw_prot; 46 | assign bus_out.aw_qos = bus_in.aw_qos; 47 | assign bus_out.aw_region = bus_in.aw_region; 48 | assign bus_out.aw_atop = bus_in.aw_atop; 49 | assign bus_out.aw_user = { {NbEccBits{1'b0}}, bus_in.aw_user }; 50 | assign bus_out.aw_valid = bus_in.aw_valid; 51 | assign bus_in.aw_ready = bus_out.aw_ready; 52 | 53 | // assign bus_out.w_data = bus_in.w_data; // add ECC below 54 | assign bus_out.w_strb = bus_in.w_strb; 55 | assign bus_out.w_last = bus_in.w_last; 56 | assign bus_out.w_user[AxiUserWidth-1:0] = bus_in.w_user; // add ECC below 57 | assign bus_out.w_valid = bus_in.w_valid; 58 | assign bus_in.w_ready = bus_out.w_ready; 59 | 60 | assign bus_in.b_id = bus_out.b_id; 61 | assign bus_in.b_resp = bus_out.b_resp; 62 | assign bus_in.b_user = bus_out.b_user[AxiUserWidth-1:0]; 63 | assign bus_in.b_valid = bus_out.b_valid; 64 | assign bus_out.b_ready = bus_in.b_ready; 65 | 66 | assign bus_out.ar_id = bus_in.ar_id; 67 | assign bus_out.ar_addr = bus_in.ar_addr; 68 | assign bus_out.ar_len = bus_in.ar_len; 69 | assign bus_out.ar_size = bus_in.ar_size; 70 | assign bus_out.ar_burst = bus_in.ar_burst; 71 | assign bus_out.ar_lock = bus_in.ar_lock; 72 | assign bus_out.ar_cache = bus_in.ar_cache; 73 | assign bus_out.ar_prot = bus_in.ar_prot; 74 | assign bus_out.ar_qos = bus_in.ar_qos; 75 | assign bus_out.ar_region = bus_in.ar_region; 76 | assign bus_out.ar_user = { {NbEccBits{1'b0}}, bus_in.ar_user }; 77 | assign bus_out.ar_valid = bus_in.ar_valid; 78 | assign bus_in.ar_ready = bus_out.ar_ready; 79 | 80 | assign bus_in.r_id = bus_out.r_id; 81 | if (DropECC) begin : gen_drop_ecc 82 | assign bus_in.r_data = bus_out.r_data; 83 | end else begin : gen_full_ecc 84 | assign bus_in.r_data = data_corrected; // remove ECC below 85 | end 86 | assign bus_in.r_resp = bus_out.r_resp; 87 | assign bus_in.r_last = bus_out.r_last; 88 | assign bus_in.r_user = bus_out.r_user[AxiUserWidth-1:0]; // remove ECC below 89 | assign bus_in.r_valid = bus_out.r_valid; 90 | assign bus_out.r_ready = bus_in.r_ready; 91 | 92 | if (AxiDataWidth == 32) begin : gen_DW32 93 | prim_secded_39_32_enc ecc_encode ( 94 | .in ( bus_in.w_data ), 95 | .out ( {bus_out.w_user[EccUserWidth-1:AxiUserWidth], bus_out.w_data} ) 96 | ); 97 | 98 | prim_secded_39_32_dec ecc_decode ( 99 | .in ( {bus_out.r_user[EccUserWidth-1:AxiUserWidth], bus_out.r_data} ), 100 | .d_o ( data_corrected ), 101 | .syndrome_o ( syndrome_o ), 102 | .err_o ( err_o ) 103 | ); 104 | end else if (AxiDataWidth == 64) begin : gen_DW64 105 | prim_secded_72_64_enc ecc_encode ( 106 | .in ( bus_in.w_data ), 107 | .out ( {bus_out.w_user[EccUserWidth-1:AxiUserWidth], bus_out.w_data} ) 108 | ); 109 | 110 | prim_secded_72_64_dec ecc_decode ( 111 | .in ( {bus_out.r_user[EccUserWidth-1:AxiUserWidth], bus_out.r_data} ), 112 | .d_o ( data_corrected ), 113 | .syndrome_o ( syndrome_o ), 114 | .err_o ( err_o ) 115 | ); 116 | end else begin : gen_err 117 | $fatal(1, "please choose appropriate AxiDataWidth or update the code."); 118 | end 119 | 120 | 121 | endmodule 122 | 123 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/PE_XBAR_bus_ecc_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Removes SECDED ECC from PE_XBAR_BUS 12 | 13 | module PE_XBAR_bus_ecc_dec #( 14 | parameter bit DropECC = 0, 15 | localparam int unsigned DataWidth = 32 // Currently will only work for 32 16 | ) ( 17 | XBAR_PERIPH_BUS.Slave bus_in, // DATA_WIDTH=39 18 | XBAR_PERIPH_BUS.Master bus_out, // DATA_WIDTH=32 19 | output logic [ 6:0] syndrome_o, 20 | output logic [ 1:0] err_o 21 | ); 22 | `ifndef TARGET_SYNTHESIS 23 | if (bus_in.DATA_WIDTH != 39) $fatal(1, "Ensure bus_in DATA_WIDTH"); 24 | if (bus_out.DATA_WIDTH != 32) $fatal(1, "Ensure bus_out DATA_WIDTH"); 25 | `endif 26 | 27 | logic [DataWidth-1:0] data_corrected; 28 | 29 | assign bus_out.req = bus_in.req; 30 | assign bus_out.add = bus_in.add; 31 | assign bus_out.wen = bus_in.wen; 32 | assign bus_out.be = bus_in.be; 33 | assign bus_out.id = bus_in.id; 34 | if (DropECC) begin : gen_drop_ecc 35 | assign bus_out.wdata = bus_in.wdata[DataWidth-1:0]; 36 | end else begin : gen_full_ecc 37 | assign bus_out.wdata = data_corrected; // remove ECC below 38 | end 39 | 40 | assign bus_in.gnt = bus_out.gnt; 41 | assign bus_in.r_opc = bus_out.r_opc; 42 | assign bus_in.r_valid = bus_out.r_valid; 43 | assign bus_in.r_id = bus_out.r_id; 44 | 45 | prim_secded_39_32_enc ecc_encode ( 46 | .in ( bus_out.r_rdata ), 47 | .out ( bus_in.r_rdata ) 48 | ); 49 | 50 | prim_secded_39_32_dec ecc_decode ( 51 | .in ( bus_in.wdata ), 52 | .d_o ( data_corrected ), 53 | .syndrome_o ( syndrome_o ), 54 | .err_o ( err_o ) 55 | ); 56 | 57 | endmodule 58 | 59 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/PE_XBAR_bus_ecc_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Adds SECDED ECC to PE_XBAR_BUS 12 | 13 | module PE_XBAR_bus_ecc_enc #( 14 | parameter bit DropECC = 0, 15 | localparam int unsigned DataWidth = 32 // Currently will only work for 32 16 | ) ( 17 | XBAR_PERIPH_BUS.Slave bus_in, // DATA_WIDTH=32 18 | XBAR_PERIPH_BUS.Master bus_out, // DATA_WIDTH=39 19 | output logic [ 6:0] syndrome_o, 20 | output logic [ 1:0] err_o 21 | ); 22 | `ifndef TARGET_SYNTHESIS 23 | if (bus_in.DATA_WIDTH != 32) $fatal(1, "Ensure bus_in DATA_WIDTH"); 24 | if (bus_out.DATA_WIDTH != 39) $fatal(1, "Ensure bus_out DATA_WIDTH"); 25 | `endif 26 | 27 | logic [DataWidth-1:0] data_corrected; 28 | 29 | assign bus_out.req = bus_in.req; 30 | assign bus_out.add = bus_in.add; 31 | assign bus_out.wen = bus_in.wen; 32 | assign bus_out.be = bus_in.be; 33 | assign bus_out.id = bus_in.id; 34 | 35 | assign bus_in.gnt = bus_out.gnt; 36 | assign bus_in.r_opc = bus_out.r_opc; 37 | assign bus_in.r_valid = bus_out.r_valid; 38 | assign bus_in.r_id = bus_out.r_id; 39 | if (DropECC) begin : gen_drop_ecc 40 | assign bus_in.r_rdata = bus_out.r_rdata[DataWidth-1:0]; 41 | end else begin : gen_full_ecc 42 | assign bus_in.r_rdata = data_corrected; // remove ECC below 43 | end 44 | 45 | prim_secded_39_32_enc ecc_encode ( 46 | .in ( bus_in.wdata ), 47 | .out ( bus_out.wdata ) 48 | ); 49 | 50 | prim_secded_39_32_dec ecc_decode ( 51 | .in ( bus_out.r_rdata ), 52 | .d_o ( data_corrected ), 53 | .syndrome_o ( syndrome_o ), 54 | .err_o ( err_o ) 55 | ); 56 | 57 | endmodule 58 | 59 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/TCDM_XBAR_bus_ecc_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Removes SECDED ECC from TCDM_XBAR_BUS 12 | 13 | module TCDM_XBAR_bus_ecc_dec #( 14 | parameter bit DropECC = 0, 15 | localparam int unsigned DataWidth = 32 // Currently will only work for 32 16 | ) ( 17 | XBAR_TCDM_BUS.Slave bus_in, // DATA_WIDTH=39 18 | XBAR_TCDM_BUS.Master bus_out, // DATA_WIDTH=32 19 | output logic [ 6:0] syndrome_o, 20 | output logic [ 1:0] err_o 21 | ); 22 | `ifndef TARGET_SYNTHESIS 23 | if (bus_in.DATA_WIDTH != 39) $fatal(1, "Ensure bus_in DATA_WIDTH"); 24 | if (bus_out.DATA_WIDTH != 32) $fatal(1, "Ensure bus_out DATA_WIDTH"); 25 | `endif 26 | 27 | logic [DataWidth-1:0] data_corrected; 28 | 29 | assign bus_out.req = bus_in.req; 30 | assign bus_out.add = bus_in.add; 31 | assign bus_out.wen = bus_in.wen; 32 | assign bus_out.be = bus_in.be; 33 | if (DropECC) begin : gen_drop_ecc 34 | assign bus_out.wdata = bus_in.wdata[DataWidth-1:0]; 35 | end else begin : gen_full_ecc 36 | assign bus_out.wdata = data_corrected; // remove ECC below 37 | end 38 | 39 | assign bus_in.gnt = bus_out.gnt; 40 | assign bus_in.r_opc = bus_out.r_opc; 41 | assign bus_in.r_valid = bus_out.r_valid; 42 | 43 | prim_secded_39_32_enc ecc_encode ( 44 | .in ( bus_out.r_rdata ), 45 | .out ( bus_in.r_rdata ) 46 | ); 47 | 48 | prim_secded_39_32_dec ecc_decode ( 49 | .in ( bus_in.wdata ), 50 | .d_o ( data_corrected ), 51 | .syndrome_o ( syndrome_o ), 52 | .err_o ( err_o ) 53 | ); 54 | 55 | endmodule 56 | 57 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/TCDM_XBAR_bus_ecc_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Adds SECDED ECC to TCDM_XBAR_BUS 12 | 13 | module TCDM_XBAR_bus_ecc_enc #( 14 | parameter bit DropECC = 0, 15 | localparam int unsigned DataWidth = 32 // Currently will only work for 32 16 | ) ( 17 | XBAR_TCDM_BUS.Slave bus_in, // DATA_WIDTH=32 18 | XBAR_TCDM_BUS.Master bus_out, // DATA_WIDTH=39 19 | output logic [ 6:0] syndrome_o, 20 | output logic [ 1:0] err_o 21 | ); 22 | `ifndef TARGET_SYNTHESIS 23 | if (bus_in.DATA_WIDTH != 32) $fatal(1, "Ensure bus_in DATA_WIDTH"); 24 | if (bus_out.DATA_WIDTH != 39) $fatal(1, "Ensure bus_out DATA_WIDTH"); 25 | `endif 26 | 27 | logic [DataWidth-1:0] data_corrected; 28 | 29 | assign bus_out.req = bus_in.req; 30 | assign bus_out.add = bus_in.add; 31 | assign bus_out.wen = bus_in.wen; 32 | assign bus_out.be = bus_in.be; 33 | 34 | assign bus_in.gnt = bus_out.gnt; 35 | assign bus_in.r_opc = bus_out.r_opc; 36 | assign bus_in.r_valid = bus_out.r_valid; 37 | if (DropECC) begin : gen_drop_ecc 38 | assign bus_in.r_rdata = bus_out.r_rdata[DataWidth-1:0]; 39 | end else begin : gen_full_ecc 40 | assign bus_in.r_rdata = data_corrected; // remove ECC below 41 | end 42 | 43 | prim_secded_39_32_enc ecc_encode ( 44 | .in ( bus_in.wdata ), 45 | .out ( bus_out.wdata ) 46 | ); 47 | 48 | prim_secded_39_32_dec ecc_decode ( 49 | .in ( bus_out.r_rdata ), 50 | .d_o ( data_corrected ), 51 | .syndrome_o ( syndrome_o ), 52 | .err_o ( err_o ) 53 | ); 54 | 55 | endmodule 56 | 57 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/XBAR_DEMUX_BUS_ecc_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Adds SECDED ECC to XBAR_DEMUX_BUS 12 | 13 | module XBAR_DEMUX_BUS_ecc_dec #( 14 | parameter bit DropECC = 0, 15 | localparam int unsigned DataWidth = 32 // Currently will only work for 32 16 | ) ( 17 | XBAR_DEMUX_BUS.Slave bus_in, // DATA_WIDTH=39 18 | XBAR_DEMUX_BUS.Master bus_out, // DATA_WIDTH=32 19 | output logic [ 6:0] syndrome_o, 20 | output logic [ 1:0] err_o 21 | ); 22 | `ifndef TARGET_SYNTHESIS 23 | if (bus_in.DATA_WIDTH != 39) $fatal(1, "Ensure bus_in DATA_WIDTH"); 24 | if (bus_out.DATA_WIDTH != 32) $fatal(1, "Ensure bus_out DATA_WIDTH"); 25 | `endif 26 | 27 | logic [DataWidth-1:0] data_corrected; 28 | 29 | assign bus_out.barrier = bus_in.barrier; 30 | assign bus_out.exec_cancel = bus_in.exec_cancel; 31 | assign bus_out.exec_stall = bus_in.exec_stall; 32 | assign bus_out.req = bus_in.req; 33 | assign bus_out.add = bus_in.add; 34 | assign bus_out.we = bus_in.we; 35 | assign bus_out.be = bus_in.be; 36 | assign bus_out.r_gnt = bus_in.r_gnt; 37 | if (DropECC) begin : gen_drop_ecc 38 | assign bus_out.wdata = bus_in.wdata[DataWidth-1:0]; 39 | end else begin : gen_full_ecc 40 | assign bus_out.wdata = data_corrected; // remove ECC below 41 | end 42 | 43 | assign bus_in.busy = bus_out.busy; 44 | assign bus_in.gnt = bus_out.gnt; 45 | assign bus_in.r_valid = bus_out.r_valid; 46 | 47 | prim_secded_39_32_enc ecc_encode ( 48 | .in ( bus_out.r_rdata ), 49 | .out ( bus_in.r_rdata ) 50 | ); 51 | 52 | prim_secded_39_32_dec ecc_decode ( 53 | .in ( bus_in.wdata ), 54 | .d_o ( data_corrected ), 55 | .syndrome_o ( syndrome_o ), 56 | .err_o ( err_o ) 57 | ); 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/XBAR_DEMUX_BUS_ecc_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Adds SECDED ECC to XBAR_DEMUX_BUS 12 | 13 | module XBAR_DEMUX_BUS_ecc_enc #( 14 | parameter bit DropECC = 0, 15 | localparam int unsigned DataWidth = 32 // Currently will only work for 32 16 | ) ( 17 | XBAR_DEMUX_BUS.Slave bus_in, // DATA_WIDTH=32 18 | XBAR_DEMUX_BUS.Master bus_out, // DATA_WIDTH=39 19 | output logic [ 6:0] syndrome_o, 20 | output logic [ 1:0] err_o 21 | ); 22 | `ifndef TARGET_SYNTHESIS 23 | if (bus_in.DATA_WIDTH != 32) $fatal(1, "Ensure bus_in DATA_WIDTH"); 24 | if (bus_out.DATA_WIDTH != 39) $fatal(1, "Ensure bus_out DATA_WIDTH"); 25 | `endif 26 | 27 | logic [DataWidth-1:0] data_corrected; 28 | 29 | assign bus_out.barrier = bus_in.barrier; 30 | assign bus_out.exec_cancel = bus_in.exec_cancel; 31 | assign bus_out.exec_stall = bus_in.exec_stall; 32 | assign bus_out.req = bus_in.req; 33 | assign bus_out.add = bus_in.add; 34 | assign bus_out.we = bus_in.we; 35 | assign bus_out.be = bus_in.be; 36 | assign bus_out.r_gnt = bus_in.r_gnt; 37 | 38 | assign bus_in.busy = bus_out.busy; 39 | assign bus_in.gnt = bus_out.gnt; 40 | assign bus_in.r_valid = bus_out.r_valid; 41 | if (DropECC) begin : gen_drop_ecc 42 | assign bus_in.r_rdata = bus_out.r_rdata[DataWidth-1:0]; 43 | end else begin : gen_full_ecc 44 | assign bus_in.r_rdata = data_corrected; // remove ECC below 45 | end 46 | 47 | prim_secded_39_32_enc ecc_encode ( 48 | .in ( bus_in.wdata ), 49 | .out ( bus_out.wdata ) 50 | ); 51 | 52 | prim_secded_39_32_dec ecc_decode ( 53 | .in ( bus_out.r_rdata ), 54 | .d_o ( data_corrected ), 55 | .syndrome_o ( syndrome_o ), 56 | .err_o ( err_o ) 57 | ); 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/hci_core_intf_ecc_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Removes SECDED ECC from hci_core_intf 12 | 13 | module hci_core_intf_ecc_dec #( 14 | parameter bit DropECC = 0, 15 | parameter int unsigned DW = 32, 16 | parameter int unsigned UW = 0, 17 | localparam int unsigned NbEccBits = ( DW == 32 ) ? 7 : 8 // currently 7bit for DW=32, 8bit for DW=64 18 | ) ( 19 | hci_core_intf.slave bus_in, // DW=DW, UW+=NbEccBits 20 | hci_core_intf.master bus_out, // DW=DW, UW=UW 21 | output logic [NbEccBits-1:0] syndrome_o, 22 | output logic [ 1:0] err_o 23 | ); 24 | 25 | // ECC is added to the higher bits of USER signals, calculated from data bits. 26 | // No management of failed ECC correction is done here. 27 | `ifndef TARGET_SYNTHESIS 28 | if (bus_in.UW != bus_out.UW+NbEccBits) $fatal(1, "Ensure bus_in UW"); 29 | `endif 30 | 31 | logic [DW-1:0] data_corrected; 32 | 33 | localparam int unsigned EccUserWidth = UW + NbEccBits; 34 | 35 | assign bus_out.req = bus_in.req; 36 | assign bus_in.gnt = bus_out.gnt; 37 | assign bus_out.add = bus_in.add; 38 | assign bus_out.wen = bus_in.wen; 39 | if (DropECC) begin : gen_drop_ecc 40 | assign bus_out.data = bus_in.data; 41 | end else begin : gen_full_ecc 42 | assign bus_out.data = data_corrected; // remove ECC below 43 | end 44 | assign bus_out.user = bus_in.user[UW-1:0]; // remove ECC below 45 | assign bus_out.be = bus_in.be; 46 | assign bus_out.boffs = bus_in.boffs; 47 | assign bus_out.lrdy = bus_in.lrdy; 48 | // assign bus_in.r_data = bus_out.r_data; // add ECC below 49 | assign bus_in.r_user[UW-1:0] = bus_out.r_user[UW-1:0]; // add ECC below 50 | assign bus_in.r_valid = bus_out.r_valid; 51 | assign bus_in.r_opc = bus_out.r_opc; 52 | 53 | 54 | if (DW == 32) begin : gen_DW32 55 | prim_secded_39_32_enc ecc_encode ( 56 | .in ( bus_out.r_data ), 57 | .out ( {bus_in.r_user[EccUserWidth-1:UW], bus_in.r_data} ) 58 | ); 59 | 60 | prim_secded_39_32_dec ecc_decode ( 61 | .in ( {bus_in.user[EccUserWidth-1:UW], bus_in.data} ), 62 | .d_o ( data_corrected ), 63 | .syndrome_o ( syndrome_o ), 64 | .err_o ( err_o ) 65 | ); 66 | end else if (DW == 64) begin : gen_DW64 67 | prim_secded_72_64_enc ecc_encode ( 68 | .in ( bus_out.r_data ), 69 | .out ( {bus_in.r_user[EccUserWidth-1:UW], bus_in.r_data} ) 70 | ); 71 | 72 | prim_secded_72_64_dec ecc_decode ( 73 | .in ( {bus_in.user[EccUserWidth-1:UW], bus_in.data} ), 74 | .d_o ( data_corrected ), 75 | .syndrome_o ( syndrome_o ), 76 | .err_o ( err_o ) 77 | ); 78 | end else begin gen_err 79 | $fatal(1, "please choose appropriate DW or update the code."); 80 | end 81 | 82 | 83 | endmodule 84 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/hci_core_intf_ecc_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Adds SECDED ECC to hci_core_intf 12 | 13 | module hci_core_intf_ecc_enc #( 14 | parameter bit DropECC = 0, 15 | parameter int unsigned DW = 32, 16 | parameter int unsigned UW = 0, 17 | localparam int unsigned NbEccBits = ( DW == 32 ) ? 7 : 8 // currently 7bit for DW=32, 8bit for DW=64 18 | ) ( 19 | hci_core_intf.slave bus_in, // DW=DW, UW=UW 20 | hci_core_intf.master bus_out, // DW=DW, UW+=NbEccBits 21 | output logic [NbEccBits-1:0] syndrome_o, 22 | output logic [ 1:0] err_o 23 | ); 24 | 25 | // ECC is added to the higher bits of USER signals, calculated from data bits. 26 | // No management of failed ECC correction is done here. 27 | `ifndef TARGET_SYNTHESIS 28 | if (bus_out.UW != bus_in.UW+NbEccBits) $fatal(1, "Ensure bus_out UW"); 29 | `endif 30 | 31 | logic [DW-1:0] data_corrected; 32 | 33 | localparam int unsigned EccUserWidth = UW + NbEccBits; 34 | 35 | assign bus_out.req = bus_in.req; 36 | assign bus_in.gnt = bus_out.gnt; 37 | assign bus_out.add = bus_in.add; 38 | assign bus_out.wen = bus_in.wen; 39 | // assign bus_out.data = bus_in.data; // add ECC below 40 | if (UW > 0) begin : gen_user 41 | assign bus_out.user[UW-1:0] = bus_in.user[UW-1:0]; // add ECC below 42 | end 43 | assign bus_out.be = bus_in.be; 44 | assign bus_out.boffs = bus_in.boffs; 45 | assign bus_out.lrdy = bus_in.lrdy; 46 | if (DropECC) begin gen_drop_ecc 47 | assign bus_in.r_data = bus_out.r_data; 48 | end else begin : gen_full_ecc 49 | assign bus_in.r_data = data_corrected; // remove ECC below 50 | end 51 | if (UW > 0) begin : gen_r_user 52 | assign bus_in.r_user = bus_out.r_user[UW-1:0]; // remove ECC below 53 | end else begin gen_no_r_user 54 | assign bus_in.r_user = '0; 55 | end 56 | assign bus_in.r_valid = bus_out.r_valid; 57 | assign bus_in.r_opc = bus_out.r_opc; 58 | 59 | 60 | if (DW == 32) begin : gen_DW32 61 | prim_secded_39_32_enc ecc_encode ( 62 | .in ( bus_in.data ), 63 | .out ( {bus_out.user[EccUserWidth-1:UW], bus_out.data} ) 64 | ); 65 | 66 | prim_secded_39_32_dec ecc_decode ( 67 | .in ( {bus_out.r_user[EccUserWidth-1:UW], bus_out.r_data} ), 68 | .d_o ( data_corrected ), 69 | .syndrome_o ( syndrome_o ), 70 | .err_o ( err_o ) 71 | ); 72 | end else if (DW == 64) begin : gen_DW64 73 | prim_secded_72_64_enc ecc_encode ( 74 | .in ( bus_in.data ), 75 | .out ( {bus_out.user[EccUserWidth-1:UW], bus_out.data} ) 76 | ); 77 | 78 | prim_secded_72_64_dec ecc_decode ( 79 | .in ( {bus_out.r_user[EccUserWidth-1:UW], bus_out.r_data} ), 80 | .d_o ( data_corrected ), 81 | .syndrome_o ( syndrome_o ), 82 | .err_o ( err_o ) 83 | ); 84 | end else begin : gen_err 85 | $fatal(1, "please choose appropriate DW or update the code."); 86 | end 87 | 88 | 89 | endmodule 90 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/hci_mem_intf_ecc_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Removes SECDED ECC from hci_mem_intf 12 | 13 | module hci_mem_intf_ecc_dec #( 14 | parameter bit DropECC = 0, 15 | parameter int unsigned DW = 32, 16 | parameter int unsigned UW = 0, 17 | localparam int unsigned NbEccBits = ( DW == 32 ) ? 7 : 8 // 7bit for DW=32, 8bit for DW=64 18 | ) ( 19 | hci_mem_intf.slave bus_in, // DW=DW, UW+=NbEccBits 20 | hci_mem_intf.master bus_out, // DW=DW, UW=UW 21 | output logic [NbEccBits-1:0] syndrome_o, 22 | output logic [ 1:0] err_o 23 | ); 24 | 25 | // ECC is added to the higher bits of USER signals, calculated from data bits. 26 | // No management of failed ECC correction is done here. 27 | `ifndef TARGET_SYNTHESIS 28 | if (bus_in.UW != bus_out.UW+NbEccBits) $fatal(1, "Ensure bus_in UW"); 29 | `endif 30 | 31 | logic [DW-1:0] data_corrected; 32 | 33 | localparam int unsigned EccUserWidth = UW + NbEccBits; 34 | 35 | assign bus_out.req = bus_in.req; 36 | assign bus_in.gnt = bus_out.gnt; 37 | assign bus_out.add = bus_in.add; 38 | assign bus_out.wen = bus_in.wen; 39 | if (DropECC) begin : gen_drop_ecc 40 | assign bus_out.data = bus_in.data; 41 | end else begin : gen_full_ecc 42 | assign bus_out.data = data_corrected; // remove ECC below 43 | end 44 | if (UW > 0) begin : gen_user 45 | assign bus_out.user = bus_in.user[UW-1:0]; // remove ECC below 46 | end else begin : gen_no_user 47 | assign bus_out.user = '0; 48 | end 49 | assign bus_out.be = bus_in.be; 50 | // assign bus_in.r_data = bus_out.r_data; // add ECC below 51 | if (UW > 0) begin : gen_r_user 52 | assign bus_in.r_user[UW-1:0] = bus_out.r_user[UW-1:0]; // add ECC below 53 | end 54 | assign bus_in.r_valid = bus_out.r_valid; 55 | 56 | 57 | if (DW == 32) begin : gen_DW32 58 | prim_secded_39_32_enc ecc_encode ( 59 | .in ( bus_out.r_data ), 60 | .out ( {bus_in.r_user[EccUserWidth-1:UW], bus_in.r_data } ) 61 | ); 62 | 63 | prim_secded_39_32_dec ecc_decode ( 64 | .in ( {bus_in.user[EccUserWidth-1:UW], bus_in.data } ), 65 | .d_o ( data_corrected ), 66 | .syndrome_o ( syndrome_o ), 67 | .err_o ( err_o ) 68 | ); 69 | end else if (DW == 64) begin : gen_DW64 70 | prim_secded_72_64_enc ecc_encode ( 71 | .in ( bus_out.r_data ), 72 | .out ( {bus_in.r_user[EccUserWidth-1:UW], bus_in.r_data } ) 73 | ); 74 | 75 | prim_secded_72_64_dec ecc_decode ( 76 | .in ( {bus_in.user[EccUserWidth-1:UW], bus_in.data } ), 77 | .d_o ( data_corrected ), 78 | .syndrome_o ( syndrome_o ), 79 | .err_o ( err_o ) 80 | ); 81 | end else begin : gen_err 82 | $fatal(1, "please choose appropriate DW or update the code."); 83 | end 84 | 85 | 86 | endmodule 87 | -------------------------------------------------------------------------------- /rtl/BUS_enc_dec/hci_mem_intf_ecc_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Adds SECDED ECC to hci_mem_intf 12 | 13 | module hci_mem_intf_ecc_enc #( 14 | parameter bit DropECC = 0, 15 | parameter int unsigned DW = 32, 16 | parameter int unsigned UW = 0, 17 | localparam int unsigned NbEccBits = ( DW == 32 ) ? 7 : 8 // 7bit for DW=32, 8bit for DW=64 18 | ) ( 19 | hci_mem_intf.slave bus_in, // DW=DW, UW=UW 20 | hci_mem_intf.master bus_out, // DW=DW, UW+=NbEccBits 21 | output logic [NbEccBits-1:0] syndrome_o, 22 | output logic [ 1:0] err_o 23 | ); 24 | 25 | // ECC is added to the higher bits of USER signals, calculated from data bits. 26 | // No management of failed ECC correction is done here. 27 | `ifndef TARGET_SYNTHESIS 28 | if (bus_out.UW != bus_in.UW+NbEccBits) $fatal(1, "Ensure bus_out UW"); 29 | `endif 30 | 31 | logic [DW-1:0] data_corrected; 32 | 33 | localparam int unsigned EccUserWidth = UW + NbEccBits; 34 | 35 | assign bus_out.req = bus_in.req; 36 | assign bus_in.gnt = bus_out.gnt; 37 | assign bus_out.add = bus_in.add; 38 | assign bus_out.wen = bus_in.wen; 39 | // assign bus_out.data = bus_in.data; // add ECC below 40 | assign bus_out.user[UW-1:0] = bus_in.user[UW-1:0]; // add ECC below 41 | assign bus_out.be = bus_in.be; 42 | if (DropECC) begin : gen_drop_ecc 43 | assign bus_in.r_data = bus_out.r_data; 44 | end else begin : gen_full_ecc 45 | assign bus_in.r_data = data_corrected; // remove ECC below 46 | end 47 | assign bus_in.r_user = bus_out.r_user[UW-1:0]; // remove ECC below 48 | assign bus_in.r_valid = bus_out.r_valid; 49 | 50 | 51 | if (DW == 32) begin : gen_DW32 52 | prim_secded_39_32_enc ecc_encode ( 53 | .in ( bus_in.wata ), 54 | .out ( {bus_out.user[EccUserWidth-1:UW], bus_out.data} ) 55 | ); 56 | 57 | prim_secded_39_32_dec ecc_decode ( 58 | .in ( {bus_out.r_user[EccUserWidth-1:UW], bus_out.r_data} ), 59 | .d_o ( data_corrected ), 60 | .syndrome_o ( syndrome_o ), 61 | .err_o ( err_o ) 62 | ); 63 | end else if (DW == 64) begin : gen_DW64 64 | prim_secded_72_64_enc ecc_encode ( 65 | .in ( bus_in.data ), 66 | .out ( {bus_out.user[EccUserWidth-1:UW], bus_out.data} ) 67 | ); 68 | 69 | prim_secded_72_64_dec ecc_decode ( 70 | .in ( {bus_out.r_user[EccUserWidth-1:UW], bus_out.r_data} ), 71 | .d_o ( data_corrected ), 72 | .syndrome_o ( syndrome_o ), 73 | .err_o ( err_o ) 74 | ); 75 | end else begin : gen_err 76 | $fatal(1, "please choose appropriate DW or update the code."); 77 | end 78 | 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /rtl/ODRG_unit/ODRG.h: -------------------------------------------------------------------------------- 1 | // Generated register defines for ODRG_manager 2 | 3 | #ifndef _ODRG_MANAGER_REG_DEFS_ 4 | #define _ODRG_MANAGER_REG_DEFS_ 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | // Register width 10 | #define ODRG_MANAGER_PARAM_REG_WIDTH 32 11 | 12 | // Stack Pointer storage register 13 | #define ODRG_MANAGER_SP_STORE_REG_OFFSET 0x0 14 | 15 | // Redundancy Mode configuration 16 | #define ODRG_MANAGER_MODE_REG_OFFSET 0x4 17 | #define ODRG_MANAGER_MODE_MODE_BIT 0 18 | #define ODRG_MANAGER_MODE_DELAY_RESYNCH_BIT 1 19 | #define ODRG_MANAGER_MODE_SETBACK_BIT 2 20 | #define ODRG_MANAGER_MODE_RELOAD_SETBACK_BIT 3 21 | #define ODRG_MANAGER_MODE_FORCE_RESYNCH_BIT 4 22 | 23 | // Mismatch counter of core 0 24 | #define ODRG_MANAGER_MISMATCHES_0_REG_OFFSET 0x8 25 | 26 | // Mismatch counter of core 1 27 | #define ODRG_MANAGER_MISMATCHES_1_REG_OFFSET 0xc 28 | 29 | // Mismatch counter of core 2 30 | #define ODRG_MANAGER_MISMATCHES_2_REG_OFFSET 0x10 31 | 32 | #ifdef __cplusplus 33 | } // extern "C" 34 | #endif 35 | #endif // _ODRG_MANAGER_REG_DEFS_ 36 | // End generated register defines for ODRG_manager -------------------------------------------------------------------------------- /rtl/ODRG_unit/ODRG_unit.hjson: -------------------------------------------------------------------------------- 1 | { 2 | name: "ODRG_manager", 3 | clock_primary: "clk_i", 4 | reset_primary: "rst_ni", 5 | bus_interfaces: [ 6 | { protocol: "reg_iface", 7 | direction: "device" 8 | } 9 | ], 10 | 11 | regwidth: "32", 12 | registers: [ 13 | { name: "SP_store", 14 | desc: "Stack Pointer storage register", 15 | swaccess: "rw", 16 | hwaccess: "hrw", 17 | hwqe: "true", 18 | fields: [ 19 | { bits: "31:0", 20 | name: "SP", 21 | desc: "Stack Pointer" 22 | } 23 | ] 24 | }, 25 | { name: "MODE", 26 | desc: "Redundancy Mode configuration", 27 | swaccess: "rw", 28 | hwaccess: "hrw", 29 | fields: [ 30 | { bits: "0", 31 | name: "MODE", 32 | desc: "TMR mode enable" 33 | }, 34 | { bits: "1", 35 | name: "DELAY_RESYNCH", 36 | desc: "Enable wait-for-restoration" 37 | }, 38 | { bits: "2", 39 | name: "SETBACK", 40 | desc: "Enable setback (synchronous reset) during re-synch" 41 | }, 42 | { bits: "3", 43 | name: "RELOAD_SETBACK", 44 | desc: "Enable setback on mismatch during reload section of re-synch (only possible with SETBACK)" 45 | }, 46 | { bits: "4", 47 | name: "FORCE_RESYNCH", 48 | desc: "Forces a resynchronization routine" 49 | } 50 | ] 51 | }, 52 | { name: "MISMATCHES_0", 53 | desc: "Mismatch counter of core 0", 54 | swaccess: "rw0c", 55 | hwaccess: "hrw", 56 | fields: [ 57 | { bits: "31:0", 58 | name: "mismatches_0", 59 | desc: "mismatch counter of core 0" 60 | } 61 | ] 62 | }, 63 | { name: "MISMATCHES_1", 64 | desc: "Mismatch counter of core 1", 65 | swaccess: "rw0c", 66 | hwaccess: "hrw", 67 | fields: [ 68 | { bits: "31:0", 69 | name: "mismatches_1", 70 | desc: "mismatch counter of core 1" 71 | } 72 | ] 73 | }, 74 | { name: "MISMATCHES_2", 75 | desc: "Mismatch counter of core 2", 76 | swaccess: "rw0c", 77 | hwaccess: "hrw", 78 | fields: [ 79 | { bits: "31:0", 80 | name: "mismatches_2", 81 | desc: "mismatch counter of core 2" 82 | } 83 | ] 84 | } 85 | ], 86 | } 87 | -------------------------------------------------------------------------------- /rtl/ODRG_unit/doc.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | | Name | Offset | Length | Description | 4 | |:---------------------------------------------|:---------|---------:|:-------------------------------| 5 | | ODRG_manager.[`SP_store`](#sp_store) | 0x0 | 4 | Stack Pointer storage register | 6 | | ODRG_manager.[`MODE`](#mode) | 0x4 | 4 | Redundancy Mode configuration | 7 | | ODRG_manager.[`MISMATCHES_0`](#mismatches_0) | 0x8 | 4 | Mismatch counter of core 0 | 8 | | ODRG_manager.[`MISMATCHES_1`](#mismatches_1) | 0xc | 4 | Mismatch counter of core 1 | 9 | | ODRG_manager.[`MISMATCHES_2`](#mismatches_2) | 0x10 | 4 | Mismatch counter of core 2 | 10 | 11 | ## SP_store 12 | Stack Pointer storage register 13 | - Offset: `0x0` 14 | - Reset default: `0x0` 15 | - Reset mask: `0xffffffff` 16 | 17 | ### Fields 18 | 19 | ```wavejson 20 | {"reg": [{"name": "SP", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 21 | ``` 22 | 23 | | Bits | Type | Reset | Name | Description | 24 | |:------:|:------:|:-------:|:-------|:--------------| 25 | | 31:0 | rw | x | SP | Stack Pointer | 26 | 27 | ## MODE 28 | Redundancy Mode configuration 29 | - Offset: `0x4` 30 | - Reset default: `0x0` 31 | - Reset mask: `0x1f` 32 | 33 | ### Fields 34 | 35 | ```wavejson 36 | {"reg": [{"name": "MODE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "DELAY_RESYNCH", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "SETBACK", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "RELOAD_SETBACK", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "FORCE_RESYNCH", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 27}], "config": {"lanes": 1, "fontsize": 10, "vspace": 160}} 37 | ``` 38 | 39 | | Bits | Type | Reset | Name | Description | 40 | |:------:|:------:|:-------:|:---------------|:------------------------------------------------------------------------------------------| 41 | | 31:5 | | | | Reserved | 42 | | 4 | rw | x | FORCE_RESYNCH | Forces a resynchronization routine | 43 | | 3 | rw | x | RELOAD_SETBACK | Enable setback on mismatch during reload section of re-synch (only possible with SETBACK) | 44 | | 2 | rw | x | SETBACK | Enable setback (synchronous reset) during re-synch | 45 | | 1 | rw | x | DELAY_RESYNCH | Enable wait-for-restoration | 46 | | 0 | rw | x | MODE | TMR mode enable | 47 | 48 | ## MISMATCHES_0 49 | Mismatch counter of core 0 50 | - Offset: `0x8` 51 | - Reset default: `0x0` 52 | - Reset mask: `0xffffffff` 53 | 54 | ### Fields 55 | 56 | ```wavejson 57 | {"reg": [{"name": "mismatches_0", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 58 | ``` 59 | 60 | | Bits | Type | Reset | Name | Description | 61 | |:------:|:------:|:-------:|:-------------|:---------------------------| 62 | | 31:0 | rw0c | x | mismatches_0 | mismatch counter of core 0 | 63 | 64 | ## MISMATCHES_1 65 | Mismatch counter of core 1 66 | - Offset: `0xc` 67 | - Reset default: `0x0` 68 | - Reset mask: `0xffffffff` 69 | 70 | ### Fields 71 | 72 | ```wavejson 73 | {"reg": [{"name": "mismatches_1", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 74 | ``` 75 | 76 | | Bits | Type | Reset | Name | Description | 77 | |:------:|:------:|:-------:|:-------------|:---------------------------| 78 | | 31:0 | rw0c | x | mismatches_1 | mismatch counter of core 1 | 79 | 80 | ## MISMATCHES_2 81 | Mismatch counter of core 2 82 | - Offset: `0x10` 83 | - Reset default: `0x0` 84 | - Reset mask: `0xffffffff` 85 | 86 | ### Fields 87 | 88 | ```wavejson 89 | {"reg": [{"name": "mismatches_2", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 90 | ``` 91 | 92 | | Bits | Type | Reset | Name | Description | 93 | |:------:|:------:|:-------:|:-------------|:---------------------------| 94 | | 31:0 | rw0c | x | mismatches_2 | mismatch counter of core 2 | 95 | 96 | -------------------------------------------------------------------------------- /rtl/ODRG_unit/odrg_manager_reg_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Register Package auto-generated by `reggen` containing data structure 6 | 7 | package odrg_manager_reg_pkg; 8 | 9 | // Address widths within the block 10 | parameter int BlockAw = 5; 11 | 12 | //////////////////////////// 13 | // Typedefs for registers // 14 | //////////////////////////// 15 | 16 | typedef struct packed { 17 | logic [31:0] q; 18 | logic qe; 19 | } odrg_manager_reg2hw_sp_store_reg_t; 20 | 21 | typedef struct packed { 22 | struct packed { 23 | logic q; 24 | } mode; 25 | struct packed { 26 | logic q; 27 | } delay_resynch; 28 | struct packed { 29 | logic q; 30 | } setback; 31 | struct packed { 32 | logic q; 33 | } reload_setback; 34 | struct packed { 35 | logic q; 36 | } force_resynch; 37 | } odrg_manager_reg2hw_mode_reg_t; 38 | 39 | typedef struct packed { 40 | logic [31:0] q; 41 | } odrg_manager_reg2hw_mismatches_0_reg_t; 42 | 43 | typedef struct packed { 44 | logic [31:0] q; 45 | } odrg_manager_reg2hw_mismatches_1_reg_t; 46 | 47 | typedef struct packed { 48 | logic [31:0] q; 49 | } odrg_manager_reg2hw_mismatches_2_reg_t; 50 | 51 | typedef struct packed { 52 | logic [31:0] d; 53 | logic de; 54 | } odrg_manager_hw2reg_sp_store_reg_t; 55 | 56 | typedef struct packed { 57 | struct packed { 58 | logic d; 59 | logic de; 60 | } mode; 61 | struct packed { 62 | logic d; 63 | logic de; 64 | } delay_resynch; 65 | struct packed { 66 | logic d; 67 | logic de; 68 | } setback; 69 | struct packed { 70 | logic d; 71 | logic de; 72 | } reload_setback; 73 | struct packed { 74 | logic d; 75 | logic de; 76 | } force_resynch; 77 | } odrg_manager_hw2reg_mode_reg_t; 78 | 79 | typedef struct packed { 80 | logic [31:0] d; 81 | logic de; 82 | } odrg_manager_hw2reg_mismatches_0_reg_t; 83 | 84 | typedef struct packed { 85 | logic [31:0] d; 86 | logic de; 87 | } odrg_manager_hw2reg_mismatches_1_reg_t; 88 | 89 | typedef struct packed { 90 | logic [31:0] d; 91 | logic de; 92 | } odrg_manager_hw2reg_mismatches_2_reg_t; 93 | 94 | // Register -> HW type 95 | typedef struct packed { 96 | odrg_manager_reg2hw_sp_store_reg_t sp_store; // [133:101] 97 | odrg_manager_reg2hw_mode_reg_t mode; // [100:96] 98 | odrg_manager_reg2hw_mismatches_0_reg_t mismatches_0; // [95:64] 99 | odrg_manager_reg2hw_mismatches_1_reg_t mismatches_1; // [63:32] 100 | odrg_manager_reg2hw_mismatches_2_reg_t mismatches_2; // [31:0] 101 | } odrg_manager_reg2hw_t; 102 | 103 | // HW -> register type 104 | typedef struct packed { 105 | odrg_manager_hw2reg_sp_store_reg_t sp_store; // [141:109] 106 | odrg_manager_hw2reg_mode_reg_t mode; // [108:99] 107 | odrg_manager_hw2reg_mismatches_0_reg_t mismatches_0; // [98:66] 108 | odrg_manager_hw2reg_mismatches_1_reg_t mismatches_1; // [65:33] 109 | odrg_manager_hw2reg_mismatches_2_reg_t mismatches_2; // [32:0] 110 | } odrg_manager_hw2reg_t; 111 | 112 | // Register offsets 113 | parameter logic [BlockAw-1:0] ODRG_MANAGER_SP_STORE_OFFSET = 5'h 0; 114 | parameter logic [BlockAw-1:0] ODRG_MANAGER_MODE_OFFSET = 5'h 4; 115 | parameter logic [BlockAw-1:0] ODRG_MANAGER_MISMATCHES_0_OFFSET = 5'h 8; 116 | parameter logic [BlockAw-1:0] ODRG_MANAGER_MISMATCHES_1_OFFSET = 5'h c; 117 | parameter logic [BlockAw-1:0] ODRG_MANAGER_MISMATCHES_2_OFFSET = 5'h 10; 118 | 119 | // Register index 120 | typedef enum int { 121 | ODRG_MANAGER_SP_STORE, 122 | ODRG_MANAGER_MODE, 123 | ODRG_MANAGER_MISMATCHES_0, 124 | ODRG_MANAGER_MISMATCHES_1, 125 | ODRG_MANAGER_MISMATCHES_2 126 | } odrg_manager_id_e; 127 | 128 | // Register width information to check illegal writes 129 | parameter logic [3:0] ODRG_MANAGER_PERMIT [5] = '{ 130 | 4'b 1111, // index[0] ODRG_MANAGER_SP_STORE 131 | 4'b 0001, // index[1] ODRG_MANAGER_MODE 132 | 4'b 1111, // index[2] ODRG_MANAGER_MISMATCHES_0 133 | 4'b 1111, // index[3] ODRG_MANAGER_MISMATCHES_1 134 | 4'b 1111 // index[4] ODRG_MANAGER_MISMATCHES_2 135 | }; 136 | 137 | endpackage 138 | 139 | -------------------------------------------------------------------------------- /rtl/ODRG_unit/triple_core_barrier.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Triple Core barrier module 12 | 13 | module triple_core_barrier #( 14 | parameter int unsigned SynchronizeCycles = 1 15 | ) ( 16 | input logic clk_i, 17 | input logic rst_ni, 18 | 19 | input logic [2:0] req_i, 20 | output logic [2:0] gnt_o, 21 | 22 | output logic request_synchronized_o 23 | ); 24 | 25 | logic shifted_gnt; 26 | logic [2:0] req_q; 27 | 28 | assign request_synchronized_o = &req_i; 29 | 30 | shift_reg #( 31 | .dtype( logic ), 32 | .Depth( SynchronizeCycles ) 33 | ) i_shift_reg ( 34 | .clk_i, 35 | .rst_ni, 36 | .d_i ( &req_i ), 37 | .d_o ( shifted_gnt ) 38 | ); 39 | 40 | for (genvar i = 0; i < 3; i++) begin : gen_gnt 41 | assign gnt_o[i] = req_q[i] && shifted_gnt; 42 | end 43 | 44 | always_ff @(posedge clk_i or negedge rst_ni) begin : proc_req_ff 45 | if(!rst_ni) begin 46 | req_q <= 0; 47 | end else begin 48 | req_q <= req_i; 49 | end 50 | end 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /rtl/TMR_voter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2020 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Triple Modular Redundancy Majority Voter (MV) for a single bit 12 | // 13 | // Classical_MV: standard and & or gates 14 | // KP_MV: Kshirsagar and Patrikar MV [https://doi.org/10.1016/j.microrel.2009.08.001] 15 | // BN_MV: Ban and Naviner MV [https://doi.org/10.1109/NEWCAS.2010.5603933] 16 | 17 | module TMR_voter #( 18 | parameter int unsigned VoterType = 2 // 0: Classical_MV, 1: KP_MV, 2: BN_MV 19 | ) ( 20 | input logic a_i, 21 | input logic b_i, 22 | input logic c_i, 23 | output logic majority_o 24 | ); 25 | 26 | if (VoterType == 0) begin : gen_classical_mv 27 | assign majority_o = (a_i & b_i) | (a_i & c_i) | (b_i & c_i); 28 | end else if (VoterType == 1) begin : gen_kp_mv 29 | logic n_1, n_2, p; 30 | assign n_1 = a_i ^ b_i; 31 | assign n_2 = b_i ^ c_i; 32 | assign p = n_1 & ~n_2; 33 | assign majority_o = p ? c_i : a_i; 34 | end else if (VoterType == 2) begin : gen_bn_mv 35 | logic n; 36 | assign n = a_i ^ b_i; 37 | assign majority_o = n ? c_i : b_i; 38 | end else begin : gen_unsupported 39 | `ifndef TARGET_SYNTHESIS 40 | $fatal(1, "Please select a valid VoterType.\n"); 41 | `endif 42 | end 43 | 44 | endmodule 45 | -------------------------------------------------------------------------------- /rtl/TMR_voter_detect.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2020 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Triple Modular Redundancy Majority Voter (MV) for a single bit, with indication of erroneous bit 12 | 13 | module TMR_voter_detect #( 14 | parameter int unsigned VoterType = 0 // 0: Classical_MV, 1: KP_MV, 2: BN_MV 15 | ) ( 16 | input logic a_i, 17 | input logic b_i, 18 | input logic c_i, 19 | output logic majority_o, 20 | output logic [2:0] error_cba_o // Indicates whether input is mismatched to majority 21 | ); 22 | 23 | TMR_voter #( 24 | .VoterType ( VoterType ) 25 | ) i_voter ( 26 | .a_i, 27 | .b_i, 28 | .c_i, 29 | .majority_o 30 | ); 31 | 32 | assign error_cba_o[0] = (a_i ^ majority_o); 33 | assign error_cba_o[1] = (b_i ^ majority_o); 34 | assign error_cba_o[2] = (c_i ^ majority_o); 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /rtl/TMR_voter_fail.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2024 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Triple Modular Redundancy Majority Voter (MV) for a single bit with a failure output 12 | // 13 | // Classical_MV: standard and & or gates 14 | // KP_MV: Kshirsagar and Patrikar MV [https://doi.org/10.1016/j.microrel.2009.08.001] 15 | // BN_MV: Ban and Naviner MV [https://doi.org/10.1109/NEWCAS.2010.5603933] 16 | // 17 | // Fault detection logic added on our own Ideas 18 | 19 | module TMR_voter_fail #( 20 | parameter int unsigned VoterType = 1 // 0: Classical_MV, 1: KP_MV, 2: BN_MV 21 | ) ( 22 | input logic a_i, 23 | input logic b_i, 24 | input logic c_i, 25 | output logic majority_o, 26 | output logic fault_detected_o 27 | ); 28 | 29 | if (VoterType == 0) begin : gen_classical_mv 30 | assign majority_o = (a_i & b_i) | (a_i & c_i) | (b_i & c_i); 31 | assign fault_detected_o = (a_i ^ b_i) | (a_i ^ c_i); // 3 extra gates 32 | end else if (VoterType == 1) begin : gen_kp_mv 33 | logic n_1, n_2, p; 34 | assign n_1 = a_i ^ b_i; 35 | assign n_2 = b_i ^ c_i; 36 | assign p = n_1 & ~n_2; 37 | assign majority_o = p ? c_i : a_i; 38 | assign fault_detected_o = n_1 | n_2; // 1 extra gate 39 | end else if (VoterType == 2) begin : gen_bn_mv 40 | logic n; 41 | assign n = a_i ^ b_i; 42 | assign majority_o = n ? c_i : b_i; 43 | assign fault_detected_o = n | b_i ^ c_i; // 2 extra gates 44 | end else begin : gen_unsupported 45 | `ifndef TARGET_SYNTHESIS 46 | $fatal(1, "Please select a valid VoterType.\n"); 47 | `endif 48 | end 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /rtl/TMR_word_voter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2020 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Triple Modular Redundancy Majority Voter (MV) for a data word 12 | // 13 | // based on https://doi.org/10.1109/VTEST.2000.843880 14 | 15 | module TMR_word_voter #( 16 | parameter int unsigned DataWidth = 32 17 | ) ( 18 | input logic [DataWidth-1:0] a_i, 19 | input logic [DataWidth-1:0] b_i, 20 | input logic [DataWidth-1:0] c_i, 21 | output logic [DataWidth-1:0] majority_o, 22 | output logic error_o, // Indicates a complete mismatch (i.e. all inputs disagree) 23 | output logic [ 2:0] error_cba_o // Indicates which input is mismatched to majority 24 | ); 25 | 26 | logic match_ab, match_bc, match_ac; 27 | logic mismatch; 28 | 29 | assign match_ab = &(a_i ~^ b_i); 30 | assign match_bc = &(b_i ~^ c_i); 31 | assign match_ac = &(a_i ~^ c_i); 32 | assign error_o = ~(match_ab | match_bc | match_ac); 33 | assign mismatch = ~(match_ab & match_bc & match_ac); 34 | 35 | for (genvar i = 0; i < DataWidth; i++) begin : gen_majority_bits 36 | assign majority_o[i] = (match_ac & a_i[i]) | (~match_ac & b_i[i]); 37 | end 38 | 39 | assign error_cba_o[0] = mismatch & match_bc; 40 | assign error_cba_o[1] = mismatch & match_ac; 41 | assign error_cba_o[2] = mismatch & match_ab; 42 | 43 | endmodule 44 | 45 | -------------------------------------------------------------------------------- /rtl/bitwise_TMR_voter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2020 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Triple Modular Redundancy Majority Voter (MV) for a data word 12 | 13 | module bitwise_TMR_voter #( 14 | parameter int unsigned DataWidth = 32, 15 | parameter int unsigned VoterType = 2 // 0: Classical_MV, 1: KP_MV, 2: BN_MV 16 | ) ( 17 | input logic [DataWidth-1:0] a_i, 18 | input logic [DataWidth-1:0] b_i, 19 | input logic [DataWidth-1:0] c_i, 20 | output logic [DataWidth-1:0] majority_o, 21 | output logic error_o, // Indicates a complete mismatch (i.e. all inputs disagree) 22 | output logic [ 2:0] error_cba_o // Indicates which input is mismatched to majority 23 | ); 24 | 25 | logic [DataWidth-1:0] err_a_all, err_b_all, err_c_all; 26 | 27 | for (genvar i = 0; i < DataWidth; i++) begin : gen_bit_voters 28 | TMR_voter_detect #( 29 | .VoterType ( VoterType ) 30 | ) i_voter ( 31 | .a_i (a_i[i]), 32 | .b_i (b_i[i]), 33 | .c_i (c_i[i]), 34 | .majority_o ( majority_o[i] ), 35 | .error_cba_o( { err_c_all[i], err_b_all[i], err_a_all[i] } ) 36 | ); 37 | end 38 | 39 | assign error_cba_o[0] = |err_a_all; 40 | assign error_cba_o[1] = |err_b_all; 41 | assign error_cba_o[2] = |err_c_all; 42 | 43 | TMR_voter #( 44 | .VoterType(0) 45 | ) i_triple_mismatch ( 46 | .a_i(error_cba_o[0]), 47 | .b_i(error_cba_o[1]), 48 | .c_i(error_cba_o[2]), 49 | .majority_o (error_o) 50 | ); 51 | 52 | endmodule 53 | 54 | -------------------------------------------------------------------------------- /rtl/bitwise_TMR_voter_fail.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2024 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Triple Modular Redundancy Majority Voter (MV) for a data word 12 | 13 | module bitwise_TMR_voter_fail #( 14 | parameter int unsigned DataWidth = 32, 15 | parameter int unsigned VoterType = 1 // 0: Classical_MV, 1: KP_MV, 2: BN_MV 16 | ) ( 17 | input logic [DataWidth-1:0] a_i, 18 | input logic [DataWidth-1:0] b_i, 19 | input logic [DataWidth-1:0] c_i, 20 | output logic [DataWidth-1:0] majority_o, 21 | output logic fault_detected_o // Indicates any type of mismatch 22 | ); 23 | 24 | logic [DataWidth-1:0] fault_detected; 25 | 26 | for (genvar i = 0; i < DataWidth; i++) begin : gen_bit_voters 27 | TMR_voter_fail #( 28 | .VoterType ( VoterType ) 29 | ) i_voter_fail ( 30 | .a_i ( a_i[i] ), 31 | .b_i ( b_i[i] ), 32 | .c_i ( c_i[i] ), 33 | .majority_o ( majority_o[i] ), 34 | .fault_detected_o ( fault_detected[i] ) 35 | ); 36 | end 37 | 38 | assign fault_detected_o = |fault_detected; 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /rtl/ecc_concat_32_64.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Concatenates two ecc words 12 | 13 | module ecc_concat_32_64 #( 14 | localparam int unsigned DataInWidthA = 39, // 32+secded 15 | localparam int unsigned DataInWidthB = 39, // 32+secded 16 | localparam int unsigned DataOutWidth = 72 // 64+secded 17 | ) ( 18 | input logic [DataInWidthA-1:0] data_a_i, // data_o[31:0] 19 | input logic [DataInWidthB-1:0] data_b_i, // data_o[63:32] 20 | output logic [DataOutWidth -1:0] data_o 21 | ); 22 | 23 | // Naiive implementation - decode and encode 24 | logic [31:0] data_a; 25 | logic [31:0] data_b; 26 | 27 | prim_secded_39_32_dec dec_a ( 28 | .in ( data_a_i ), 29 | .d_o ( data_a ), 30 | .syndrome_o (), 31 | .err_o () 32 | ); 33 | 34 | prim_secded_39_32_dec dec_b ( 35 | .in ( data_b_i ), 36 | .d_o ( data_b ), 37 | .syndrome_o (), 38 | .err_o () 39 | ); 40 | 41 | prim_secded_72_64_enc enc_out ( 42 | .in ( {data_b, data_a} ), 43 | .out ( data_o ) 44 | ); 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /rtl/ecc_wrap/ECC.h: -------------------------------------------------------------------------------- 1 | // Generated register defines for ECC_manager 2 | 3 | #ifndef _ECC_MANAGER_REG_DEFS_ 4 | #define _ECC_MANAGER_REG_DEFS_ 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | // Register width 10 | #define ECC_MANAGER_PARAM_REG_WIDTH 32 11 | 12 | // Correctable mismatches caught by ecc on access 13 | #define ECC_MANAGER_MISMATCH_COUNT_REG_OFFSET 0x0 14 | 15 | // Interval between scrubs 16 | #define ECC_MANAGER_SCRUB_INTERVAL_REG_OFFSET 0x4 17 | 18 | // Correctable mismatches caught by ecc on scrub 19 | #define ECC_MANAGER_SCRUB_FIX_COUNT_REG_OFFSET 0x8 20 | 21 | // Uncorrectable mismatches caught by ecc on scrub 22 | #define ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_REG_OFFSET 0xc 23 | 24 | // Testing: Inverted write mask for data bits 25 | #define ECC_MANAGER_WRITE_MASK_DATA_N_REG_OFFSET 0x10 26 | 27 | // Testing: Inverted write mask for ECC bits 28 | #define ECC_MANAGER_WRITE_MASK_ECC_N_REG_OFFSET 0x14 29 | #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_MASK 0x7f 30 | #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_OFFSET 0 31 | #define ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_FIELD \ 32 | ((bitfield_field32_t) { .mask = ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_MASK, .index = ECC_MANAGER_WRITE_MASK_ECC_N_WRITE_MASK_ECC_N_OFFSET }) 33 | 34 | #ifdef __cplusplus 35 | } // extern "C" 36 | #endif 37 | #endif // _ECC_MANAGER_REG_DEFS_ 38 | // End generated register defines for ECC_manager -------------------------------------------------------------------------------- /rtl/ecc_wrap/doc.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | | Name | Offset | Length | Description | 4 | |:----------------------------------------------------------------------|:---------|---------:|:------------------------------------------------| 5 | | ECC_manager.[`mismatch_count`](#mismatch_count) | 0x0 | 4 | Correctable mismatches caught by ecc on access | 6 | | ECC_manager.[`scrub_interval`](#scrub_interval) | 0x4 | 4 | Interval between scrubs | 7 | | ECC_manager.[`scrub_fix_count`](#scrub_fix_count) | 0x8 | 4 | Correctable mismatches caught by ecc on scrub | 8 | | ECC_manager.[`scrub_uncorrectable_count`](#scrub_uncorrectable_count) | 0xc | 4 | Uncorrectable mismatches caught by ecc on scrub | 9 | | ECC_manager.[`write_mask_data_n`](#write_mask_data_n) | 0x10 | 4 | Testing: Inverted write mask for data bits | 10 | | ECC_manager.[`write_mask_ecc_n`](#write_mask_ecc_n) | 0x14 | 4 | Testing: Inverted write mask for ECC bits | 11 | 12 | ## mismatch_count 13 | Correctable mismatches caught by ecc on access 14 | - Offset: `0x0` 15 | - Reset default: `0x0` 16 | - Reset mask: `0xffffffff` 17 | 18 | ### Fields 19 | 20 | ```wavejson 21 | {"reg": [{"name": "correctable_mismatches", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 22 | ``` 23 | 24 | | Bits | Type | Reset | Name | Description | 25 | |:------:|:------:|:-------:|:-----------------------|:-----------------------------------------------| 26 | | 31:0 | rw0c | 0x0 | correctable_mismatches | Correctable mismatches caught by ecc on access | 27 | 28 | ## scrub_interval 29 | Interval between scrubs 30 | - Offset: `0x4` 31 | - Reset default: `0x0` 32 | - Reset mask: `0xffffffff` 33 | 34 | ### Fields 35 | 36 | ```wavejson 37 | {"reg": [{"name": "scrub_interval", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 38 | ``` 39 | 40 | | Bits | Type | Reset | Name | Description | 41 | |:------:|:------:|:-------:|:---------------|:------------------------| 42 | | 31:0 | rw | x | scrub_interval | Interval between scrubs | 43 | 44 | ## scrub_fix_count 45 | Correctable mismatches caught by ecc on scrub 46 | - Offset: `0x8` 47 | - Reset default: `0x0` 48 | - Reset mask: `0xffffffff` 49 | 50 | ### Fields 51 | 52 | ```wavejson 53 | {"reg": [{"name": "correctable_mismatches", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 54 | ``` 55 | 56 | | Bits | Type | Reset | Name | Description | 57 | |:------:|:------:|:-------:|:-----------------------|:----------------------------------------------| 58 | | 31:0 | rw0c | 0x0 | correctable_mismatches | Correctable mismatches caught by ecc on scrub | 59 | 60 | ## scrub_uncorrectable_count 61 | Uncorrectable mismatches caught by ecc on scrub 62 | - Offset: `0xc` 63 | - Reset default: `0x0` 64 | - Reset mask: `0xffffffff` 65 | 66 | ### Fields 67 | 68 | ```wavejson 69 | {"reg": [{"name": "uncorrectable_mismatches", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 70 | ``` 71 | 72 | | Bits | Type | Reset | Name | Description | 73 | |:------:|:------:|:-------:|:-------------------------|:------------------------------------------------| 74 | | 31:0 | rw0c | 0x0 | uncorrectable_mismatches | Uncorrectable mismatches caught by ecc on scrub | 75 | 76 | ## write_mask_data_n 77 | Testing: Inverted write mask for data bits 78 | - Offset: `0x10` 79 | - Reset default: `0x0` 80 | - Reset mask: `0xffffffff` 81 | 82 | ### Fields 83 | 84 | ```wavejson 85 | {"reg": [{"name": "write_mask_data_n", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 86 | ``` 87 | 88 | | Bits | Type | Reset | Name | Description | 89 | |:------:|:------:|:-------:|:------------------|:-------------------------------------------| 90 | | 31:0 | rw | 0x0 | write_mask_data_n | Testing: Inverted write mask for data bits | 91 | 92 | ## write_mask_ecc_n 93 | Testing: Inverted write mask for ECC bits 94 | - Offset: `0x14` 95 | - Reset default: `0x0` 96 | - Reset mask: `0x7f` 97 | 98 | ### Fields 99 | 100 | ```wavejson 101 | {"reg": [{"name": "write_mask_ecc_n", "bits": 7, "attr": ["rw"], "rotate": -90}, {"bits": 25}], "config": {"lanes": 1, "fontsize": 10, "vspace": 180}} 102 | ``` 103 | 104 | | Bits | Type | Reset | Name | Description | 105 | |:------:|:------:|:-------:|:-----------------|:------------------------------------------| 106 | | 31:7 | | | | Reserved | 107 | | 6:0 | rw | 0x0 | write_mask_ecc_n | Testing: Inverted write mask for ECC bits | 108 | 109 | -------------------------------------------------------------------------------- /rtl/ecc_wrap/ecc_manager.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2020 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // ECC sram manager (loggs faults, triggers scrubber) 12 | 13 | module ecc_manager #( 14 | parameter int unsigned NumBanks = 6, 15 | parameter type ecc_mgr_req_t = logic, 16 | parameter type ecc_mgr_rsp_t = logic 17 | ) ( 18 | input logic clk_i, 19 | input logic rst_ni, 20 | 21 | input ecc_mgr_req_t ecc_mgr_req_i, 22 | output ecc_mgr_rsp_t ecc_mgr_rsp_o, 23 | 24 | input logic [NumBanks-1:0] bank_faults_i, 25 | input logic [NumBanks-1:0] scrub_fix_i, 26 | input logic [NumBanks-1:0] scrub_uncorrectable_i, 27 | output logic [NumBanks-1:0] scrub_trigger_o, 28 | output logic [NumBanks-1:0][38:0] test_write_mask_no 29 | ); 30 | import ecc_manager_reg_pkg::*; 31 | 32 | logic [NumBanks-1:0][31:0] counter_value; 33 | 34 | ecc_mgr_req_t [NumBanks-1:0] reg_req; 35 | ecc_mgr_rsp_t [NumBanks-1:0] reg_rsp; 36 | 37 | ecc_manager_reg2hw_t [NumBanks-1:0] reg2hw; 38 | ecc_manager_hw2reg_t [NumBanks-1:0] hw2reg; 39 | 40 | reg_demux #( 41 | .req_t ( ecc_mgr_req_t ), 42 | .rsp_t ( ecc_mgr_rsp_t ), 43 | .NoPorts ( NumBanks ) 44 | ) i_reg_demux ( 45 | .clk_i, 46 | .rst_ni, 47 | .in_req_i ( ecc_mgr_req_i ), 48 | .in_rsp_o ( ecc_mgr_rsp_o ), 49 | .out_req_o ( reg_req ), 50 | .out_rsp_i ( reg_rsp ), 51 | .in_select_i ( ecc_mgr_req_i.addr[5+:$clog2(NumBanks)] ) // 0x20 per manager registers 52 | ); 53 | 54 | for (genvar i = 0; i < NumBanks; i++) begin : gen_fault_increment 55 | ecc_manager_reg_top #( 56 | .reg_req_t ( ecc_mgr_req_t ), 57 | .reg_rsp_t ( ecc_mgr_rsp_t ) 58 | ) i_registers ( 59 | .clk_i, 60 | .rst_ni, 61 | .reg_req_i ( reg_req[i] ), 62 | .reg_rsp_o ( reg_rsp[i] ), 63 | .reg2hw ( reg2hw [i] ), 64 | .hw2reg ( hw2reg [i] ), 65 | .devmode_i ( '0 ) 66 | ); 67 | 68 | 69 | // Count ECC fixes on access 70 | assign hw2reg[i].mismatch_count.d = reg2hw[i].mismatch_count.q + 1; 71 | assign hw2reg[i].mismatch_count.de = bank_faults_i[i]; 72 | 73 | // Count ECC fixes on scrub 74 | assign hw2reg[i].scrub_fix_count.d = reg2hw[i].scrub_fix_count.q + 1; 75 | assign hw2reg[i].scrub_fix_count.de = scrub_fix_i[i]; 76 | 77 | // Count uncorrectable scrubs 78 | assign hw2reg[i].scrub_uncorrectable_count.d = reg2hw[i].scrub_uncorrectable_count.q + 1; 79 | assign hw2reg[i].scrub_uncorrectable_count.de = scrub_uncorrectable_i[i]; 80 | 81 | // Assign testing mask 82 | assign test_write_mask_no[i][31:0] = reg2hw[i].write_mask_data_n; 83 | assign test_write_mask_no[i][38:32] = reg2hw[i].write_mask_ecc_n; 84 | 85 | // Instantiate scrub trigger counter 86 | assign scrub_trigger_o[i] = (reg2hw[i].scrub_interval.q != '0) && 87 | (counter_value[i] == reg2hw[i].scrub_interval.q); 88 | counter #( 89 | .WIDTH ( 32 ), 90 | .STICKY_OVERFLOW ( 1'b0 ) 91 | ) i_scrub_counter ( 92 | .clk_i, 93 | .rst_ni, 94 | .clear_i ( reg2hw[i].scrub_interval.q == '0 ), 95 | .en_i ( reg2hw[i].scrub_interval.q != '0 ), 96 | .load_i ( counter_value[i] == reg2hw[i].scrub_interval.q ), 97 | .down_i ( 1'b0 ), 98 | .d_i ( '0 ), 99 | .q_o ( counter_value[i] ), 100 | .overflow_o() 101 | ); 102 | end 103 | 104 | endmodule 105 | -------------------------------------------------------------------------------- /rtl/ecc_wrap/ecc_manager_reg_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Register Package auto-generated by `reggen` containing data structure 6 | 7 | package ecc_manager_reg_pkg; 8 | 9 | // Address widths within the block 10 | parameter int BlockAw = 5; 11 | 12 | //////////////////////////// 13 | // Typedefs for registers // 14 | //////////////////////////// 15 | 16 | typedef struct packed { 17 | logic [31:0] q; 18 | } ecc_manager_reg2hw_mismatch_count_reg_t; 19 | 20 | typedef struct packed { 21 | logic [31:0] q; 22 | } ecc_manager_reg2hw_scrub_interval_reg_t; 23 | 24 | typedef struct packed { 25 | logic [31:0] q; 26 | } ecc_manager_reg2hw_scrub_fix_count_reg_t; 27 | 28 | typedef struct packed { 29 | logic [31:0] q; 30 | } ecc_manager_reg2hw_scrub_uncorrectable_count_reg_t; 31 | 32 | typedef struct packed { 33 | logic [31:0] q; 34 | } ecc_manager_reg2hw_write_mask_data_n_reg_t; 35 | 36 | typedef struct packed { 37 | logic [6:0] q; 38 | } ecc_manager_reg2hw_write_mask_ecc_n_reg_t; 39 | 40 | typedef struct packed { 41 | logic [31:0] d; 42 | logic de; 43 | } ecc_manager_hw2reg_mismatch_count_reg_t; 44 | 45 | typedef struct packed { 46 | logic [31:0] d; 47 | logic de; 48 | } ecc_manager_hw2reg_scrub_fix_count_reg_t; 49 | 50 | typedef struct packed { 51 | logic [31:0] d; 52 | logic de; 53 | } ecc_manager_hw2reg_scrub_uncorrectable_count_reg_t; 54 | 55 | // Register -> HW type 56 | typedef struct packed { 57 | ecc_manager_reg2hw_mismatch_count_reg_t mismatch_count; // [166:135] 58 | ecc_manager_reg2hw_scrub_interval_reg_t scrub_interval; // [134:103] 59 | ecc_manager_reg2hw_scrub_fix_count_reg_t scrub_fix_count; // [102:71] 60 | ecc_manager_reg2hw_scrub_uncorrectable_count_reg_t scrub_uncorrectable_count; // [70:39] 61 | ecc_manager_reg2hw_write_mask_data_n_reg_t write_mask_data_n; // [38:7] 62 | ecc_manager_reg2hw_write_mask_ecc_n_reg_t write_mask_ecc_n; // [6:0] 63 | } ecc_manager_reg2hw_t; 64 | 65 | // HW -> register type 66 | typedef struct packed { 67 | ecc_manager_hw2reg_mismatch_count_reg_t mismatch_count; // [98:66] 68 | ecc_manager_hw2reg_scrub_fix_count_reg_t scrub_fix_count; // [65:33] 69 | ecc_manager_hw2reg_scrub_uncorrectable_count_reg_t scrub_uncorrectable_count; // [32:0] 70 | } ecc_manager_hw2reg_t; 71 | 72 | // Register offsets 73 | parameter logic [BlockAw-1:0] ECC_MANAGER_MISMATCH_COUNT_OFFSET = 5'h 0; 74 | parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_INTERVAL_OFFSET = 5'h 4; 75 | parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_FIX_COUNT_OFFSET = 5'h 8; 76 | parameter logic [BlockAw-1:0] ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT_OFFSET = 5'h c; 77 | parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_DATA_N_OFFSET = 5'h 10; 78 | parameter logic [BlockAw-1:0] ECC_MANAGER_WRITE_MASK_ECC_N_OFFSET = 5'h 14; 79 | 80 | // Register index 81 | typedef enum int { 82 | ECC_MANAGER_MISMATCH_COUNT, 83 | ECC_MANAGER_SCRUB_INTERVAL, 84 | ECC_MANAGER_SCRUB_FIX_COUNT, 85 | ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT, 86 | ECC_MANAGER_WRITE_MASK_DATA_N, 87 | ECC_MANAGER_WRITE_MASK_ECC_N 88 | } ecc_manager_id_e; 89 | 90 | // Register width information to check illegal writes 91 | parameter logic [3:0] ECC_MANAGER_PERMIT [6] = '{ 92 | 4'b 1111, // index[0] ECC_MANAGER_MISMATCH_COUNT 93 | 4'b 1111, // index[1] ECC_MANAGER_SCRUB_INTERVAL 94 | 4'b 1111, // index[2] ECC_MANAGER_SCRUB_FIX_COUNT 95 | 4'b 1111, // index[3] ECC_MANAGER_SCRUB_UNCORRECTABLE_COUNT 96 | 4'b 1111, // index[4] ECC_MANAGER_WRITE_MASK_DATA_N 97 | 4'b 0001 // index[5] ECC_MANAGER_WRITE_MASK_ECC_N 98 | }; 99 | 100 | endpackage 101 | 102 | -------------------------------------------------------------------------------- /rtl/ecc_wrap/ecc_scrubber.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Scrubber for ecc 12 | // - iteratively steps through memory bank 13 | // - corrects *only* correctable errors 14 | 15 | module ecc_scrubber #( 16 | parameter int unsigned BankSize = 256, 17 | parameter bit UseExternalECC = 0, 18 | parameter int unsigned DataWidth = 39, 19 | parameter int unsigned ProtWidth = 7 20 | ) ( 21 | input logic clk_i, 22 | input logic rst_ni, 23 | 24 | input logic scrub_trigger_i, // Set to 1'b0 to disable 25 | output logic bit_corrected_o, 26 | output logic uncorrectable_o, 27 | 28 | // Input signals from others accessing memory bank 29 | input logic intc_req_i, 30 | input logic intc_we_i, 31 | input logic [$clog2(BankSize)-1:0] intc_add_i, 32 | input logic [ DataWidth-1:0] intc_wdata_i, 33 | output logic [ DataWidth-1:0] intc_rdata_o, 34 | 35 | // Output directly to bank 36 | output logic bank_req_o, 37 | output logic bank_we_o, 38 | output logic [$clog2(BankSize)-1:0] bank_add_o, 39 | output logic [ DataWidth-1:0] bank_wdata_o, 40 | input logic [ DataWidth-1:0] bank_rdata_i, 41 | 42 | // If using external ECC 43 | output logic [ DataWidth-1:0] ecc_out_o, 44 | input logic [ DataWidth-1:0] ecc_in_i, 45 | input logic [ 2:0] ecc_err_i 46 | ); 47 | 48 | logic [ 1:0] ecc_err; 49 | 50 | logic scrub_req; 51 | logic scrub_we; 52 | logic [$clog2(BankSize)-1:0] scrub_add; 53 | logic [ DataWidth-1:0] scrub_wdata; 54 | logic [ DataWidth-1:0] scrub_rdata; 55 | 56 | typedef enum logic [2:0] {Idle, Read, Write} scrub_state_e; 57 | 58 | scrub_state_e state_d, state_q; 59 | 60 | logic [$clog2(BankSize)-1:0] working_add_d, working_add_q; 61 | assign scrub_add = working_add_q; 62 | 63 | assign bank_req_o = intc_req_i || scrub_req; 64 | assign intc_rdata_o = bank_rdata_i; 65 | assign scrub_rdata = bank_rdata_i; 66 | 67 | always_comb begin : proc_bank_assign 68 | // By default, bank is connected to outside 69 | bank_we_o = intc_we_i; 70 | bank_add_o = intc_add_i; 71 | bank_wdata_o = intc_wdata_i; 72 | 73 | // If scrubber active and outside is not, do scrub 74 | if ( (state_q == Read || state_q == Write) && intc_req_i == 1'b0) begin 75 | bank_we_o = scrub_we; 76 | bank_add_o = scrub_add; 77 | bank_wdata_o = scrub_wdata; 78 | end 79 | end 80 | 81 | if (UseExternalECC) begin : gen_external_ecc 82 | assign ecc_err = ecc_err_i; 83 | assign ecc_out_o = scrub_rdata; 84 | assign scrub_wdata = ecc_in_i; 85 | end else begin : gen_internal_ecc 86 | assign ecc_out_o = '0; 87 | hsiao_ecc_cor #( 88 | .DataWidth (DataWidth-ProtWidth), 89 | .ProtWidth (ProtWidth) 90 | ) ecc_corrector ( 91 | .in ( scrub_rdata ), 92 | .out ( scrub_wdata ), 93 | .syndrome_o(), 94 | .err_o ( ecc_err ) 95 | ); 96 | end 97 | 98 | always_comb begin : proc_FSM_logic 99 | state_d = state_q; 100 | scrub_req = 1'b0; 101 | scrub_we = 1'b0; 102 | working_add_d = working_add_q; 103 | bit_corrected_o = 1'b0; 104 | uncorrectable_o = 1'b0; 105 | 106 | if (state_q == Idle) begin 107 | // Switch to read state if triggered to scrub 108 | if (scrub_trigger_i) begin 109 | state_d = Read; 110 | end 111 | 112 | end else if (state_q == Read) begin 113 | // Request read to scrub 114 | scrub_req = 1'b1; 115 | // Request only active if outside is inactive 116 | if (intc_req_i == 1'b0) begin 117 | state_d = Write; 118 | end 119 | 120 | end else if (state_q == Write) begin 121 | if (ecc_err[0] == 1'b0) begin // No correctable Error 122 | // Return to idle state 123 | state_d = Idle; 124 | working_add_d = (working_add_q + 1) % BankSize; // increment address 125 | uncorrectable_o = ecc_err[1]; 126 | 127 | end else begin // Correctable Error 128 | // Write corrected version 129 | scrub_req = 1'b1; 130 | scrub_we = 1'b1; 131 | 132 | // INTC interference - retry read and write 133 | if (intc_req_i == 1'b1) begin 134 | state_d = Read; 135 | end else begin // Error corrected 136 | state_d = Idle; 137 | working_add_d = (working_add_q + 1) % BankSize; // increment address 138 | bit_corrected_o = 1'b1; 139 | end 140 | end 141 | end 142 | end 143 | 144 | always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bank_add 145 | if(!rst_ni) begin 146 | working_add_q <= '0; 147 | end else begin 148 | working_add_q <= working_add_d; 149 | end 150 | end 151 | 152 | always_ff @(posedge clk_i or negedge rst_ni) begin : proc_FSM 153 | if(!rst_ni) begin 154 | state_q <= Idle; 155 | end else begin 156 | state_q <= state_d; 157 | end 158 | end 159 | 160 | endmodule 161 | -------------------------------------------------------------------------------- /rtl/ecc_wrap/ecc_sram_wrapper.hjson: -------------------------------------------------------------------------------- 1 | { 2 | name: "ECC_manager", 3 | clock_primary: "clk_i", 4 | reset_primary: "rst_ni", 5 | bus_interfaces: [ 6 | { protocol: "reg_iface", 7 | direction: "device" 8 | } 9 | ], 10 | 11 | regwidth: "32", 12 | 13 | registers: [ 14 | { name: "mismatch_count", 15 | desc: "Correctable mismatches caught by ecc on access", 16 | swaccess: "rw0c", 17 | hwaccess: "hrw", 18 | resval: "0", 19 | fields: [ 20 | { bits: "31:0", 21 | name: "correctable_mismatches", 22 | desc: "Correctable mismatches caught by ecc on access" 23 | } 24 | ] 25 | }, 26 | { name: "scrub_interval", 27 | desc: "Interval between scrubs", 28 | swaccess: "rw", 29 | hwaccess: "hro", 30 | fields: [ 31 | { bits: "31:0" 32 | name: "scrub_interval" 33 | desc: "Interval between scrubs" 34 | } 35 | ] 36 | }, 37 | { name: "scrub_fix_count", 38 | desc: "Correctable mismatches caught by ecc on scrub", 39 | swaccess: "rw0c", 40 | hwaccess: "hrw", 41 | resval: "0", 42 | fields: [ 43 | { bits: "31:0", 44 | name: "correctable_mismatches", 45 | desc: "Correctable mismatches caught by ecc on scrub" 46 | } 47 | ] 48 | }, 49 | { name: "scrub_uncorrectable_count", 50 | desc: "Uncorrectable mismatches caught by ecc on scrub", 51 | swaccess: "rw0c", 52 | hwaccess: "hrw", 53 | resval: "0", 54 | fields: [ 55 | { bits: "31:0", 56 | name: "uncorrectable_mismatches", 57 | desc: "Uncorrectable mismatches caught by ecc on scrub" 58 | } 59 | ] 60 | }, 61 | { name: "write_mask_data_n", 62 | desc: "Testing: Inverted write mask for data bits", 63 | swaccess: "rw", 64 | hwaccess: "hro", 65 | resval: "0", 66 | fields: [ 67 | { bits: "31:0", 68 | name: "write_mask_data_n", 69 | desc: "Testing: Inverted write mask for data bits" 70 | } 71 | ] 72 | }, 73 | { name: "write_mask_ecc_n", 74 | desc: "Testing: Inverted write mask for ECC bits", 75 | swaccess: "rw", 76 | hwaccess: "hro", 77 | resval: "0", 78 | fields: [ 79 | { bits: "6:0", 80 | name: "write_mask_ecc_n", 81 | desc: "Testing: Inverted write mask for ECC bits" 82 | } 83 | ] 84 | } 85 | ], 86 | } 87 | -------------------------------------------------------------------------------- /rtl/hsiao_ecc/hsiao_ecc_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2024 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Hsiao ECC decoder 12 | // Based in part on work by lowRISC 13 | 14 | module hsiao_ecc_cor import hsiao_ecc_pkg::*; #( 15 | parameter int unsigned DataWidth = 32, 16 | parameter int unsigned ProtWidth = min_ecc(DataWidth), 17 | parameter int unsigned TotalWidth = DataWidth + ProtWidth, 18 | parameter bit PrintHsiao = 1'b0 19 | ) ( 20 | input logic [TotalWidth-1:0] in, 21 | output logic [TotalWidth-1:0] out, 22 | output logic [ ProtWidth-1:0] syndrome_o, 23 | output logic [ 1:0] err_o 24 | ); 25 | 26 | if (ProtWidth < min_ecc(DataWidth)) $error("ProtWidth must be greater than $clog2(DataWidth)+2"); 27 | 28 | localparam bit [MaxParityWidth-1:0][ MaxTotalWidth-1:0] HsiaoCodes = 29 | hsiao_matrix(DataWidth, ProtWidth); 30 | localparam bit [ MaxTotalWidth-1:0][MaxParityWidth-1:0] CorrCodes = 31 | transpose(HsiaoCodes, ProtWidth, TotalWidth); 32 | 33 | logic single_error; 34 | 35 | for (genvar i = 0; i < ProtWidth; i++) begin : gen_syndrome 36 | assign syndrome_o[i] = ^(in & HsiaoCodes[i][TotalWidth-1:0]); 37 | end 38 | 39 | for (genvar i = 0; i < TotalWidth; i++) begin : gen_out 40 | assign out[i] = in[i] ^ (syndrome_o == CorrCodes[i][ProtWidth-1:0]); 41 | end 42 | 43 | assign single_error = ^syndrome_o; 44 | assign err_o[0] = single_error; 45 | assign err_o[1] = ~single_error & (|syndrome_o); 46 | 47 | `ifndef TARGET_SYNTHESIS 48 | if (PrintHsiao) begin : gen_print_matrix 49 | initial begin : p_hsiao_matrix 50 | automatic string s = "##"; 51 | for (int i = 0; i < TotalWidth; i++) begin 52 | s = {s, "#"}; 53 | end 54 | $display("%s", s); 55 | $display("hsiao_ecc_cor for %d_%d", TotalWidth, DataWidth); 56 | for (int i = ProtWidth-1; i >= 0; i--) begin 57 | $display("%b",HsiaoCodes[i][TotalWidth-1:0]); 58 | end 59 | $display("%s", s); 60 | for (int i = TotalWidth-1; i >= 0; i--) begin 61 | $display("%b",CorrCodes[i][ProtWidth-1:0]); 62 | end 63 | $display("%s", s); 64 | end 65 | end 66 | `endif 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /rtl/hsiao_ecc/hsiao_ecc_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2024 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Hsiao ECC decoder 12 | // Based in part on work by lowRISC 13 | 14 | module hsiao_ecc_dec import hsiao_ecc_pkg::*; #( 15 | parameter int unsigned DataWidth = 32, 16 | parameter int unsigned ProtWidth = min_ecc(DataWidth), 17 | parameter int unsigned TotalWidth = DataWidth + ProtWidth, 18 | parameter bit PrintHsiao = 1'b0 19 | ) ( 20 | input logic [TotalWidth-1:0] in, 21 | output logic [ DataWidth-1:0] out, 22 | output logic [ ProtWidth-1:0] syndrome_o, 23 | output logic [ 1:0] err_o 24 | ); 25 | 26 | if (ProtWidth < min_ecc(DataWidth)) $error("ProtWidth must be greater than $clog2(DataWidth)+2"); 27 | 28 | localparam bit [MaxParityWidth-1:0][ MaxTotalWidth-1:0] HsiaoCodes = 29 | hsiao_matrix(DataWidth, ProtWidth); 30 | localparam bit [ MaxTotalWidth-1:0][MaxParityWidth-1:0] CorrCodes = 31 | transpose(HsiaoCodes, ProtWidth, TotalWidth); 32 | 33 | logic single_error; 34 | 35 | for (genvar i = 0; i < ProtWidth; i++) begin : gen_syndrome 36 | assign syndrome_o[i] = ^(in & HsiaoCodes[i][TotalWidth-1:0]); 37 | end 38 | 39 | for (genvar i = 0; i < DataWidth; i++) begin : gen_out 40 | assign out[i] = in[i] ^ (syndrome_o == CorrCodes[i][ProtWidth-1:0]); 41 | end 42 | 43 | assign single_error = ^syndrome_o; 44 | assign err_o[0] = single_error; 45 | assign err_o[1] = ~single_error & (|syndrome_o); 46 | 47 | `ifndef TARGET_SYNTHESIS 48 | if (PrintHsiao) begin : gen_print_matrix 49 | initial begin : p_hsiao_matrix 50 | automatic string s = "##"; 51 | for (int i = 0; i < TotalWidth; i++) begin 52 | s = {s, "#"}; 53 | end 54 | $display("%s", s); 55 | $display("hsiao_ecc_dec for %d_%d", TotalWidth, DataWidth); 56 | for (int i = ProtWidth-1; i >= 0; i--) begin 57 | $display("%b",HsiaoCodes[i][TotalWidth-1:0]); 58 | end 59 | $display("%s", s); 60 | end 61 | end 62 | `endif 63 | 64 | endmodule 65 | -------------------------------------------------------------------------------- /rtl/hsiao_ecc/hsiao_ecc_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2024 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Hsiao ECC encoder 12 | // Based in part on work by lowRISC 13 | 14 | module hsiao_ecc_enc import hsiao_ecc_pkg::*; #( 15 | parameter int unsigned DataWidth = 32, 16 | parameter int unsigned ProtWidth = min_ecc(DataWidth), 17 | parameter int unsigned TotalWidth = DataWidth + ProtWidth, 18 | parameter bit PrintHsiao = 1'b0 19 | ) ( 20 | input logic [ DataWidth-1:0] in, 21 | output logic [TotalWidth-1:0] out 22 | ); 23 | 24 | if (ProtWidth < min_ecc(DataWidth)) $error("ProtWidth must be greater than $clog2(DataWidth)+2"); 25 | 26 | localparam bit [MaxParityWidth-1:0][MaxTotalWidth-1:0] HsiaoCodes = 27 | hsiao_matrix(DataWidth, ProtWidth); 28 | 29 | always_comb begin : proc_encode 30 | out[DataWidth-1:0] = in; 31 | for (int unsigned i = 0; i < ProtWidth; i++) begin 32 | out[DataWidth + i] = ^(in & HsiaoCodes[i][DataWidth-1:0]); 33 | end 34 | end 35 | 36 | `ifndef TARGET_SYNTHESIS 37 | if (PrintHsiao) begin : gen_print_matrix 38 | initial begin : p_hsiao_matrix 39 | automatic string s = "##"; 40 | for (int i = 0; i < TotalWidth; i++) begin 41 | s = {s, "#"}; 42 | end 43 | $display("%s", s); 44 | $display("hsiao_ecc_enc for %d_%d", TotalWidth, DataWidth); 45 | for (int i = ProtWidth-1; i >= 0; i--) begin 46 | $display("%b",HsiaoCodes[i][TotalWidth-1:0]); 47 | end 48 | $display("%s", s); 49 | end 50 | end 51 | `endif 52 | 53 | endmodule 54 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_13_8_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 5 -k 8 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_13_8_cor ( 9 | input [12:0] d_i, 10 | output logic [12:0] d_o, 11 | output logic [4:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(d_i & 13'h016B); 19 | assign syndrome_o[1] = ^(d_i & 13'h02AD); 20 | assign syndrome_o[2] = ^(d_i & 13'h04D5); 21 | assign syndrome_o[3] = ^(d_i & 13'h0836); 22 | assign syndrome_o[4] = ^(d_i & 13'h10DA); 23 | 24 | // Corrected output calculation 25 | assign d_o[0] = (syndrome_o == 5'h7) ^ d_i[0]; 26 | assign d_o[1] = (syndrome_o == 5'h19) ^ d_i[1]; 27 | assign d_o[2] = (syndrome_o == 5'he) ^ d_i[2]; 28 | assign d_o[3] = (syndrome_o == 5'h13) ^ d_i[3]; 29 | assign d_o[4] = (syndrome_o == 5'h1c) ^ d_i[4]; 30 | assign d_o[5] = (syndrome_o == 5'hb) ^ d_i[5]; 31 | assign d_o[6] = (syndrome_o == 5'h15) ^ d_i[6]; 32 | assign d_o[7] = (syndrome_o == 5'h16) ^ d_i[7]; 33 | assign d_o[8] = (syndrome_o == 5'h1) ^ d_i[8]; 34 | assign d_o[9] = (syndrome_o == 5'h2) ^ d_i[9]; 35 | assign d_o[10] = (syndrome_o == 5'h4) ^ d_i[10]; 36 | assign d_o[11] = (syndrome_o == 5'h8) ^ d_i[11]; 37 | assign d_o[12] = (syndrome_o == 5'h10) ^ d_i[12]; 38 | 39 | // err_o calc. bit0: single error, bit1: double error 40 | assign single_error = ^syndrome_o; 41 | assign err_o[0] = single_error; 42 | assign err_o[1] = ~single_error & (|syndrome_o); 43 | 44 | endmodule : prim_secded_13_8_cor 45 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_13_8_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 5 -k 8 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_13_8_dec ( 9 | input [12:0] in, 10 | output logic [7:0] d_o, 11 | output logic [4:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(in & 13'h016B); 19 | assign syndrome_o[1] = ^(in & 13'h02AD); 20 | assign syndrome_o[2] = ^(in & 13'h04D5); 21 | assign syndrome_o[3] = ^(in & 13'h0836); 22 | assign syndrome_o[4] = ^(in & 13'h10DA); 23 | 24 | // Corrected output calculation 25 | assign d_o[0] = (syndrome_o == 5'h7) ^ in[0]; 26 | assign d_o[1] = (syndrome_o == 5'h19) ^ in[1]; 27 | assign d_o[2] = (syndrome_o == 5'he) ^ in[2]; 28 | assign d_o[3] = (syndrome_o == 5'h13) ^ in[3]; 29 | assign d_o[4] = (syndrome_o == 5'h1c) ^ in[4]; 30 | assign d_o[5] = (syndrome_o == 5'hb) ^ in[5]; 31 | assign d_o[6] = (syndrome_o == 5'h15) ^ in[6]; 32 | assign d_o[7] = (syndrome_o == 5'h16) ^ in[7]; 33 | 34 | // err_o calc. bit0: single error, bit1: double error 35 | assign single_error = ^syndrome_o; 36 | assign err_o[0] = single_error; 37 | assign err_o[1] = ~single_error & (|syndrome_o); 38 | 39 | endmodule : prim_secded_13_8_dec 40 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_13_8_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 5 -k 8 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_13_8_enc ( 9 | input [7:0] in, 10 | output logic [12:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[7:0] = in; 15 | out[8] = ^(in & 8'h6B); 16 | out[9] = ^(in & 8'hAD); 17 | out[10] = ^(in & 8'hD5); 18 | out[11] = ^(in & 8'h36); 19 | out[12] = ^(in & 8'hDA); 20 | end 21 | 22 | endmodule : prim_secded_13_8_enc 23 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_22_16_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_22_16_cor ( 9 | input [21:0] d_i, 10 | output logic [21:0] d_o, 11 | output logic [5:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(d_i & 22'h015555); 19 | assign syndrome_o[1] = ^(d_i & 22'h02AA55); 20 | assign syndrome_o[2] = ^(d_i & 22'h0495A9); 21 | assign syndrome_o[3] = ^(d_i & 22'h0869A6); 22 | assign syndrome_o[4] = ^(d_i & 22'h10669A); 23 | assign syndrome_o[5] = ^(d_i & 22'h209A6A); 24 | 25 | // Corrected output calculation 26 | assign d_o[0] = (syndrome_o == 6'h7) ^ d_i[0]; 27 | assign d_o[1] = (syndrome_o == 6'h38) ^ d_i[1]; 28 | assign d_o[2] = (syndrome_o == 6'hb) ^ d_i[2]; 29 | assign d_o[3] = (syndrome_o == 6'h34) ^ d_i[3]; 30 | assign d_o[4] = (syndrome_o == 6'h13) ^ d_i[4]; 31 | assign d_o[5] = (syndrome_o == 6'h2c) ^ d_i[5]; 32 | assign d_o[6] = (syndrome_o == 6'h23) ^ d_i[6]; 33 | assign d_o[7] = (syndrome_o == 6'h1c) ^ d_i[7]; 34 | assign d_o[8] = (syndrome_o == 6'hd) ^ d_i[8]; 35 | assign d_o[9] = (syndrome_o == 6'h32) ^ d_i[9]; 36 | assign d_o[10] = (syndrome_o == 6'h15) ^ d_i[10]; 37 | assign d_o[11] = (syndrome_o == 6'h2a) ^ d_i[11]; 38 | assign d_o[12] = (syndrome_o == 6'h25) ^ d_i[12]; 39 | assign d_o[13] = (syndrome_o == 6'h1a) ^ d_i[13]; 40 | assign d_o[14] = (syndrome_o == 6'h19) ^ d_i[14]; 41 | assign d_o[15] = (syndrome_o == 6'h26) ^ d_i[15]; 42 | assign d_o[16] = (syndrome_o == 6'h1) ^ d_i[16]; 43 | assign d_o[17] = (syndrome_o == 6'h2) ^ d_i[17]; 44 | assign d_o[18] = (syndrome_o == 6'h4) ^ d_i[18]; 45 | assign d_o[19] = (syndrome_o == 6'h8) ^ d_i[19]; 46 | assign d_o[20] = (syndrome_o == 6'h10) ^ d_i[20]; 47 | assign d_o[21] = (syndrome_o == 6'h20) ^ d_i[21]; 48 | 49 | // err_o calc. bit0: single error, bit1: double error 50 | assign single_error = ^syndrome_o; 51 | assign err_o[0] = single_error; 52 | assign err_o[1] = ~single_error & (|syndrome_o); 53 | 54 | endmodule : prim_secded_22_16_cor 55 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_22_16_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_22_16_dec ( 9 | input [21:0] in, 10 | output logic [15:0] d_o, 11 | output logic [5:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(in & 22'h015555); 19 | assign syndrome_o[1] = ^(in & 22'h02AA55); 20 | assign syndrome_o[2] = ^(in & 22'h0495A9); 21 | assign syndrome_o[3] = ^(in & 22'h0869A6); 22 | assign syndrome_o[4] = ^(in & 22'h10669A); 23 | assign syndrome_o[5] = ^(in & 22'h209A6A); 24 | 25 | // Corrected output calculation 26 | assign d_o[0] = (syndrome_o == 6'h7) ^ in[0]; 27 | assign d_o[1] = (syndrome_o == 6'h38) ^ in[1]; 28 | assign d_o[2] = (syndrome_o == 6'hb) ^ in[2]; 29 | assign d_o[3] = (syndrome_o == 6'h34) ^ in[3]; 30 | assign d_o[4] = (syndrome_o == 6'h13) ^ in[4]; 31 | assign d_o[5] = (syndrome_o == 6'h2c) ^ in[5]; 32 | assign d_o[6] = (syndrome_o == 6'h23) ^ in[6]; 33 | assign d_o[7] = (syndrome_o == 6'h1c) ^ in[7]; 34 | assign d_o[8] = (syndrome_o == 6'hd) ^ in[8]; 35 | assign d_o[9] = (syndrome_o == 6'h32) ^ in[9]; 36 | assign d_o[10] = (syndrome_o == 6'h15) ^ in[10]; 37 | assign d_o[11] = (syndrome_o == 6'h2a) ^ in[11]; 38 | assign d_o[12] = (syndrome_o == 6'h25) ^ in[12]; 39 | assign d_o[13] = (syndrome_o == 6'h1a) ^ in[13]; 40 | assign d_o[14] = (syndrome_o == 6'h19) ^ in[14]; 41 | assign d_o[15] = (syndrome_o == 6'h26) ^ in[15]; 42 | 43 | // err_o calc. bit0: single error, bit1: double error 44 | assign single_error = ^syndrome_o; 45 | assign err_o[0] = single_error; 46 | assign err_o[1] = ~single_error & (|syndrome_o); 47 | 48 | endmodule : prim_secded_22_16_dec 49 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_22_16_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_22_16_enc ( 9 | input [15:0] in, 10 | output logic [21:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[15:0] = in; 15 | out[16] = ^(in & 16'h5555); 16 | out[17] = ^(in & 16'hAA55); 17 | out[18] = ^(in & 16'h95A9); 18 | out[19] = ^(in & 16'h69A6); 19 | out[20] = ^(in & 16'h669A); 20 | out[21] = ^(in & 16'h9A6A); 21 | end 22 | 23 | endmodule : prim_secded_22_16_enc 24 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_28_22_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 6 -k 22 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_28_22_cor ( 9 | input [27:0] d_i, 10 | output logic [27:0] d_o, 11 | output logic [5:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(d_i & 28'h07003FF); 19 | assign syndrome_o[1] = ^(d_i & 28'h0B0FC0F); 20 | assign syndrome_o[2] = ^(d_i & 28'h1371C71); 21 | assign syndrome_o[3] = ^(d_i & 28'h23B6592); 22 | assign syndrome_o[4] = ^(d_i & 28'h41DAAA4); 23 | assign syndrome_o[5] = ^(d_i & 28'h82ED348); 24 | 25 | // Corrected output calculation 26 | assign d_o[0] = (syndrome_o == 6'h7) ^ d_i[0]; 27 | assign d_o[1] = (syndrome_o == 6'hb) ^ d_i[1]; 28 | assign d_o[2] = (syndrome_o == 6'h13) ^ d_i[2]; 29 | assign d_o[3] = (syndrome_o == 6'h23) ^ d_i[3]; 30 | assign d_o[4] = (syndrome_o == 6'hd) ^ d_i[4]; 31 | assign d_o[5] = (syndrome_o == 6'h15) ^ d_i[5]; 32 | assign d_o[6] = (syndrome_o == 6'h25) ^ d_i[6]; 33 | assign d_o[7] = (syndrome_o == 6'h19) ^ d_i[7]; 34 | assign d_o[8] = (syndrome_o == 6'h29) ^ d_i[8]; 35 | assign d_o[9] = (syndrome_o == 6'h31) ^ d_i[9]; 36 | assign d_o[10] = (syndrome_o == 6'he) ^ d_i[10]; 37 | assign d_o[11] = (syndrome_o == 6'h16) ^ d_i[11]; 38 | assign d_o[12] = (syndrome_o == 6'h26) ^ d_i[12]; 39 | assign d_o[13] = (syndrome_o == 6'h1a) ^ d_i[13]; 40 | assign d_o[14] = (syndrome_o == 6'h2a) ^ d_i[14]; 41 | assign d_o[15] = (syndrome_o == 6'h32) ^ d_i[15]; 42 | assign d_o[16] = (syndrome_o == 6'h1c) ^ d_i[16]; 43 | assign d_o[17] = (syndrome_o == 6'h2c) ^ d_i[17]; 44 | assign d_o[18] = (syndrome_o == 6'h34) ^ d_i[18]; 45 | assign d_o[19] = (syndrome_o == 6'h38) ^ d_i[19]; 46 | assign d_o[20] = (syndrome_o == 6'h1f) ^ d_i[20]; 47 | assign d_o[21] = (syndrome_o == 6'h2f) ^ d_i[21]; 48 | assign d_o[22] = (syndrome_o == 6'h1) ^ d_i[22]; 49 | assign d_o[23] = (syndrome_o == 6'h2) ^ d_i[23]; 50 | assign d_o[24] = (syndrome_o == 6'h4) ^ d_i[24]; 51 | assign d_o[25] = (syndrome_o == 6'h8) ^ d_i[25]; 52 | assign d_o[26] = (syndrome_o == 6'h10) ^ d_i[26]; 53 | assign d_o[27] = (syndrome_o == 6'h20) ^ d_i[27]; 54 | 55 | // err_o calc. bit0: single error, bit1: double error 56 | assign single_error = ^syndrome_o; 57 | assign err_o[0] = single_error; 58 | assign err_o[1] = ~single_error & (|syndrome_o); 59 | 60 | endmodule : prim_secded_28_22_cor 61 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_28_22_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 6 -k 22 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_28_22_dec ( 9 | input [27:0] in, 10 | output logic [21:0] d_o, 11 | output logic [5:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(in & 28'h07003FF); 19 | assign syndrome_o[1] = ^(in & 28'h0B0FC0F); 20 | assign syndrome_o[2] = ^(in & 28'h1371C71); 21 | assign syndrome_o[3] = ^(in & 28'h23B6592); 22 | assign syndrome_o[4] = ^(in & 28'h41DAAA4); 23 | assign syndrome_o[5] = ^(in & 28'h82ED348); 24 | 25 | // Corrected output calculation 26 | assign d_o[0] = (syndrome_o == 6'h7) ^ in[0]; 27 | assign d_o[1] = (syndrome_o == 6'hb) ^ in[1]; 28 | assign d_o[2] = (syndrome_o == 6'h13) ^ in[2]; 29 | assign d_o[3] = (syndrome_o == 6'h23) ^ in[3]; 30 | assign d_o[4] = (syndrome_o == 6'hd) ^ in[4]; 31 | assign d_o[5] = (syndrome_o == 6'h15) ^ in[5]; 32 | assign d_o[6] = (syndrome_o == 6'h25) ^ in[6]; 33 | assign d_o[7] = (syndrome_o == 6'h19) ^ in[7]; 34 | assign d_o[8] = (syndrome_o == 6'h29) ^ in[8]; 35 | assign d_o[9] = (syndrome_o == 6'h31) ^ in[9]; 36 | assign d_o[10] = (syndrome_o == 6'he) ^ in[10]; 37 | assign d_o[11] = (syndrome_o == 6'h16) ^ in[11]; 38 | assign d_o[12] = (syndrome_o == 6'h26) ^ in[12]; 39 | assign d_o[13] = (syndrome_o == 6'h1a) ^ in[13]; 40 | assign d_o[14] = (syndrome_o == 6'h2a) ^ in[14]; 41 | assign d_o[15] = (syndrome_o == 6'h32) ^ in[15]; 42 | assign d_o[16] = (syndrome_o == 6'h1c) ^ in[16]; 43 | assign d_o[17] = (syndrome_o == 6'h2c) ^ in[17]; 44 | assign d_o[18] = (syndrome_o == 6'h34) ^ in[18]; 45 | assign d_o[19] = (syndrome_o == 6'h38) ^ in[19]; 46 | assign d_o[20] = (syndrome_o == 6'h1f) ^ in[20]; 47 | assign d_o[21] = (syndrome_o == 6'h2f) ^ in[21]; 48 | 49 | // err_o calc. bit0: single error, bit1: double error 50 | assign single_error = ^syndrome_o; 51 | assign err_o[0] = single_error; 52 | assign err_o[1] = ~single_error & (|syndrome_o); 53 | 54 | endmodule : prim_secded_28_22_dec 55 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_28_22_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 6 -k 22 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_28_22_enc ( 9 | input [21:0] in, 10 | output logic [27:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[21:0] = in; 15 | out[22] = ^(in & 22'h3003FF); 16 | out[23] = ^(in & 22'h30FC0F); 17 | out[24] = ^(in & 22'h371C71); 18 | out[25] = ^(in & 22'h3B6592); 19 | out[26] = ^(in & 22'h1DAAA4); 20 | out[27] = ^(in & 22'h2ED348); 21 | end 22 | 23 | endmodule : prim_secded_28_22_enc 24 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_39_32_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_39_32_cor ( 9 | input [38:0] d_i, 10 | output logic [38:0] d_o, 11 | output logic [6:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(d_i & 39'h012CA53295); 19 | assign syndrome_o[1] = ^(d_i & 39'h0293492CA5); 20 | assign syndrome_o[2] = ^(d_i & 39'h04552A5329); 21 | assign syndrome_o[3] = ^(d_i & 39'h08A8D294AA); 22 | assign syndrome_o[4] = ^(d_i & 39'h104A2CA54A); 23 | assign syndrome_o[5] = ^(d_i & 39'h2025534952); 24 | assign syndrome_o[6] = ^(d_i & 39'h40D294CA54); 25 | 26 | // Corrected output calculation 27 | assign d_o[0] = (syndrome_o == 7'h7) ^ d_i[0]; 28 | assign d_o[1] = (syndrome_o == 7'h38) ^ d_i[1]; 29 | assign d_o[2] = (syndrome_o == 7'h43) ^ d_i[2]; 30 | assign d_o[3] = (syndrome_o == 7'h1c) ^ d_i[3]; 31 | assign d_o[4] = (syndrome_o == 7'h61) ^ d_i[4]; 32 | assign d_o[5] = (syndrome_o == 7'he) ^ d_i[5]; 33 | assign d_o[6] = (syndrome_o == 7'h70) ^ d_i[6]; 34 | assign d_o[7] = (syndrome_o == 7'hb) ^ d_i[7]; 35 | assign d_o[8] = (syndrome_o == 7'h34) ^ d_i[8]; 36 | assign d_o[9] = (syndrome_o == 7'h45) ^ d_i[9]; 37 | assign d_o[10] = (syndrome_o == 7'h1a) ^ d_i[10]; 38 | assign d_o[11] = (syndrome_o == 7'h62) ^ d_i[11]; 39 | assign d_o[12] = (syndrome_o == 7'hd) ^ d_i[12]; 40 | assign d_o[13] = (syndrome_o == 7'h13) ^ d_i[13]; 41 | assign d_o[14] = (syndrome_o == 7'h64) ^ d_i[14]; 42 | assign d_o[15] = (syndrome_o == 7'h58) ^ d_i[15]; 43 | assign d_o[16] = (syndrome_o == 7'h23) ^ d_i[16]; 44 | assign d_o[17] = (syndrome_o == 7'h2c) ^ d_i[17]; 45 | assign d_o[18] = (syndrome_o == 7'h51) ^ d_i[18]; 46 | assign d_o[19] = (syndrome_o == 7'h16) ^ d_i[19]; 47 | assign d_o[20] = (syndrome_o == 7'h68) ^ d_i[20]; 48 | assign d_o[21] = (syndrome_o == 7'h15) ^ d_i[21]; 49 | assign d_o[22] = (syndrome_o == 7'h2a) ^ d_i[22]; 50 | assign d_o[23] = (syndrome_o == 7'h49) ^ d_i[23]; 51 | assign d_o[24] = (syndrome_o == 7'h26) ^ d_i[24]; 52 | assign d_o[25] = (syndrome_o == 7'h52) ^ d_i[25]; 53 | assign d_o[26] = (syndrome_o == 7'h25) ^ d_i[26]; 54 | assign d_o[27] = (syndrome_o == 7'h19) ^ d_i[27]; 55 | assign d_o[28] = (syndrome_o == 7'h46) ^ d_i[28]; 56 | assign d_o[29] = (syndrome_o == 7'h29) ^ d_i[29]; 57 | assign d_o[30] = (syndrome_o == 7'h54) ^ d_i[30]; 58 | assign d_o[31] = (syndrome_o == 7'h4a) ^ d_i[31]; 59 | assign d_o[32] = (syndrome_o == 7'h1) ^ d_i[32]; 60 | assign d_o[33] = (syndrome_o == 7'h2) ^ d_i[33]; 61 | assign d_o[34] = (syndrome_o == 7'h4) ^ d_i[34]; 62 | assign d_o[35] = (syndrome_o == 7'h8) ^ d_i[35]; 63 | assign d_o[36] = (syndrome_o == 7'h10) ^ d_i[36]; 64 | assign d_o[37] = (syndrome_o == 7'h20) ^ d_i[37]; 65 | assign d_o[38] = (syndrome_o == 7'h40) ^ d_i[38]; 66 | 67 | // err_o calc. bit0: single error, bit1: double error 68 | assign single_error = ^syndrome_o; 69 | assign err_o[0] = single_error; 70 | assign err_o[1] = ~single_error & (|syndrome_o); 71 | 72 | endmodule : prim_secded_39_32_cor 73 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_39_32_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_39_32_dec ( 9 | input [38:0] in, 10 | output logic [31:0] d_o, 11 | output logic [6:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(in & 39'h012CA53295); 19 | assign syndrome_o[1] = ^(in & 39'h0293492CA5); 20 | assign syndrome_o[2] = ^(in & 39'h04552A5329); 21 | assign syndrome_o[3] = ^(in & 39'h08A8D294AA); 22 | assign syndrome_o[4] = ^(in & 39'h104A2CA54A); 23 | assign syndrome_o[5] = ^(in & 39'h2025534952); 24 | assign syndrome_o[6] = ^(in & 39'h40D294CA54); 25 | 26 | // Corrected output calculation 27 | assign d_o[0] = (syndrome_o == 7'h7) ^ in[0]; 28 | assign d_o[1] = (syndrome_o == 7'h38) ^ in[1]; 29 | assign d_o[2] = (syndrome_o == 7'h43) ^ in[2]; 30 | assign d_o[3] = (syndrome_o == 7'h1c) ^ in[3]; 31 | assign d_o[4] = (syndrome_o == 7'h61) ^ in[4]; 32 | assign d_o[5] = (syndrome_o == 7'he) ^ in[5]; 33 | assign d_o[6] = (syndrome_o == 7'h70) ^ in[6]; 34 | assign d_o[7] = (syndrome_o == 7'hb) ^ in[7]; 35 | assign d_o[8] = (syndrome_o == 7'h34) ^ in[8]; 36 | assign d_o[9] = (syndrome_o == 7'h45) ^ in[9]; 37 | assign d_o[10] = (syndrome_o == 7'h1a) ^ in[10]; 38 | assign d_o[11] = (syndrome_o == 7'h62) ^ in[11]; 39 | assign d_o[12] = (syndrome_o == 7'hd) ^ in[12]; 40 | assign d_o[13] = (syndrome_o == 7'h13) ^ in[13]; 41 | assign d_o[14] = (syndrome_o == 7'h64) ^ in[14]; 42 | assign d_o[15] = (syndrome_o == 7'h58) ^ in[15]; 43 | assign d_o[16] = (syndrome_o == 7'h23) ^ in[16]; 44 | assign d_o[17] = (syndrome_o == 7'h2c) ^ in[17]; 45 | assign d_o[18] = (syndrome_o == 7'h51) ^ in[18]; 46 | assign d_o[19] = (syndrome_o == 7'h16) ^ in[19]; 47 | assign d_o[20] = (syndrome_o == 7'h68) ^ in[20]; 48 | assign d_o[21] = (syndrome_o == 7'h15) ^ in[21]; 49 | assign d_o[22] = (syndrome_o == 7'h2a) ^ in[22]; 50 | assign d_o[23] = (syndrome_o == 7'h49) ^ in[23]; 51 | assign d_o[24] = (syndrome_o == 7'h26) ^ in[24]; 52 | assign d_o[25] = (syndrome_o == 7'h52) ^ in[25]; 53 | assign d_o[26] = (syndrome_o == 7'h25) ^ in[26]; 54 | assign d_o[27] = (syndrome_o == 7'h19) ^ in[27]; 55 | assign d_o[28] = (syndrome_o == 7'h46) ^ in[28]; 56 | assign d_o[29] = (syndrome_o == 7'h29) ^ in[29]; 57 | assign d_o[30] = (syndrome_o == 7'h54) ^ in[30]; 58 | assign d_o[31] = (syndrome_o == 7'h4a) ^ in[31]; 59 | 60 | // err_o calc. bit0: single error, bit1: double error 61 | assign single_error = ^syndrome_o; 62 | assign err_o[0] = single_error; 63 | assign err_o[1] = ~single_error & (|syndrome_o); 64 | 65 | endmodule : prim_secded_39_32_dec 66 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_39_32_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_39_32_enc ( 9 | input [31:0] in, 10 | output logic [38:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[31:0] = in; 15 | out[32] = ^(in & 32'h2CA53295); 16 | out[33] = ^(in & 32'h93492CA5); 17 | out[34] = ^(in & 32'h552A5329); 18 | out[35] = ^(in & 32'hA8D294AA); 19 | out[36] = ^(in & 32'h4A2CA54A); 20 | out[37] = ^(in & 32'h25534952); 21 | out[38] = ^(in & 32'hD294CA54); 22 | end 23 | 24 | endmodule : prim_secded_39_32_enc 25 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_64_57_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 7 -k 57 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_64_57_cor ( 9 | input [63:0] d_i, 10 | output logic [63:0] d_o, 11 | output logic [6:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(d_i & 64'h0303FFF800007FFF); 19 | assign syndrome_o[1] = ^(d_i & 64'h057C1FF801FF801F); 20 | assign syndrome_o[2] = ^(d_i & 64'h09BDE1F87E0781E1); 21 | assign syndrome_o[3] = ^(d_i & 64'h11DEEE3B8E388E22); 22 | assign syndrome_o[4] = ^(d_i & 64'h21EF76CDB2C93244); 23 | assign syndrome_o[5] = ^(d_i & 64'h41F7BB56D5525488); 24 | assign syndrome_o[6] = ^(d_i & 64'h81FBDDA769A46910); 25 | 26 | // Corrected output calculation 27 | assign d_o[0] = (syndrome_o == 7'h7) ^ d_i[0]; 28 | assign d_o[1] = (syndrome_o == 7'hb) ^ d_i[1]; 29 | assign d_o[2] = (syndrome_o == 7'h13) ^ d_i[2]; 30 | assign d_o[3] = (syndrome_o == 7'h23) ^ d_i[3]; 31 | assign d_o[4] = (syndrome_o == 7'h43) ^ d_i[4]; 32 | assign d_o[5] = (syndrome_o == 7'hd) ^ d_i[5]; 33 | assign d_o[6] = (syndrome_o == 7'h15) ^ d_i[6]; 34 | assign d_o[7] = (syndrome_o == 7'h25) ^ d_i[7]; 35 | assign d_o[8] = (syndrome_o == 7'h45) ^ d_i[8]; 36 | assign d_o[9] = (syndrome_o == 7'h19) ^ d_i[9]; 37 | assign d_o[10] = (syndrome_o == 7'h29) ^ d_i[10]; 38 | assign d_o[11] = (syndrome_o == 7'h49) ^ d_i[11]; 39 | assign d_o[12] = (syndrome_o == 7'h31) ^ d_i[12]; 40 | assign d_o[13] = (syndrome_o == 7'h51) ^ d_i[13]; 41 | assign d_o[14] = (syndrome_o == 7'h61) ^ d_i[14]; 42 | assign d_o[15] = (syndrome_o == 7'he) ^ d_i[15]; 43 | assign d_o[16] = (syndrome_o == 7'h16) ^ d_i[16]; 44 | assign d_o[17] = (syndrome_o == 7'h26) ^ d_i[17]; 45 | assign d_o[18] = (syndrome_o == 7'h46) ^ d_i[18]; 46 | assign d_o[19] = (syndrome_o == 7'h1a) ^ d_i[19]; 47 | assign d_o[20] = (syndrome_o == 7'h2a) ^ d_i[20]; 48 | assign d_o[21] = (syndrome_o == 7'h4a) ^ d_i[21]; 49 | assign d_o[22] = (syndrome_o == 7'h32) ^ d_i[22]; 50 | assign d_o[23] = (syndrome_o == 7'h52) ^ d_i[23]; 51 | assign d_o[24] = (syndrome_o == 7'h62) ^ d_i[24]; 52 | assign d_o[25] = (syndrome_o == 7'h1c) ^ d_i[25]; 53 | assign d_o[26] = (syndrome_o == 7'h2c) ^ d_i[26]; 54 | assign d_o[27] = (syndrome_o == 7'h4c) ^ d_i[27]; 55 | assign d_o[28] = (syndrome_o == 7'h34) ^ d_i[28]; 56 | assign d_o[29] = (syndrome_o == 7'h54) ^ d_i[29]; 57 | assign d_o[30] = (syndrome_o == 7'h64) ^ d_i[30]; 58 | assign d_o[31] = (syndrome_o == 7'h38) ^ d_i[31]; 59 | assign d_o[32] = (syndrome_o == 7'h58) ^ d_i[32]; 60 | assign d_o[33] = (syndrome_o == 7'h68) ^ d_i[33]; 61 | assign d_o[34] = (syndrome_o == 7'h70) ^ d_i[34]; 62 | assign d_o[35] = (syndrome_o == 7'h1f) ^ d_i[35]; 63 | assign d_o[36] = (syndrome_o == 7'h2f) ^ d_i[36]; 64 | assign d_o[37] = (syndrome_o == 7'h4f) ^ d_i[37]; 65 | assign d_o[38] = (syndrome_o == 7'h37) ^ d_i[38]; 66 | assign d_o[39] = (syndrome_o == 7'h57) ^ d_i[39]; 67 | assign d_o[40] = (syndrome_o == 7'h67) ^ d_i[40]; 68 | assign d_o[41] = (syndrome_o == 7'h3b) ^ d_i[41]; 69 | assign d_o[42] = (syndrome_o == 7'h5b) ^ d_i[42]; 70 | assign d_o[43] = (syndrome_o == 7'h6b) ^ d_i[43]; 71 | assign d_o[44] = (syndrome_o == 7'h73) ^ d_i[44]; 72 | assign d_o[45] = (syndrome_o == 7'h3d) ^ d_i[45]; 73 | assign d_o[46] = (syndrome_o == 7'h5d) ^ d_i[46]; 74 | assign d_o[47] = (syndrome_o == 7'h6d) ^ d_i[47]; 75 | assign d_o[48] = (syndrome_o == 7'h75) ^ d_i[48]; 76 | assign d_o[49] = (syndrome_o == 7'h79) ^ d_i[49]; 77 | assign d_o[50] = (syndrome_o == 7'h3e) ^ d_i[50]; 78 | assign d_o[51] = (syndrome_o == 7'h5e) ^ d_i[51]; 79 | assign d_o[52] = (syndrome_o == 7'h6e) ^ d_i[52]; 80 | assign d_o[53] = (syndrome_o == 7'h76) ^ d_i[53]; 81 | assign d_o[54] = (syndrome_o == 7'h7a) ^ d_i[54]; 82 | assign d_o[55] = (syndrome_o == 7'h7c) ^ d_i[55]; 83 | assign d_o[56] = (syndrome_o == 7'h7f) ^ d_i[56]; 84 | assign d_o[57] = (syndrome_o == 7'h1) ^ d_i[57]; 85 | assign d_o[58] = (syndrome_o == 7'h2) ^ d_i[58]; 86 | assign d_o[59] = (syndrome_o == 7'h4) ^ d_i[59]; 87 | assign d_o[60] = (syndrome_o == 7'h8) ^ d_i[60]; 88 | assign d_o[61] = (syndrome_o == 7'h10) ^ d_i[61]; 89 | assign d_o[62] = (syndrome_o == 7'h20) ^ d_i[62]; 90 | assign d_o[63] = (syndrome_o == 7'h40) ^ d_i[63]; 91 | 92 | // err_o calc. bit0: single error, bit1: double error 93 | assign single_error = ^syndrome_o; 94 | assign err_o[0] = single_error; 95 | assign err_o[1] = ~single_error & (|syndrome_o); 96 | 97 | endmodule : prim_secded_64_57_cor 98 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_64_57_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 7 -k 57 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_64_57_dec ( 9 | input [63:0] in, 10 | output logic [56:0] d_o, 11 | output logic [6:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(in & 64'h0303FFF800007FFF); 19 | assign syndrome_o[1] = ^(in & 64'h057C1FF801FF801F); 20 | assign syndrome_o[2] = ^(in & 64'h09BDE1F87E0781E1); 21 | assign syndrome_o[3] = ^(in & 64'h11DEEE3B8E388E22); 22 | assign syndrome_o[4] = ^(in & 64'h21EF76CDB2C93244); 23 | assign syndrome_o[5] = ^(in & 64'h41F7BB56D5525488); 24 | assign syndrome_o[6] = ^(in & 64'h81FBDDA769A46910); 25 | 26 | // Corrected output calculation 27 | assign d_o[0] = (syndrome_o == 7'h7) ^ in[0]; 28 | assign d_o[1] = (syndrome_o == 7'hb) ^ in[1]; 29 | assign d_o[2] = (syndrome_o == 7'h13) ^ in[2]; 30 | assign d_o[3] = (syndrome_o == 7'h23) ^ in[3]; 31 | assign d_o[4] = (syndrome_o == 7'h43) ^ in[4]; 32 | assign d_o[5] = (syndrome_o == 7'hd) ^ in[5]; 33 | assign d_o[6] = (syndrome_o == 7'h15) ^ in[6]; 34 | assign d_o[7] = (syndrome_o == 7'h25) ^ in[7]; 35 | assign d_o[8] = (syndrome_o == 7'h45) ^ in[8]; 36 | assign d_o[9] = (syndrome_o == 7'h19) ^ in[9]; 37 | assign d_o[10] = (syndrome_o == 7'h29) ^ in[10]; 38 | assign d_o[11] = (syndrome_o == 7'h49) ^ in[11]; 39 | assign d_o[12] = (syndrome_o == 7'h31) ^ in[12]; 40 | assign d_o[13] = (syndrome_o == 7'h51) ^ in[13]; 41 | assign d_o[14] = (syndrome_o == 7'h61) ^ in[14]; 42 | assign d_o[15] = (syndrome_o == 7'he) ^ in[15]; 43 | assign d_o[16] = (syndrome_o == 7'h16) ^ in[16]; 44 | assign d_o[17] = (syndrome_o == 7'h26) ^ in[17]; 45 | assign d_o[18] = (syndrome_o == 7'h46) ^ in[18]; 46 | assign d_o[19] = (syndrome_o == 7'h1a) ^ in[19]; 47 | assign d_o[20] = (syndrome_o == 7'h2a) ^ in[20]; 48 | assign d_o[21] = (syndrome_o == 7'h4a) ^ in[21]; 49 | assign d_o[22] = (syndrome_o == 7'h32) ^ in[22]; 50 | assign d_o[23] = (syndrome_o == 7'h52) ^ in[23]; 51 | assign d_o[24] = (syndrome_o == 7'h62) ^ in[24]; 52 | assign d_o[25] = (syndrome_o == 7'h1c) ^ in[25]; 53 | assign d_o[26] = (syndrome_o == 7'h2c) ^ in[26]; 54 | assign d_o[27] = (syndrome_o == 7'h4c) ^ in[27]; 55 | assign d_o[28] = (syndrome_o == 7'h34) ^ in[28]; 56 | assign d_o[29] = (syndrome_o == 7'h54) ^ in[29]; 57 | assign d_o[30] = (syndrome_o == 7'h64) ^ in[30]; 58 | assign d_o[31] = (syndrome_o == 7'h38) ^ in[31]; 59 | assign d_o[32] = (syndrome_o == 7'h58) ^ in[32]; 60 | assign d_o[33] = (syndrome_o == 7'h68) ^ in[33]; 61 | assign d_o[34] = (syndrome_o == 7'h70) ^ in[34]; 62 | assign d_o[35] = (syndrome_o == 7'h1f) ^ in[35]; 63 | assign d_o[36] = (syndrome_o == 7'h2f) ^ in[36]; 64 | assign d_o[37] = (syndrome_o == 7'h4f) ^ in[37]; 65 | assign d_o[38] = (syndrome_o == 7'h37) ^ in[38]; 66 | assign d_o[39] = (syndrome_o == 7'h57) ^ in[39]; 67 | assign d_o[40] = (syndrome_o == 7'h67) ^ in[40]; 68 | assign d_o[41] = (syndrome_o == 7'h3b) ^ in[41]; 69 | assign d_o[42] = (syndrome_o == 7'h5b) ^ in[42]; 70 | assign d_o[43] = (syndrome_o == 7'h6b) ^ in[43]; 71 | assign d_o[44] = (syndrome_o == 7'h73) ^ in[44]; 72 | assign d_o[45] = (syndrome_o == 7'h3d) ^ in[45]; 73 | assign d_o[46] = (syndrome_o == 7'h5d) ^ in[46]; 74 | assign d_o[47] = (syndrome_o == 7'h6d) ^ in[47]; 75 | assign d_o[48] = (syndrome_o == 7'h75) ^ in[48]; 76 | assign d_o[49] = (syndrome_o == 7'h79) ^ in[49]; 77 | assign d_o[50] = (syndrome_o == 7'h3e) ^ in[50]; 78 | assign d_o[51] = (syndrome_o == 7'h5e) ^ in[51]; 79 | assign d_o[52] = (syndrome_o == 7'h6e) ^ in[52]; 80 | assign d_o[53] = (syndrome_o == 7'h76) ^ in[53]; 81 | assign d_o[54] = (syndrome_o == 7'h7a) ^ in[54]; 82 | assign d_o[55] = (syndrome_o == 7'h7c) ^ in[55]; 83 | assign d_o[56] = (syndrome_o == 7'h7f) ^ in[56]; 84 | 85 | // err_o calc. bit0: single error, bit1: double error 86 | assign single_error = ^syndrome_o; 87 | assign err_o[0] = single_error; 88 | assign err_o[1] = ~single_error & (|syndrome_o); 89 | 90 | endmodule : prim_secded_64_57_dec 91 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_64_57_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 7 -k 57 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_64_57_enc ( 9 | input [56:0] in, 10 | output logic [63:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[56:0] = in; 15 | out[57] = ^(in & 57'h103FFF800007FFF); 16 | out[58] = ^(in & 57'h17C1FF801FF801F); 17 | out[59] = ^(in & 57'h1BDE1F87E0781E1); 18 | out[60] = ^(in & 57'h1DEEE3B8E388E22); 19 | out[61] = ^(in & 57'h1EF76CDB2C93244); 20 | out[62] = ^(in & 57'h1F7BB56D5525488); 21 | out[63] = ^(in & 57'h1FBDDA769A46910); 22 | end 23 | 24 | endmodule : prim_secded_64_57_enc 25 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_72_64_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_72_64_cor ( 9 | input [71:0] d_i, 10 | output logic [71:0] d_o, 11 | output logic [7:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(d_i & 72'h015B000000001FFFFF); 19 | assign syndrome_o[1] = ^(d_i & 72'h026B00000FFFE0003F); 20 | assign syndrome_o[2] = ^(d_i & 72'h046D003FF003E007C1); 21 | assign syndrome_o[3] = ^(d_i & 72'h08AD0FC0F03C207842); 22 | assign syndrome_o[4] = ^(d_i & 72'h10B571C711C4438884); 23 | assign syndrome_o[5] = ^(d_i & 72'h20B6B65926488C9108); 24 | assign syndrome_o[6] = ^(d_i & 72'h40D6DAAA4A91152210); 25 | assign syndrome_o[7] = ^(d_i & 72'h80DAED348D221A4420); 26 | 27 | // Corrected output calculation 28 | assign d_o[0] = (syndrome_o == 8'h7) ^ d_i[0]; 29 | assign d_o[1] = (syndrome_o == 8'hb) ^ d_i[1]; 30 | assign d_o[2] = (syndrome_o == 8'h13) ^ d_i[2]; 31 | assign d_o[3] = (syndrome_o == 8'h23) ^ d_i[3]; 32 | assign d_o[4] = (syndrome_o == 8'h43) ^ d_i[4]; 33 | assign d_o[5] = (syndrome_o == 8'h83) ^ d_i[5]; 34 | assign d_o[6] = (syndrome_o == 8'hd) ^ d_i[6]; 35 | assign d_o[7] = (syndrome_o == 8'h15) ^ d_i[7]; 36 | assign d_o[8] = (syndrome_o == 8'h25) ^ d_i[8]; 37 | assign d_o[9] = (syndrome_o == 8'h45) ^ d_i[9]; 38 | assign d_o[10] = (syndrome_o == 8'h85) ^ d_i[10]; 39 | assign d_o[11] = (syndrome_o == 8'h19) ^ d_i[11]; 40 | assign d_o[12] = (syndrome_o == 8'h29) ^ d_i[12]; 41 | assign d_o[13] = (syndrome_o == 8'h49) ^ d_i[13]; 42 | assign d_o[14] = (syndrome_o == 8'h89) ^ d_i[14]; 43 | assign d_o[15] = (syndrome_o == 8'h31) ^ d_i[15]; 44 | assign d_o[16] = (syndrome_o == 8'h51) ^ d_i[16]; 45 | assign d_o[17] = (syndrome_o == 8'h91) ^ d_i[17]; 46 | assign d_o[18] = (syndrome_o == 8'h61) ^ d_i[18]; 47 | assign d_o[19] = (syndrome_o == 8'ha1) ^ d_i[19]; 48 | assign d_o[20] = (syndrome_o == 8'hc1) ^ d_i[20]; 49 | assign d_o[21] = (syndrome_o == 8'he) ^ d_i[21]; 50 | assign d_o[22] = (syndrome_o == 8'h16) ^ d_i[22]; 51 | assign d_o[23] = (syndrome_o == 8'h26) ^ d_i[23]; 52 | assign d_o[24] = (syndrome_o == 8'h46) ^ d_i[24]; 53 | assign d_o[25] = (syndrome_o == 8'h86) ^ d_i[25]; 54 | assign d_o[26] = (syndrome_o == 8'h1a) ^ d_i[26]; 55 | assign d_o[27] = (syndrome_o == 8'h2a) ^ d_i[27]; 56 | assign d_o[28] = (syndrome_o == 8'h4a) ^ d_i[28]; 57 | assign d_o[29] = (syndrome_o == 8'h8a) ^ d_i[29]; 58 | assign d_o[30] = (syndrome_o == 8'h32) ^ d_i[30]; 59 | assign d_o[31] = (syndrome_o == 8'h52) ^ d_i[31]; 60 | assign d_o[32] = (syndrome_o == 8'h92) ^ d_i[32]; 61 | assign d_o[33] = (syndrome_o == 8'h62) ^ d_i[33]; 62 | assign d_o[34] = (syndrome_o == 8'ha2) ^ d_i[34]; 63 | assign d_o[35] = (syndrome_o == 8'hc2) ^ d_i[35]; 64 | assign d_o[36] = (syndrome_o == 8'h1c) ^ d_i[36]; 65 | assign d_o[37] = (syndrome_o == 8'h2c) ^ d_i[37]; 66 | assign d_o[38] = (syndrome_o == 8'h4c) ^ d_i[38]; 67 | assign d_o[39] = (syndrome_o == 8'h8c) ^ d_i[39]; 68 | assign d_o[40] = (syndrome_o == 8'h34) ^ d_i[40]; 69 | assign d_o[41] = (syndrome_o == 8'h54) ^ d_i[41]; 70 | assign d_o[42] = (syndrome_o == 8'h94) ^ d_i[42]; 71 | assign d_o[43] = (syndrome_o == 8'h64) ^ d_i[43]; 72 | assign d_o[44] = (syndrome_o == 8'ha4) ^ d_i[44]; 73 | assign d_o[45] = (syndrome_o == 8'hc4) ^ d_i[45]; 74 | assign d_o[46] = (syndrome_o == 8'h38) ^ d_i[46]; 75 | assign d_o[47] = (syndrome_o == 8'h58) ^ d_i[47]; 76 | assign d_o[48] = (syndrome_o == 8'h98) ^ d_i[48]; 77 | assign d_o[49] = (syndrome_o == 8'h68) ^ d_i[49]; 78 | assign d_o[50] = (syndrome_o == 8'ha8) ^ d_i[50]; 79 | assign d_o[51] = (syndrome_o == 8'hc8) ^ d_i[51]; 80 | assign d_o[52] = (syndrome_o == 8'h70) ^ d_i[52]; 81 | assign d_o[53] = (syndrome_o == 8'hb0) ^ d_i[53]; 82 | assign d_o[54] = (syndrome_o == 8'hd0) ^ d_i[54]; 83 | assign d_o[55] = (syndrome_o == 8'he0) ^ d_i[55]; 84 | assign d_o[56] = (syndrome_o == 8'h1f) ^ d_i[56]; 85 | assign d_o[57] = (syndrome_o == 8'he3) ^ d_i[57]; 86 | assign d_o[58] = (syndrome_o == 8'h7c) ^ d_i[58]; 87 | assign d_o[59] = (syndrome_o == 8'h8f) ^ d_i[59]; 88 | assign d_o[60] = (syndrome_o == 8'hf1) ^ d_i[60]; 89 | assign d_o[61] = (syndrome_o == 8'h3e) ^ d_i[61]; 90 | assign d_o[62] = (syndrome_o == 8'hc7) ^ d_i[62]; 91 | assign d_o[63] = (syndrome_o == 8'hf8) ^ d_i[63]; 92 | assign d_o[64] = (syndrome_o == 8'h1) ^ d_i[64]; 93 | assign d_o[65] = (syndrome_o == 8'h2) ^ d_i[65]; 94 | assign d_o[66] = (syndrome_o == 8'h4) ^ d_i[66]; 95 | assign d_o[67] = (syndrome_o == 8'h8) ^ d_i[67]; 96 | assign d_o[68] = (syndrome_o == 8'h10) ^ d_i[68]; 97 | assign d_o[69] = (syndrome_o == 8'h20) ^ d_i[69]; 98 | assign d_o[70] = (syndrome_o == 8'h40) ^ d_i[70]; 99 | assign d_o[71] = (syndrome_o == 8'h80) ^ d_i[71]; 100 | 101 | // err_o calc. bit0: single error, bit1: double error 102 | assign single_error = ^syndrome_o; 103 | assign err_o[0] = single_error; 104 | assign err_o[1] = ~single_error & (|syndrome_o); 105 | 106 | endmodule : prim_secded_72_64_cor 107 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_72_64_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_72_64_dec ( 9 | input [71:0] in, 10 | output logic [63:0] d_o, 11 | output logic [7:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | logic single_error; 16 | 17 | // Syndrome calculation 18 | assign syndrome_o[0] = ^(in & 72'h015B000000001FFFFF); 19 | assign syndrome_o[1] = ^(in & 72'h026B00000FFFE0003F); 20 | assign syndrome_o[2] = ^(in & 72'h046D003FF003E007C1); 21 | assign syndrome_o[3] = ^(in & 72'h08AD0FC0F03C207842); 22 | assign syndrome_o[4] = ^(in & 72'h10B571C711C4438884); 23 | assign syndrome_o[5] = ^(in & 72'h20B6B65926488C9108); 24 | assign syndrome_o[6] = ^(in & 72'h40D6DAAA4A91152210); 25 | assign syndrome_o[7] = ^(in & 72'h80DAED348D221A4420); 26 | 27 | // Corrected output calculation 28 | assign d_o[0] = (syndrome_o == 8'h7) ^ in[0]; 29 | assign d_o[1] = (syndrome_o == 8'hb) ^ in[1]; 30 | assign d_o[2] = (syndrome_o == 8'h13) ^ in[2]; 31 | assign d_o[3] = (syndrome_o == 8'h23) ^ in[3]; 32 | assign d_o[4] = (syndrome_o == 8'h43) ^ in[4]; 33 | assign d_o[5] = (syndrome_o == 8'h83) ^ in[5]; 34 | assign d_o[6] = (syndrome_o == 8'hd) ^ in[6]; 35 | assign d_o[7] = (syndrome_o == 8'h15) ^ in[7]; 36 | assign d_o[8] = (syndrome_o == 8'h25) ^ in[8]; 37 | assign d_o[9] = (syndrome_o == 8'h45) ^ in[9]; 38 | assign d_o[10] = (syndrome_o == 8'h85) ^ in[10]; 39 | assign d_o[11] = (syndrome_o == 8'h19) ^ in[11]; 40 | assign d_o[12] = (syndrome_o == 8'h29) ^ in[12]; 41 | assign d_o[13] = (syndrome_o == 8'h49) ^ in[13]; 42 | assign d_o[14] = (syndrome_o == 8'h89) ^ in[14]; 43 | assign d_o[15] = (syndrome_o == 8'h31) ^ in[15]; 44 | assign d_o[16] = (syndrome_o == 8'h51) ^ in[16]; 45 | assign d_o[17] = (syndrome_o == 8'h91) ^ in[17]; 46 | assign d_o[18] = (syndrome_o == 8'h61) ^ in[18]; 47 | assign d_o[19] = (syndrome_o == 8'ha1) ^ in[19]; 48 | assign d_o[20] = (syndrome_o == 8'hc1) ^ in[20]; 49 | assign d_o[21] = (syndrome_o == 8'he) ^ in[21]; 50 | assign d_o[22] = (syndrome_o == 8'h16) ^ in[22]; 51 | assign d_o[23] = (syndrome_o == 8'h26) ^ in[23]; 52 | assign d_o[24] = (syndrome_o == 8'h46) ^ in[24]; 53 | assign d_o[25] = (syndrome_o == 8'h86) ^ in[25]; 54 | assign d_o[26] = (syndrome_o == 8'h1a) ^ in[26]; 55 | assign d_o[27] = (syndrome_o == 8'h2a) ^ in[27]; 56 | assign d_o[28] = (syndrome_o == 8'h4a) ^ in[28]; 57 | assign d_o[29] = (syndrome_o == 8'h8a) ^ in[29]; 58 | assign d_o[30] = (syndrome_o == 8'h32) ^ in[30]; 59 | assign d_o[31] = (syndrome_o == 8'h52) ^ in[31]; 60 | assign d_o[32] = (syndrome_o == 8'h92) ^ in[32]; 61 | assign d_o[33] = (syndrome_o == 8'h62) ^ in[33]; 62 | assign d_o[34] = (syndrome_o == 8'ha2) ^ in[34]; 63 | assign d_o[35] = (syndrome_o == 8'hc2) ^ in[35]; 64 | assign d_o[36] = (syndrome_o == 8'h1c) ^ in[36]; 65 | assign d_o[37] = (syndrome_o == 8'h2c) ^ in[37]; 66 | assign d_o[38] = (syndrome_o == 8'h4c) ^ in[38]; 67 | assign d_o[39] = (syndrome_o == 8'h8c) ^ in[39]; 68 | assign d_o[40] = (syndrome_o == 8'h34) ^ in[40]; 69 | assign d_o[41] = (syndrome_o == 8'h54) ^ in[41]; 70 | assign d_o[42] = (syndrome_o == 8'h94) ^ in[42]; 71 | assign d_o[43] = (syndrome_o == 8'h64) ^ in[43]; 72 | assign d_o[44] = (syndrome_o == 8'ha4) ^ in[44]; 73 | assign d_o[45] = (syndrome_o == 8'hc4) ^ in[45]; 74 | assign d_o[46] = (syndrome_o == 8'h38) ^ in[46]; 75 | assign d_o[47] = (syndrome_o == 8'h58) ^ in[47]; 76 | assign d_o[48] = (syndrome_o == 8'h98) ^ in[48]; 77 | assign d_o[49] = (syndrome_o == 8'h68) ^ in[49]; 78 | assign d_o[50] = (syndrome_o == 8'ha8) ^ in[50]; 79 | assign d_o[51] = (syndrome_o == 8'hc8) ^ in[51]; 80 | assign d_o[52] = (syndrome_o == 8'h70) ^ in[52]; 81 | assign d_o[53] = (syndrome_o == 8'hb0) ^ in[53]; 82 | assign d_o[54] = (syndrome_o == 8'hd0) ^ in[54]; 83 | assign d_o[55] = (syndrome_o == 8'he0) ^ in[55]; 84 | assign d_o[56] = (syndrome_o == 8'h1f) ^ in[56]; 85 | assign d_o[57] = (syndrome_o == 8'he3) ^ in[57]; 86 | assign d_o[58] = (syndrome_o == 8'h7c) ^ in[58]; 87 | assign d_o[59] = (syndrome_o == 8'h8f) ^ in[59]; 88 | assign d_o[60] = (syndrome_o == 8'hf1) ^ in[60]; 89 | assign d_o[61] = (syndrome_o == 8'h3e) ^ in[61]; 90 | assign d_o[62] = (syndrome_o == 8'hc7) ^ in[62]; 91 | assign d_o[63] = (syndrome_o == 8'hf8) ^ in[63]; 92 | 93 | // err_o calc. bit0: single error, bit1: double error 94 | assign single_error = ^syndrome_o; 95 | assign err_o[0] = single_error; 96 | assign err_o[1] = ~single_error & (|syndrome_o); 97 | 98 | endmodule : prim_secded_72_64_dec 99 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_72_64_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hsiao 7 | 8 | module prim_secded_72_64_enc ( 9 | input [63:0] in, 10 | output logic [71:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[63:0] = in; 15 | out[64] = ^(in & 64'h5B000000001FFFFF); 16 | out[65] = ^(in & 64'h6B00000FFFE0003F); 17 | out[66] = ^(in & 64'h6D003FF003E007C1); 18 | out[67] = ^(in & 64'hAD0FC0F03C207842); 19 | out[68] = ^(in & 64'hB571C711C4438884); 20 | out[69] = ^(in & 64'hB6B65926488C9108); 21 | out[70] = ^(in & 64'hD6DAAA4A91152210); 22 | out[71] = ^(in & 64'hDAED348D221A4420); 23 | end 24 | 25 | endmodule : prim_secded_72_64_enc 26 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_22_16_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_22_16_cor ( 9 | input [21:0] d_i, 10 | output logic [21:0] d_o, 11 | output logic [5:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | 16 | // Syndrome calculation 17 | assign syndrome_o[0] = ^(d_i & 22'h01AD5B); 18 | assign syndrome_o[1] = ^(d_i & 22'h02366D); 19 | assign syndrome_o[2] = ^(d_i & 22'h04C78E); 20 | assign syndrome_o[3] = ^(d_i & 22'h0807F0); 21 | assign syndrome_o[4] = ^(d_i & 22'h10F800); 22 | assign syndrome_o[5] = ^(d_i & 22'h205CB7); 23 | 24 | // Corrected output calculation 25 | assign d_o[0] = (syndrome_o == 6'h23) ^ d_i[0]; 26 | assign d_o[1] = (syndrome_o == 6'h25) ^ d_i[1]; 27 | assign d_o[2] = (syndrome_o == 6'h26) ^ d_i[2]; 28 | assign d_o[3] = (syndrome_o == 6'h7) ^ d_i[3]; 29 | assign d_o[4] = (syndrome_o == 6'h29) ^ d_i[4]; 30 | assign d_o[5] = (syndrome_o == 6'h2a) ^ d_i[5]; 31 | assign d_o[6] = (syndrome_o == 6'hb) ^ d_i[6]; 32 | assign d_o[7] = (syndrome_o == 6'h2c) ^ d_i[7]; 33 | assign d_o[8] = (syndrome_o == 6'hd) ^ d_i[8]; 34 | assign d_o[9] = (syndrome_o == 6'he) ^ d_i[9]; 35 | assign d_o[10] = (syndrome_o == 6'h2f) ^ d_i[10]; 36 | assign d_o[11] = (syndrome_o == 6'h31) ^ d_i[11]; 37 | assign d_o[12] = (syndrome_o == 6'h32) ^ d_i[12]; 38 | assign d_o[13] = (syndrome_o == 6'h13) ^ d_i[13]; 39 | assign d_o[14] = (syndrome_o == 6'h34) ^ d_i[14]; 40 | assign d_o[15] = (syndrome_o == 6'h15) ^ d_i[15]; 41 | assign d_o[16] = (syndrome_o == 6'h1) ^ d_i[16]; 42 | assign d_o[17] = (syndrome_o == 6'h2) ^ d_i[17]; 43 | assign d_o[18] = (syndrome_o == 6'h4) ^ d_i[18]; 44 | assign d_o[19] = (syndrome_o == 6'h8) ^ d_i[19]; 45 | assign d_o[20] = (syndrome_o == 6'h10) ^ d_i[20]; 46 | assign d_o[21] = (syndrome_o == 6'h20) ^ d_i[21]; 47 | 48 | // err_o calc. bit0: single error, bit1: double error 49 | assign err_o[0] = syndrome_o[5]; 50 | assign err_o[1] = |syndrome_o[4:0] & ~syndrome_o[5]; 51 | 52 | endmodule : prim_secded_hamming_22_16_cor 53 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_22_16_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_22_16_dec ( 9 | input [21:0] in, 10 | output logic [15:0] d_o, 11 | output logic [5:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | 16 | // Syndrome calculation 17 | assign syndrome_o[0] = ^(in & 22'h01AD5B); 18 | assign syndrome_o[1] = ^(in & 22'h02366D); 19 | assign syndrome_o[2] = ^(in & 22'h04C78E); 20 | assign syndrome_o[3] = ^(in & 22'h0807F0); 21 | assign syndrome_o[4] = ^(in & 22'h10F800); 22 | assign syndrome_o[5] = ^(in & 22'h205CB7); 23 | 24 | // Corrected output calculation 25 | assign d_o[0] = (syndrome_o == 6'h23) ^ in[0]; 26 | assign d_o[1] = (syndrome_o == 6'h25) ^ in[1]; 27 | assign d_o[2] = (syndrome_o == 6'h26) ^ in[2]; 28 | assign d_o[3] = (syndrome_o == 6'h7) ^ in[3]; 29 | assign d_o[4] = (syndrome_o == 6'h29) ^ in[4]; 30 | assign d_o[5] = (syndrome_o == 6'h2a) ^ in[5]; 31 | assign d_o[6] = (syndrome_o == 6'hb) ^ in[6]; 32 | assign d_o[7] = (syndrome_o == 6'h2c) ^ in[7]; 33 | assign d_o[8] = (syndrome_o == 6'hd) ^ in[8]; 34 | assign d_o[9] = (syndrome_o == 6'he) ^ in[9]; 35 | assign d_o[10] = (syndrome_o == 6'h2f) ^ in[10]; 36 | assign d_o[11] = (syndrome_o == 6'h31) ^ in[11]; 37 | assign d_o[12] = (syndrome_o == 6'h32) ^ in[12]; 38 | assign d_o[13] = (syndrome_o == 6'h13) ^ in[13]; 39 | assign d_o[14] = (syndrome_o == 6'h34) ^ in[14]; 40 | assign d_o[15] = (syndrome_o == 6'h15) ^ in[15]; 41 | 42 | // err_o calc. bit0: single error, bit1: double error 43 | assign err_o[0] = syndrome_o[5]; 44 | assign err_o[1] = |syndrome_o[4:0] & ~syndrome_o[5]; 45 | 46 | endmodule : prim_secded_hamming_22_16_dec 47 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_22_16_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 6 -k 16 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_22_16_enc ( 9 | input [15:0] in, 10 | output logic [21:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[15:0] = in; 15 | out[16] = ^(in & 16'hAD5B); 16 | out[17] = ^(in & 16'h366D); 17 | out[18] = ^(in & 16'hC78E); 18 | out[19] = ^(in & 16'h07F0); 19 | out[20] = ^(in & 16'hF800); 20 | out[21] = ^(in & 16'h5CB7); 21 | end 22 | 23 | endmodule : prim_secded_hamming_22_16_enc 24 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_39_32_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_39_32_cor ( 9 | input [38:0] d_i, 10 | output logic [38:0] d_o, 11 | output logic [6:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | 16 | // Syndrome calculation 17 | assign syndrome_o[0] = ^(d_i & 39'h0156AAAD5B); 18 | assign syndrome_o[1] = ^(d_i & 39'h029B33366D); 19 | assign syndrome_o[2] = ^(d_i & 39'h04E3C3C78E); 20 | assign syndrome_o[3] = ^(d_i & 39'h0803FC07F0); 21 | assign syndrome_o[4] = ^(d_i & 39'h1003FFF800); 22 | assign syndrome_o[5] = ^(d_i & 39'h20FC000000); 23 | assign syndrome_o[6] = ^(d_i & 39'h402DA65CB7); 24 | 25 | // Corrected output calculation 26 | assign d_o[0] = (syndrome_o == 7'h43) ^ d_i[0]; 27 | assign d_o[1] = (syndrome_o == 7'h45) ^ d_i[1]; 28 | assign d_o[2] = (syndrome_o == 7'h46) ^ d_i[2]; 29 | assign d_o[3] = (syndrome_o == 7'h7) ^ d_i[3]; 30 | assign d_o[4] = (syndrome_o == 7'h49) ^ d_i[4]; 31 | assign d_o[5] = (syndrome_o == 7'h4a) ^ d_i[5]; 32 | assign d_o[6] = (syndrome_o == 7'hb) ^ d_i[6]; 33 | assign d_o[7] = (syndrome_o == 7'h4c) ^ d_i[7]; 34 | assign d_o[8] = (syndrome_o == 7'hd) ^ d_i[8]; 35 | assign d_o[9] = (syndrome_o == 7'he) ^ d_i[9]; 36 | assign d_o[10] = (syndrome_o == 7'h4f) ^ d_i[10]; 37 | assign d_o[11] = (syndrome_o == 7'h51) ^ d_i[11]; 38 | assign d_o[12] = (syndrome_o == 7'h52) ^ d_i[12]; 39 | assign d_o[13] = (syndrome_o == 7'h13) ^ d_i[13]; 40 | assign d_o[14] = (syndrome_o == 7'h54) ^ d_i[14]; 41 | assign d_o[15] = (syndrome_o == 7'h15) ^ d_i[15]; 42 | assign d_o[16] = (syndrome_o == 7'h16) ^ d_i[16]; 43 | assign d_o[17] = (syndrome_o == 7'h57) ^ d_i[17]; 44 | assign d_o[18] = (syndrome_o == 7'h58) ^ d_i[18]; 45 | assign d_o[19] = (syndrome_o == 7'h19) ^ d_i[19]; 46 | assign d_o[20] = (syndrome_o == 7'h1a) ^ d_i[20]; 47 | assign d_o[21] = (syndrome_o == 7'h5b) ^ d_i[21]; 48 | assign d_o[22] = (syndrome_o == 7'h1c) ^ d_i[22]; 49 | assign d_o[23] = (syndrome_o == 7'h5d) ^ d_i[23]; 50 | assign d_o[24] = (syndrome_o == 7'h5e) ^ d_i[24]; 51 | assign d_o[25] = (syndrome_o == 7'h1f) ^ d_i[25]; 52 | assign d_o[26] = (syndrome_o == 7'h61) ^ d_i[26]; 53 | assign d_o[27] = (syndrome_o == 7'h62) ^ d_i[27]; 54 | assign d_o[28] = (syndrome_o == 7'h23) ^ d_i[28]; 55 | assign d_o[29] = (syndrome_o == 7'h64) ^ d_i[29]; 56 | assign d_o[30] = (syndrome_o == 7'h25) ^ d_i[30]; 57 | assign d_o[31] = (syndrome_o == 7'h26) ^ d_i[31]; 58 | assign d_o[32] = (syndrome_o == 7'h1) ^ d_i[32]; 59 | assign d_o[33] = (syndrome_o == 7'h2) ^ d_i[33]; 60 | assign d_o[34] = (syndrome_o == 7'h4) ^ d_i[34]; 61 | assign d_o[35] = (syndrome_o == 7'h8) ^ d_i[35]; 62 | assign d_o[36] = (syndrome_o == 7'h10) ^ d_i[36]; 63 | assign d_o[37] = (syndrome_o == 7'h20) ^ d_i[37]; 64 | assign d_o[38] = (syndrome_o == 7'h40) ^ d_i[38]; 65 | 66 | // err_o calc. bit0: single error, bit1: double error 67 | assign err_o[0] = syndrome_o[6]; 68 | assign err_o[1] = |syndrome_o[5:0] & ~syndrome_o[6]; 69 | 70 | endmodule : prim_secded_hamming_39_32_cor 71 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_39_32_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_39_32_dec ( 9 | input [38:0] in, 10 | output logic [31:0] d_o, 11 | output logic [6:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | 16 | // Syndrome calculation 17 | assign syndrome_o[0] = ^(in & 39'h0156AAAD5B); 18 | assign syndrome_o[1] = ^(in & 39'h029B33366D); 19 | assign syndrome_o[2] = ^(in & 39'h04E3C3C78E); 20 | assign syndrome_o[3] = ^(in & 39'h0803FC07F0); 21 | assign syndrome_o[4] = ^(in & 39'h1003FFF800); 22 | assign syndrome_o[5] = ^(in & 39'h20FC000000); 23 | assign syndrome_o[6] = ^(in & 39'h402DA65CB7); 24 | 25 | // Corrected output calculation 26 | assign d_o[0] = (syndrome_o == 7'h43) ^ in[0]; 27 | assign d_o[1] = (syndrome_o == 7'h45) ^ in[1]; 28 | assign d_o[2] = (syndrome_o == 7'h46) ^ in[2]; 29 | assign d_o[3] = (syndrome_o == 7'h7) ^ in[3]; 30 | assign d_o[4] = (syndrome_o == 7'h49) ^ in[4]; 31 | assign d_o[5] = (syndrome_o == 7'h4a) ^ in[5]; 32 | assign d_o[6] = (syndrome_o == 7'hb) ^ in[6]; 33 | assign d_o[7] = (syndrome_o == 7'h4c) ^ in[7]; 34 | assign d_o[8] = (syndrome_o == 7'hd) ^ in[8]; 35 | assign d_o[9] = (syndrome_o == 7'he) ^ in[9]; 36 | assign d_o[10] = (syndrome_o == 7'h4f) ^ in[10]; 37 | assign d_o[11] = (syndrome_o == 7'h51) ^ in[11]; 38 | assign d_o[12] = (syndrome_o == 7'h52) ^ in[12]; 39 | assign d_o[13] = (syndrome_o == 7'h13) ^ in[13]; 40 | assign d_o[14] = (syndrome_o == 7'h54) ^ in[14]; 41 | assign d_o[15] = (syndrome_o == 7'h15) ^ in[15]; 42 | assign d_o[16] = (syndrome_o == 7'h16) ^ in[16]; 43 | assign d_o[17] = (syndrome_o == 7'h57) ^ in[17]; 44 | assign d_o[18] = (syndrome_o == 7'h58) ^ in[18]; 45 | assign d_o[19] = (syndrome_o == 7'h19) ^ in[19]; 46 | assign d_o[20] = (syndrome_o == 7'h1a) ^ in[20]; 47 | assign d_o[21] = (syndrome_o == 7'h5b) ^ in[21]; 48 | assign d_o[22] = (syndrome_o == 7'h1c) ^ in[22]; 49 | assign d_o[23] = (syndrome_o == 7'h5d) ^ in[23]; 50 | assign d_o[24] = (syndrome_o == 7'h5e) ^ in[24]; 51 | assign d_o[25] = (syndrome_o == 7'h1f) ^ in[25]; 52 | assign d_o[26] = (syndrome_o == 7'h61) ^ in[26]; 53 | assign d_o[27] = (syndrome_o == 7'h62) ^ in[27]; 54 | assign d_o[28] = (syndrome_o == 7'h23) ^ in[28]; 55 | assign d_o[29] = (syndrome_o == 7'h64) ^ in[29]; 56 | assign d_o[30] = (syndrome_o == 7'h25) ^ in[30]; 57 | assign d_o[31] = (syndrome_o == 7'h26) ^ in[31]; 58 | 59 | // err_o calc. bit0: single error, bit1: double error 60 | assign err_o[0] = syndrome_o[6]; 61 | assign err_o[1] = |syndrome_o[5:0] & ~syndrome_o[6]; 62 | 63 | endmodule : prim_secded_hamming_39_32_dec 64 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_39_32_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 7 -k 32 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_39_32_enc ( 9 | input [31:0] in, 10 | output logic [38:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[31:0] = in; 15 | out[32] = ^(in & 32'h56AAAD5B); 16 | out[33] = ^(in & 32'h9B33366D); 17 | out[34] = ^(in & 32'hE3C3C78E); 18 | out[35] = ^(in & 32'h03FC07F0); 19 | out[36] = ^(in & 32'h03FFF800); 20 | out[37] = ^(in & 32'hFC000000); 21 | out[38] = ^(in & 32'h2DA65CB7); 22 | end 23 | 24 | endmodule : prim_secded_hamming_39_32_enc 25 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_72_64_cor.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Corrector generated by 6 | // util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_72_64_cor ( 9 | input [71:0] d_i, 10 | output logic [71:0] d_o, 11 | output logic [7:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | 16 | // Syndrome calculation 17 | assign syndrome_o[0] = ^(d_i & 72'h01AB55555556AAAD5B); 18 | assign syndrome_o[1] = ^(d_i & 72'h02CD9999999B33366D); 19 | assign syndrome_o[2] = ^(d_i & 72'h04F1E1E1E1E3C3C78E); 20 | assign syndrome_o[3] = ^(d_i & 72'h0801FE01FE03FC07F0); 21 | assign syndrome_o[4] = ^(d_i & 72'h1001FFFE0003FFF800); 22 | assign syndrome_o[5] = ^(d_i & 72'h2001FFFFFFFC000000); 23 | assign syndrome_o[6] = ^(d_i & 72'h40FE00000000000000); 24 | assign syndrome_o[7] = ^(d_i & 72'h80972CD2D32DA65CB7); 25 | 26 | // Corrected output calculation 27 | assign d_o[0] = (syndrome_o == 8'h83) ^ d_i[0]; 28 | assign d_o[1] = (syndrome_o == 8'h85) ^ d_i[1]; 29 | assign d_o[2] = (syndrome_o == 8'h86) ^ d_i[2]; 30 | assign d_o[3] = (syndrome_o == 8'h7) ^ d_i[3]; 31 | assign d_o[4] = (syndrome_o == 8'h89) ^ d_i[4]; 32 | assign d_o[5] = (syndrome_o == 8'h8a) ^ d_i[5]; 33 | assign d_o[6] = (syndrome_o == 8'hb) ^ d_i[6]; 34 | assign d_o[7] = (syndrome_o == 8'h8c) ^ d_i[7]; 35 | assign d_o[8] = (syndrome_o == 8'hd) ^ d_i[8]; 36 | assign d_o[9] = (syndrome_o == 8'he) ^ d_i[9]; 37 | assign d_o[10] = (syndrome_o == 8'h8f) ^ d_i[10]; 38 | assign d_o[11] = (syndrome_o == 8'h91) ^ d_i[11]; 39 | assign d_o[12] = (syndrome_o == 8'h92) ^ d_i[12]; 40 | assign d_o[13] = (syndrome_o == 8'h13) ^ d_i[13]; 41 | assign d_o[14] = (syndrome_o == 8'h94) ^ d_i[14]; 42 | assign d_o[15] = (syndrome_o == 8'h15) ^ d_i[15]; 43 | assign d_o[16] = (syndrome_o == 8'h16) ^ d_i[16]; 44 | assign d_o[17] = (syndrome_o == 8'h97) ^ d_i[17]; 45 | assign d_o[18] = (syndrome_o == 8'h98) ^ d_i[18]; 46 | assign d_o[19] = (syndrome_o == 8'h19) ^ d_i[19]; 47 | assign d_o[20] = (syndrome_o == 8'h1a) ^ d_i[20]; 48 | assign d_o[21] = (syndrome_o == 8'h9b) ^ d_i[21]; 49 | assign d_o[22] = (syndrome_o == 8'h1c) ^ d_i[22]; 50 | assign d_o[23] = (syndrome_o == 8'h9d) ^ d_i[23]; 51 | assign d_o[24] = (syndrome_o == 8'h9e) ^ d_i[24]; 52 | assign d_o[25] = (syndrome_o == 8'h1f) ^ d_i[25]; 53 | assign d_o[26] = (syndrome_o == 8'ha1) ^ d_i[26]; 54 | assign d_o[27] = (syndrome_o == 8'ha2) ^ d_i[27]; 55 | assign d_o[28] = (syndrome_o == 8'h23) ^ d_i[28]; 56 | assign d_o[29] = (syndrome_o == 8'ha4) ^ d_i[29]; 57 | assign d_o[30] = (syndrome_o == 8'h25) ^ d_i[30]; 58 | assign d_o[31] = (syndrome_o == 8'h26) ^ d_i[31]; 59 | assign d_o[32] = (syndrome_o == 8'ha7) ^ d_i[32]; 60 | assign d_o[33] = (syndrome_o == 8'ha8) ^ d_i[33]; 61 | assign d_o[34] = (syndrome_o == 8'h29) ^ d_i[34]; 62 | assign d_o[35] = (syndrome_o == 8'h2a) ^ d_i[35]; 63 | assign d_o[36] = (syndrome_o == 8'hab) ^ d_i[36]; 64 | assign d_o[37] = (syndrome_o == 8'h2c) ^ d_i[37]; 65 | assign d_o[38] = (syndrome_o == 8'had) ^ d_i[38]; 66 | assign d_o[39] = (syndrome_o == 8'hae) ^ d_i[39]; 67 | assign d_o[40] = (syndrome_o == 8'h2f) ^ d_i[40]; 68 | assign d_o[41] = (syndrome_o == 8'hb0) ^ d_i[41]; 69 | assign d_o[42] = (syndrome_o == 8'h31) ^ d_i[42]; 70 | assign d_o[43] = (syndrome_o == 8'h32) ^ d_i[43]; 71 | assign d_o[44] = (syndrome_o == 8'hb3) ^ d_i[44]; 72 | assign d_o[45] = (syndrome_o == 8'h34) ^ d_i[45]; 73 | assign d_o[46] = (syndrome_o == 8'hb5) ^ d_i[46]; 74 | assign d_o[47] = (syndrome_o == 8'hb6) ^ d_i[47]; 75 | assign d_o[48] = (syndrome_o == 8'h37) ^ d_i[48]; 76 | assign d_o[49] = (syndrome_o == 8'h38) ^ d_i[49]; 77 | assign d_o[50] = (syndrome_o == 8'hb9) ^ d_i[50]; 78 | assign d_o[51] = (syndrome_o == 8'hba) ^ d_i[51]; 79 | assign d_o[52] = (syndrome_o == 8'h3b) ^ d_i[52]; 80 | assign d_o[53] = (syndrome_o == 8'hbc) ^ d_i[53]; 81 | assign d_o[54] = (syndrome_o == 8'h3d) ^ d_i[54]; 82 | assign d_o[55] = (syndrome_o == 8'h3e) ^ d_i[55]; 83 | assign d_o[56] = (syndrome_o == 8'hbf) ^ d_i[56]; 84 | assign d_o[57] = (syndrome_o == 8'hc1) ^ d_i[57]; 85 | assign d_o[58] = (syndrome_o == 8'hc2) ^ d_i[58]; 86 | assign d_o[59] = (syndrome_o == 8'h43) ^ d_i[59]; 87 | assign d_o[60] = (syndrome_o == 8'hc4) ^ d_i[60]; 88 | assign d_o[61] = (syndrome_o == 8'h45) ^ d_i[61]; 89 | assign d_o[62] = (syndrome_o == 8'h46) ^ d_i[62]; 90 | assign d_o[63] = (syndrome_o == 8'hc7) ^ d_i[63]; 91 | assign d_o[64] = (syndrome_o == 8'h1) ^ d_i[64]; 92 | assign d_o[65] = (syndrome_o == 8'h2) ^ d_i[65]; 93 | assign d_o[66] = (syndrome_o == 8'h4) ^ d_i[66]; 94 | assign d_o[67] = (syndrome_o == 8'h8) ^ d_i[67]; 95 | assign d_o[68] = (syndrome_o == 8'h10) ^ d_i[68]; 96 | assign d_o[69] = (syndrome_o == 8'h20) ^ d_i[69]; 97 | assign d_o[70] = (syndrome_o == 8'h40) ^ d_i[70]; 98 | assign d_o[71] = (syndrome_o == 8'h80) ^ d_i[71]; 99 | 100 | // err_o calc. bit0: single error, bit1: double error 101 | assign err_o[0] = syndrome_o[7]; 102 | assign err_o[1] = |syndrome_o[6:0] & ~syndrome_o[7]; 103 | 104 | endmodule : prim_secded_hamming_72_64_cor 105 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_72_64_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Decoder generated by 6 | // util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_72_64_dec ( 9 | input [71:0] in, 10 | output logic [63:0] d_o, 11 | output logic [7:0] syndrome_o, 12 | output logic [1:0] err_o 13 | ); 14 | 15 | 16 | // Syndrome calculation 17 | assign syndrome_o[0] = ^(in & 72'h01AB55555556AAAD5B); 18 | assign syndrome_o[1] = ^(in & 72'h02CD9999999B33366D); 19 | assign syndrome_o[2] = ^(in & 72'h04F1E1E1E1E3C3C78E); 20 | assign syndrome_o[3] = ^(in & 72'h0801FE01FE03FC07F0); 21 | assign syndrome_o[4] = ^(in & 72'h1001FFFE0003FFF800); 22 | assign syndrome_o[5] = ^(in & 72'h2001FFFFFFFC000000); 23 | assign syndrome_o[6] = ^(in & 72'h40FE00000000000000); 24 | assign syndrome_o[7] = ^(in & 72'h80972CD2D32DA65CB7); 25 | 26 | // Corrected output calculation 27 | assign d_o[0] = (syndrome_o == 8'h83) ^ in[0]; 28 | assign d_o[1] = (syndrome_o == 8'h85) ^ in[1]; 29 | assign d_o[2] = (syndrome_o == 8'h86) ^ in[2]; 30 | assign d_o[3] = (syndrome_o == 8'h7) ^ in[3]; 31 | assign d_o[4] = (syndrome_o == 8'h89) ^ in[4]; 32 | assign d_o[5] = (syndrome_o == 8'h8a) ^ in[5]; 33 | assign d_o[6] = (syndrome_o == 8'hb) ^ in[6]; 34 | assign d_o[7] = (syndrome_o == 8'h8c) ^ in[7]; 35 | assign d_o[8] = (syndrome_o == 8'hd) ^ in[8]; 36 | assign d_o[9] = (syndrome_o == 8'he) ^ in[9]; 37 | assign d_o[10] = (syndrome_o == 8'h8f) ^ in[10]; 38 | assign d_o[11] = (syndrome_o == 8'h91) ^ in[11]; 39 | assign d_o[12] = (syndrome_o == 8'h92) ^ in[12]; 40 | assign d_o[13] = (syndrome_o == 8'h13) ^ in[13]; 41 | assign d_o[14] = (syndrome_o == 8'h94) ^ in[14]; 42 | assign d_o[15] = (syndrome_o == 8'h15) ^ in[15]; 43 | assign d_o[16] = (syndrome_o == 8'h16) ^ in[16]; 44 | assign d_o[17] = (syndrome_o == 8'h97) ^ in[17]; 45 | assign d_o[18] = (syndrome_o == 8'h98) ^ in[18]; 46 | assign d_o[19] = (syndrome_o == 8'h19) ^ in[19]; 47 | assign d_o[20] = (syndrome_o == 8'h1a) ^ in[20]; 48 | assign d_o[21] = (syndrome_o == 8'h9b) ^ in[21]; 49 | assign d_o[22] = (syndrome_o == 8'h1c) ^ in[22]; 50 | assign d_o[23] = (syndrome_o == 8'h9d) ^ in[23]; 51 | assign d_o[24] = (syndrome_o == 8'h9e) ^ in[24]; 52 | assign d_o[25] = (syndrome_o == 8'h1f) ^ in[25]; 53 | assign d_o[26] = (syndrome_o == 8'ha1) ^ in[26]; 54 | assign d_o[27] = (syndrome_o == 8'ha2) ^ in[27]; 55 | assign d_o[28] = (syndrome_o == 8'h23) ^ in[28]; 56 | assign d_o[29] = (syndrome_o == 8'ha4) ^ in[29]; 57 | assign d_o[30] = (syndrome_o == 8'h25) ^ in[30]; 58 | assign d_o[31] = (syndrome_o == 8'h26) ^ in[31]; 59 | assign d_o[32] = (syndrome_o == 8'ha7) ^ in[32]; 60 | assign d_o[33] = (syndrome_o == 8'ha8) ^ in[33]; 61 | assign d_o[34] = (syndrome_o == 8'h29) ^ in[34]; 62 | assign d_o[35] = (syndrome_o == 8'h2a) ^ in[35]; 63 | assign d_o[36] = (syndrome_o == 8'hab) ^ in[36]; 64 | assign d_o[37] = (syndrome_o == 8'h2c) ^ in[37]; 65 | assign d_o[38] = (syndrome_o == 8'had) ^ in[38]; 66 | assign d_o[39] = (syndrome_o == 8'hae) ^ in[39]; 67 | assign d_o[40] = (syndrome_o == 8'h2f) ^ in[40]; 68 | assign d_o[41] = (syndrome_o == 8'hb0) ^ in[41]; 69 | assign d_o[42] = (syndrome_o == 8'h31) ^ in[42]; 70 | assign d_o[43] = (syndrome_o == 8'h32) ^ in[43]; 71 | assign d_o[44] = (syndrome_o == 8'hb3) ^ in[44]; 72 | assign d_o[45] = (syndrome_o == 8'h34) ^ in[45]; 73 | assign d_o[46] = (syndrome_o == 8'hb5) ^ in[46]; 74 | assign d_o[47] = (syndrome_o == 8'hb6) ^ in[47]; 75 | assign d_o[48] = (syndrome_o == 8'h37) ^ in[48]; 76 | assign d_o[49] = (syndrome_o == 8'h38) ^ in[49]; 77 | assign d_o[50] = (syndrome_o == 8'hb9) ^ in[50]; 78 | assign d_o[51] = (syndrome_o == 8'hba) ^ in[51]; 79 | assign d_o[52] = (syndrome_o == 8'h3b) ^ in[52]; 80 | assign d_o[53] = (syndrome_o == 8'hbc) ^ in[53]; 81 | assign d_o[54] = (syndrome_o == 8'h3d) ^ in[54]; 82 | assign d_o[55] = (syndrome_o == 8'h3e) ^ in[55]; 83 | assign d_o[56] = (syndrome_o == 8'hbf) ^ in[56]; 84 | assign d_o[57] = (syndrome_o == 8'hc1) ^ in[57]; 85 | assign d_o[58] = (syndrome_o == 8'hc2) ^ in[58]; 86 | assign d_o[59] = (syndrome_o == 8'h43) ^ in[59]; 87 | assign d_o[60] = (syndrome_o == 8'hc4) ^ in[60]; 88 | assign d_o[61] = (syndrome_o == 8'h45) ^ in[61]; 89 | assign d_o[62] = (syndrome_o == 8'h46) ^ in[62]; 90 | assign d_o[63] = (syndrome_o == 8'hc7) ^ in[63]; 91 | 92 | // err_o calc. bit0: single error, bit1: double error 93 | assign err_o[0] = syndrome_o[7]; 94 | assign err_o[1] = |syndrome_o[6:0] & ~syndrome_o[7]; 95 | 96 | endmodule : prim_secded_hamming_72_64_dec 97 | -------------------------------------------------------------------------------- /rtl/lowrisc_ecc/prim_secded_hamming_72_64_enc.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // SECDED Encoder generated by 6 | // util/design/secded_gen.py -m 8 -k 64 -s 1592631616 -c hamming 7 | 8 | module prim_secded_hamming_72_64_enc ( 9 | input [63:0] in, 10 | output logic [71:0] out 11 | ); 12 | 13 | always_comb begin : p_encode 14 | out[63:0] = in; 15 | out[64] = ^(in & 64'hAB55555556AAAD5B); 16 | out[65] = ^(in & 64'hCD9999999B33366D); 17 | out[66] = ^(in & 64'hF1E1E1E1E3C3C78E); 18 | out[67] = ^(in & 64'h01FE01FE03FC07F0); 19 | out[68] = ^(in & 64'h01FFFE0003FFF800); 20 | out[69] = ^(in & 64'h01FFFFFFFC000000); 21 | out[70] = ^(in & 64'hFE00000000000000); 22 | out[71] = ^(in & 64'h972CD2D32DA65CB7); 23 | end 24 | 25 | endmodule : prim_secded_hamming_72_64_enc 26 | -------------------------------------------------------------------------------- /rtl/pulpissimo_tcls/TCLS.h: -------------------------------------------------------------------------------- 1 | // Generated register defines for TCLS_manager 2 | 3 | #ifndef _TCLS_MANAGER_REG_DEFS_ 4 | #define _TCLS_MANAGER_REG_DEFS_ 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | // Register width 10 | #define TCLS_MANAGER_PARAM_REG_WIDTH 32 11 | 12 | // Stack Pointer storage register 13 | #define TCLS_MANAGER_SP_STORE_REG_OFFSET 0x0 14 | 15 | // Re-synchronization configuration 16 | #define TCLS_MANAGER_TCLS_CONFIG_REG_OFFSET 0x4 17 | #define TCLS_MANAGER_TCLS_CONFIG_SETBACK_BIT 0 18 | #define TCLS_MANAGER_TCLS_CONFIG_RELOAD_SETBACK_BIT 1 19 | #define TCLS_MANAGER_TCLS_CONFIG_FORCE_RESYNCH_BIT 2 20 | 21 | // Mismatch counter of core 0 22 | #define TCLS_MANAGER_MISMATCHES_0_REG_OFFSET 0x8 23 | 24 | // Mismatch counter of core 1 25 | #define TCLS_MANAGER_MISMATCHES_1_REG_OFFSET 0xc 26 | 27 | // Mismatch counter of core 2 28 | #define TCLS_MANAGER_MISMATCHES_2_REG_OFFSET 0x10 29 | 30 | #ifdef __cplusplus 31 | } // extern "C" 32 | #endif 33 | #endif // _TCLS_MANAGER_REG_DEFS_ 34 | // End generated register defines for TCLS_manager -------------------------------------------------------------------------------- /rtl/pulpissimo_tcls/TCLS_unit.hjson: -------------------------------------------------------------------------------- 1 | { 2 | name: "TCLS_manager", 3 | clock_primary: "clk_i", 4 | reset_primary: "rst_ni", 5 | bus_interfaces: [ 6 | { protocol: "reg_iface", 7 | direction: "device" 8 | } 9 | ], 10 | 11 | regwidth: "32", 12 | registers: [ 13 | { name: "SP_store", 14 | desc: "Stack Pointer storage register", 15 | swaccess: "rw", 16 | hwaccess: "hrw", 17 | hwqe: "true", 18 | fields: [ 19 | { bits: "31:0", 20 | name: "SP", 21 | desc: "Stack Pointer" 22 | } 23 | ] 24 | }, 25 | { name: "TCLS_CONFIG", 26 | desc: "Re-synchronization configuration", 27 | swaccess: "rw", 28 | hwaccess: "hrw", 29 | fields: [ 30 | { bits: "0", 31 | name: "SETBACK", 32 | desc: "Enable setback (synchronous reset) during re-synch" 33 | }, 34 | { bits: "1", 35 | name: "RELOAD_SETBACK", 36 | desc: "Enable setback on mismatch during reload section of re-synch (only possible with SETBACK)" 37 | }, 38 | { bits: "2", 39 | name: "FORCE_RESYNCH", 40 | desc: "Forces a resynchronization routine" 41 | } 42 | ] 43 | }, 44 | { name: "MISMATCHES_0", 45 | desc: "Mismatch counter of core 0", 46 | swaccess: "rw0c", 47 | hwaccess: "hrw", 48 | fields: [ 49 | { bits: "31:0", 50 | name: "mismatches_0", 51 | desc: "mismatch counter of core 0" 52 | } 53 | ] 54 | }, 55 | { name: "MISMATCHES_1", 56 | desc: "Mismatch counter of core 1", 57 | swaccess: "rw0c", 58 | hwaccess: "hrw", 59 | fields: [ 60 | { bits: "31:0", 61 | name: "mismatches_1", 62 | desc: "mismatch counter of core 1" 63 | } 64 | ] 65 | }, 66 | { name: "MISMATCHES_2", 67 | desc: "Mismatch counter of core 2", 68 | swaccess: "rw0c", 69 | hwaccess: "hrw", 70 | fields: [ 71 | { bits: "31:0", 72 | name: "mismatches_2", 73 | desc: "mismatch counter of core 2" 74 | } 75 | ] 76 | } 77 | ], 78 | } 79 | -------------------------------------------------------------------------------- /rtl/pulpissimo_tcls/doc.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | | Name | Offset | Length | Description | 4 | |:---------------------------------------------|:---------|---------:|:---------------------------------| 5 | | TCLS_manager.[`SP_store`](#sp_store) | 0x0 | 4 | Stack Pointer storage register | 6 | | TCLS_manager.[`TCLS_CONFIG`](#tcls_config) | 0x4 | 4 | Re-synchronization configuration | 7 | | TCLS_manager.[`MISMATCHES_0`](#mismatches_0) | 0x8 | 4 | Mismatch counter of core 0 | 8 | | TCLS_manager.[`MISMATCHES_1`](#mismatches_1) | 0xc | 4 | Mismatch counter of core 1 | 9 | | TCLS_manager.[`MISMATCHES_2`](#mismatches_2) | 0x10 | 4 | Mismatch counter of core 2 | 10 | 11 | ## SP_store 12 | Stack Pointer storage register 13 | - Offset: `0x0` 14 | - Reset default: `0x0` 15 | - Reset mask: `0xffffffff` 16 | 17 | ### Fields 18 | 19 | ```wavejson 20 | {"reg": [{"name": "SP", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 21 | ``` 22 | 23 | | Bits | Type | Reset | Name | Description | 24 | |:------:|:------:|:-------:|:-------|:--------------| 25 | | 31:0 | rw | x | SP | Stack Pointer | 26 | 27 | ## TCLS_CONFIG 28 | Re-synchronization configuration 29 | - Offset: `0x4` 30 | - Reset default: `0x0` 31 | - Reset mask: `0x7` 32 | 33 | ### Fields 34 | 35 | ```wavejson 36 | {"reg": [{"name": "SETBACK", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "RELOAD_SETBACK", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "FORCE_RESYNCH", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 29}], "config": {"lanes": 1, "fontsize": 10, "vspace": 160}} 37 | ``` 38 | 39 | | Bits | Type | Reset | Name | Description | 40 | |:------:|:------:|:-------:|:---------------|:------------------------------------------------------------------------------------------| 41 | | 31:3 | | | | Reserved | 42 | | 2 | rw | x | FORCE_RESYNCH | Forces a resynchronization routine | 43 | | 1 | rw | x | RELOAD_SETBACK | Enable setback on mismatch during reload section of re-synch (only possible with SETBACK) | 44 | | 0 | rw | x | SETBACK | Enable setback (synchronous reset) during re-synch | 45 | 46 | ## MISMATCHES_0 47 | Mismatch counter of core 0 48 | - Offset: `0x8` 49 | - Reset default: `0x0` 50 | - Reset mask: `0xffffffff` 51 | 52 | ### Fields 53 | 54 | ```wavejson 55 | {"reg": [{"name": "mismatches_0", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 56 | ``` 57 | 58 | | Bits | Type | Reset | Name | Description | 59 | |:------:|:------:|:-------:|:-------------|:---------------------------| 60 | | 31:0 | rw0c | x | mismatches_0 | mismatch counter of core 0 | 61 | 62 | ## MISMATCHES_1 63 | Mismatch counter of core 1 64 | - Offset: `0xc` 65 | - Reset default: `0x0` 66 | - Reset mask: `0xffffffff` 67 | 68 | ### Fields 69 | 70 | ```wavejson 71 | {"reg": [{"name": "mismatches_1", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 72 | ``` 73 | 74 | | Bits | Type | Reset | Name | Description | 75 | |:------:|:------:|:-------:|:-------------|:---------------------------| 76 | | 31:0 | rw0c | x | mismatches_1 | mismatch counter of core 1 | 77 | 78 | ## MISMATCHES_2 79 | Mismatch counter of core 2 80 | - Offset: `0x10` 81 | - Reset default: `0x0` 82 | - Reset mask: `0xffffffff` 83 | 84 | ### Fields 85 | 86 | ```wavejson 87 | {"reg": [{"name": "mismatches_2", "bits": 32, "attr": ["rw0c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} 88 | ``` 89 | 90 | | Bits | Type | Reset | Name | Description | 91 | |:------:|:------:|:-------:|:-------------|:---------------------------| 92 | | 31:0 | rw0c | x | mismatches_2 | mismatch counter of core 2 | 93 | 94 | -------------------------------------------------------------------------------- /rtl/pulpissimo_tcls/tcls_manager_reg_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | // Register Package auto-generated by `reggen` containing data structure 6 | 7 | package tcls_manager_reg_pkg; 8 | 9 | // Address widths within the block 10 | parameter int BlockAw = 5; 11 | 12 | //////////////////////////// 13 | // Typedefs for registers // 14 | //////////////////////////// 15 | 16 | typedef struct packed { 17 | logic [31:0] q; 18 | logic qe; 19 | } tcls_manager_reg2hw_sp_store_reg_t; 20 | 21 | typedef struct packed { 22 | struct packed { 23 | logic q; 24 | } setback; 25 | struct packed { 26 | logic q; 27 | } reload_setback; 28 | struct packed { 29 | logic q; 30 | } force_resynch; 31 | } tcls_manager_reg2hw_tcls_config_reg_t; 32 | 33 | typedef struct packed { 34 | logic [31:0] q; 35 | } tcls_manager_reg2hw_mismatches_0_reg_t; 36 | 37 | typedef struct packed { 38 | logic [31:0] q; 39 | } tcls_manager_reg2hw_mismatches_1_reg_t; 40 | 41 | typedef struct packed { 42 | logic [31:0] q; 43 | } tcls_manager_reg2hw_mismatches_2_reg_t; 44 | 45 | typedef struct packed { 46 | logic [31:0] d; 47 | logic de; 48 | } tcls_manager_hw2reg_sp_store_reg_t; 49 | 50 | typedef struct packed { 51 | struct packed { 52 | logic d; 53 | logic de; 54 | } setback; 55 | struct packed { 56 | logic d; 57 | logic de; 58 | } reload_setback; 59 | struct packed { 60 | logic d; 61 | logic de; 62 | } force_resynch; 63 | } tcls_manager_hw2reg_tcls_config_reg_t; 64 | 65 | typedef struct packed { 66 | logic [31:0] d; 67 | logic de; 68 | } tcls_manager_hw2reg_mismatches_0_reg_t; 69 | 70 | typedef struct packed { 71 | logic [31:0] d; 72 | logic de; 73 | } tcls_manager_hw2reg_mismatches_1_reg_t; 74 | 75 | typedef struct packed { 76 | logic [31:0] d; 77 | logic de; 78 | } tcls_manager_hw2reg_mismatches_2_reg_t; 79 | 80 | // Register -> HW type 81 | typedef struct packed { 82 | tcls_manager_reg2hw_sp_store_reg_t sp_store; // [131:99] 83 | tcls_manager_reg2hw_tcls_config_reg_t tcls_config; // [98:96] 84 | tcls_manager_reg2hw_mismatches_0_reg_t mismatches_0; // [95:64] 85 | tcls_manager_reg2hw_mismatches_1_reg_t mismatches_1; // [63:32] 86 | tcls_manager_reg2hw_mismatches_2_reg_t mismatches_2; // [31:0] 87 | } tcls_manager_reg2hw_t; 88 | 89 | // HW -> register type 90 | typedef struct packed { 91 | tcls_manager_hw2reg_sp_store_reg_t sp_store; // [137:105] 92 | tcls_manager_hw2reg_tcls_config_reg_t tcls_config; // [104:99] 93 | tcls_manager_hw2reg_mismatches_0_reg_t mismatches_0; // [98:66] 94 | tcls_manager_hw2reg_mismatches_1_reg_t mismatches_1; // [65:33] 95 | tcls_manager_hw2reg_mismatches_2_reg_t mismatches_2; // [32:0] 96 | } tcls_manager_hw2reg_t; 97 | 98 | // Register offsets 99 | parameter logic [BlockAw-1:0] TCLS_MANAGER_SP_STORE_OFFSET = 5'h 0; 100 | parameter logic [BlockAw-1:0] TCLS_MANAGER_TCLS_CONFIG_OFFSET = 5'h 4; 101 | parameter logic [BlockAw-1:0] TCLS_MANAGER_MISMATCHES_0_OFFSET = 5'h 8; 102 | parameter logic [BlockAw-1:0] TCLS_MANAGER_MISMATCHES_1_OFFSET = 5'h c; 103 | parameter logic [BlockAw-1:0] TCLS_MANAGER_MISMATCHES_2_OFFSET = 5'h 10; 104 | 105 | // Register index 106 | typedef enum int { 107 | TCLS_MANAGER_SP_STORE, 108 | TCLS_MANAGER_TCLS_CONFIG, 109 | TCLS_MANAGER_MISMATCHES_0, 110 | TCLS_MANAGER_MISMATCHES_1, 111 | TCLS_MANAGER_MISMATCHES_2 112 | } tcls_manager_id_e; 113 | 114 | // Register width information to check illegal writes 115 | parameter logic [3:0] TCLS_MANAGER_PERMIT [5] = '{ 116 | 4'b 1111, // index[0] TCLS_MANAGER_SP_STORE 117 | 4'b 0001, // index[1] TCLS_MANAGER_TCLS_CONFIG 118 | 4'b 1111, // index[2] TCLS_MANAGER_MISMATCHES_0 119 | 4'b 1111, // index[3] TCLS_MANAGER_MISMATCHES_1 120 | 4'b 1111 // index[4] TCLS_MANAGER_MISMATCHES_2 121 | }; 122 | 123 | endpackage 124 | 125 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) 2021 ETH Zurich, University of Bologna 3 | # 4 | # Copyright and related rights are licensed under the Solderpad Hardware 5 | # License, Version 0.51 (the "License"); you may not use this file except in 6 | # compliance with the License. You may obtain a copy of the License at 7 | # http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | # or agreed to in writing, software, hardware and materials distributed under 9 | # this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | # specific language governing permissions and limitations under the License. 12 | # 13 | # Testing script for redundancy cells 14 | 15 | set -e 16 | 17 | [ ! -z "$VSIM" ] || VSIM=vsim 18 | 19 | VSIM_LOGFILE=vsim.log 20 | 21 | bender script vsim -t test -t rtl --vlog-arg="-svinputport=compat" -t deprecated > compile.tcl 22 | echo "return 0" >> compile.tcl 23 | 24 | $VSIM -c -do 'quit -code [source compile.tcl]' > vcom.log 25 | 26 | rm -f $VSIM_LOGFILE 27 | 28 | call_vsim() { 29 | if [ $1 == tb_ecc_sram ]; then 30 | echo "source test/ecc_sram_fault_injection.tcl; run -all" | $VSIM "$@" >> $VSIM_LOGFILE 2>&1 31 | else 32 | echo "run -all" | $VSIM "$@" >> $VSIM_LOGFILE 2>&1 33 | fi 34 | echo " --> $@" 35 | tail -7 $VSIM_LOGFILE 36 | echo "" 37 | tail -1 vsim.log | grep "Errors: 0," > /dev/null 38 | } 39 | 40 | call_vsim tb_tmr_voter 41 | call_vsim tb_tmr_voter_fail 42 | call_vsim tb_tmr_voter_detect 43 | call_vsim tb_tmr_word_voter 44 | call_vsim tb_bitwise_tmr_voter 45 | call_vsim tb_bitwise_tmr_voter_fail 46 | call_vsim tb_ecc_sram -voptargs="+acc=nr" 47 | call_vsim -GDataWidth=8 tb_ecc_secded 48 | call_vsim -GDataWidth=16 tb_ecc_secded 49 | call_vsim -GDataWidth=32 tb_ecc_secded 50 | call_vsim -GDataWidth=64 tb_ecc_secded 51 | call_vsim tb_ecc_scrubber 52 | call_vsim tb_voter_macros 53 | -------------------------------------------------------------------------------- /src_files.yml: -------------------------------------------------------------------------------- 1 | redundancy_cells: 2 | files: [ 3 | # Level 0 4 | lowrisc_ecc/prim_secded_13_8_dec.sv, 5 | lowrisc_ecc/prim_secded_13_8_enc.sv, 6 | lowrisc_ecc/prim_secded_22_16_dec.sv, 7 | lowrisc_ecc/prim_secded_22_16_enc.sv, 8 | lowrisc_ecc/prim_secded_39_32_dec.sv, 9 | lowrisc_ecc/prim_secded_39_32_enc.sv, 10 | lowrisc_ecc/prim_secded_72_64_dec.sv, 11 | lowrisc_ecc/prim_secded_72_64_enc.sv, 12 | rtl/TMR_voter.sv, 13 | rtl/TMR_voter_fail.sv, 14 | rtl/TMR_word_voter, 15 | # Level 1 16 | rtl/bitwise_TMR_voter_fail.sv 17 | rtl/ecc_concat_32_64.sv, 18 | rtl/ecc_sram_wrap.sv, 19 | rtl/BUS_enc_dec/AXI_bus_ecc_dec.sv, 20 | rtl/BUS_enc_dec/AXI_bus_ecc_enc.sv, 21 | rtl/BUS_enc_dec/hci_core_intf_ecc_dec.sv, 22 | rtl/BUS_enc_dec/hci_core_intf_ecc_enc.sv, 23 | rtl/BUS_enc_dec/hci_mem_intf_ecc_dec.sv, 24 | rtl/BUS_enc_dec/hci_mem_intf_ecc_enc.sv, 25 | rtl/BUS_enc_dec/PE_XBAR_bus_ecc_dec.sv, 26 | rtl/BUS_enc_dec/PE_XBAR_bus_ecc_enc.sv, 27 | rtl/BUS_enc_dec/TCDM_XBAR_bus_ecc_dec.sv, 28 | rtl/BUS_enc_dec/TCDM_XBAR_bus_ecc_enc.sv, 29 | rlt/BUS_enc_dec/XBAR_DEMUX_BUS_ecc_dec.sv, 30 | rtl/BUS_enc_dec/XBAR_DEMUX_BUS_ecc_enc.sv, 31 | rtl/TMR_voter_detect.sv, 32 | # Level 2 33 | rtl/bitwise_TMR_voter.sv, 34 | ] 35 | -------------------------------------------------------------------------------- /test/ecc_sram_fault_injection.tcl: -------------------------------------------------------------------------------- 1 | # Fault injection file by Michael Rogenmoser 2 | # 3 | # This script flips a single bit in each memory word at the halfway point in the simulation. 4 | # Not each flip will be tested, as not every bit is read. 5 | # 6 | # Based in part on: 7 | # - https://diglib.tugraz.at/download.php?id=576a7490f01c3&location=browse 8 | 9 | echo "Bitflip script enabled\n" 10 | 11 | when { sim:/tb_ecc_sram/test_halfway == 1'b1 } { 12 | for {set i 0} {$i < [regsub ".*'h" [examine sim:/tb_ecc_sram/BankSize] "0x"]} {incr i} { 13 | set indent [expr int(floor(rand()*39))] 14 | set current_value [examine /tb_ecc_sram/i_dut/i_bank/sram($i)($indent)] 15 | if {$current_value == "1'h0"} { 16 | force -deposit /tb_ecc_sram/i_dut/i_bank/sram($i)($indent) 1 17 | } 18 | if {$current_value == "1'h1"} { 19 | force -deposit /tb_ecc_sram/i_dut/i_bank/sram($i)($indent) 0 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/tb_tmr_voter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Testbench for TMR Voter 12 | 13 | module tb_tmr_voter; 14 | 15 | /****************** 16 | * Helper tasks * 17 | ******************/ 18 | 19 | localparam time TTest = 8ns; 20 | localparam time TApply = 2ns; 21 | 22 | task cycle_start(); 23 | #TApply; 24 | endtask: cycle_start 25 | 26 | task cycle_end(); 27 | #TTest; 28 | endtask: cycle_end 29 | 30 | /********************** 31 | * Helper variables * 32 | **********************/ 33 | 34 | longint test_cnt; 35 | 36 | logic [2:0] in; 37 | logic out_classic; 38 | logic out_kp; 39 | logic out_bn; 40 | 41 | TMR_voter #( 42 | .VoterType(0) 43 | ) i_dut_classic ( 44 | .a_i (in[0] ), 45 | .b_i (in[1] ), 46 | .c_i (in[2] ), 47 | .majority_o (out_classic) 48 | ); 49 | 50 | TMR_voter #( 51 | .VoterType(1) 52 | ) i_dut_kp ( 53 | .a_i (in[0] ), 54 | .b_i (in[1] ), 55 | .c_i (in[2] ), 56 | .majority_o (out_kp) 57 | ); 58 | 59 | TMR_voter #( 60 | .VoterType(2) 61 | ) i_dut_bn ( 62 | .a_i (in[0] ), 63 | .b_i (in[1] ), 64 | .c_i (in[2] ), 65 | .majority_o (out_bn) 66 | ); 67 | 68 | initial begin 69 | cycle_start(); 70 | in = 3'b000; 71 | cycle_end(); 72 | assert(out_classic == 1'b0); 73 | assert(out_kp == 1'b0); 74 | assert(out_bn == 1'b0); 75 | cycle_start(); 76 | in = 3'b001; 77 | cycle_end(); 78 | assert(out_classic == 1'b0); 79 | assert(out_kp == 1'b0); 80 | assert(out_bn == 1'b0); 81 | cycle_start(); 82 | in = 3'b010; 83 | cycle_end(); 84 | assert(out_classic == 1'b0); 85 | assert(out_kp == 1'b0); 86 | assert(out_bn == 1'b0); 87 | cycle_start(); 88 | in = 3'b100; 89 | cycle_end(); 90 | assert(out_classic == 1'b0); 91 | assert(out_kp == 1'b0); 92 | assert(out_bn == 1'b0); 93 | 94 | cycle_start(); 95 | in = 3'b111; 96 | cycle_end(); 97 | assert(out_classic == 1'b1); 98 | assert(out_kp == 1'b1); 99 | assert(out_bn == 1'b1); 100 | cycle_start(); 101 | in = 3'b110; 102 | cycle_end(); 103 | assert(out_classic == 1'b1); 104 | assert(out_kp == 1'b1); 105 | assert(out_bn == 1'b1); 106 | cycle_start(); 107 | in = 3'b101; 108 | cycle_end(); 109 | assert(out_classic == 1'b1); 110 | assert(out_kp == 1'b1); 111 | assert(out_bn == 1'b1); 112 | cycle_start(); 113 | in = 3'b011; 114 | cycle_end(); 115 | assert(out_classic == 1'b1); 116 | assert(out_kp == 1'b1); 117 | assert(out_bn == 1'b1); 118 | end 119 | 120 | endmodule 121 | 122 | -------------------------------------------------------------------------------- /test/tb_tmr_voter_detect.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Testbench for TMR Voter 12 | 13 | module tb_tmr_voter_detect; 14 | 15 | localparam time TTest = 8ns; 16 | localparam time TApply = 2ns; 17 | 18 | logic [2:0] in; 19 | logic out_classic; 20 | logic out_kp; 21 | logic out_bn; 22 | logic [2:0] error_classic; 23 | logic [2:0] error_kp; 24 | logic [2:0] error_bn; 25 | 26 | TMR_voter_detect #( 27 | .VoterType( 0 ) 28 | ) tmr_classic ( 29 | .a_i ( in[0] ), 30 | .b_i ( in[1] ), 31 | .c_i ( in[2] ), 32 | .majority_o ( out_classic ), 33 | .error_cba_o ( error_classic ) 34 | ); 35 | 36 | TMR_voter_detect #( 37 | .VoterType( 1 ) 38 | ) tmr_kp ( 39 | .a_i ( in[0] ), 40 | .b_i ( in[1] ), 41 | .c_i ( in[2] ), 42 | .majority_o ( out_kp ), 43 | .error_cba_o ( error_kp ) 44 | ); 45 | 46 | TMR_voter_detect #( 47 | .VoterType( 2 ) 48 | ) tmr_bn ( 49 | .a_i ( in[0] ), 50 | .b_i ( in[1] ), 51 | .c_i ( in[2] ), 52 | .majority_o ( out_bn ), 53 | .error_cba_o ( error_bn ) 54 | ); 55 | 56 | initial begin 57 | in = 3'b000; 58 | #TTest 59 | assert(out_classic == 1'b0); 60 | assert(out_kp == 1'b0); 61 | assert(out_bn == 1'b0); 62 | assert(error_classic == 3'b000); 63 | assert(error_kp == 3'b000); 64 | assert(error_bn == 3'b000); 65 | #TApply 66 | in = 3'b001; 67 | #TTest 68 | assert(out_classic == 1'b0); 69 | assert(out_kp == 1'b0); 70 | assert(out_bn == 1'b0); 71 | assert(error_classic == 3'b001); 72 | assert(error_kp == 3'b001); 73 | assert(error_bn == 3'b001); 74 | #TApply 75 | in = 3'b010; 76 | #TTest 77 | assert(out_classic == 1'b0); 78 | assert(out_kp == 1'b0); 79 | assert(out_bn == 1'b0); 80 | assert(error_classic == 3'b010); 81 | assert(error_kp == 3'b010); 82 | assert(error_bn == 3'b010); 83 | #TApply 84 | in = 3'b100; 85 | #TTest 86 | assert(out_classic == 1'b0); 87 | assert(out_kp == 1'b0); 88 | assert(out_bn == 1'b0); 89 | assert(error_classic == 3'b100); 90 | assert(error_kp == 3'b100); 91 | assert(error_bn == 3'b100); 92 | #TApply 93 | 94 | in = 3'b111; 95 | #TTest 96 | assert(out_classic == 1'b1); 97 | assert(out_kp == 1'b1); 98 | assert(out_bn == 1'b1); 99 | assert(error_classic == 3'b000); 100 | assert(error_kp == 3'b000); 101 | assert(error_bn == 3'b000); 102 | #TApply 103 | in = 3'b110; 104 | #TTest 105 | assert(out_classic == 1'b1); 106 | assert(out_kp == 1'b1); 107 | assert(out_bn == 1'b1); 108 | assert(error_classic == 3'b001); 109 | assert(error_kp == 3'b001); 110 | assert(error_bn == 3'b001); 111 | #TApply 112 | in = 3'b101; 113 | #TTest 114 | assert(out_classic == 1'b1); 115 | assert(out_kp == 1'b1); 116 | assert(out_bn == 1'b1); 117 | assert(error_classic == 3'b010); 118 | assert(error_kp == 3'b010); 119 | assert(error_bn == 3'b010); 120 | #TApply 121 | in = 3'b011; 122 | #TTest 123 | assert(out_classic == 1'b1); 124 | assert(out_kp == 1'b1); 125 | assert(out_bn == 1'b1); 126 | assert(error_classic == 3'b100); 127 | assert(error_kp == 3'b100); 128 | assert(error_bn == 3'b100); 129 | end 130 | 131 | endmodule 132 | 133 | -------------------------------------------------------------------------------- /test/tb_tmr_voter_fail.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Testbench for TMR Voter with fault output 12 | 13 | module tb_tmr_voter_fail; 14 | 15 | /****************** 16 | * Helper tasks * 17 | ******************/ 18 | 19 | localparam time TTest = 8ns; 20 | localparam time TApply = 2ns; 21 | 22 | task cycle_start(); 23 | #TApply; 24 | endtask: cycle_start 25 | 26 | task cycle_end(); 27 | #TTest; 28 | endtask: cycle_end 29 | 30 | /********************** 31 | * Helper variables * 32 | **********************/ 33 | 34 | longint test_cnt; 35 | 36 | logic [2:0] in; 37 | logic out_classic, out_kp, out_bn; 38 | logic fault_classic, fault_kp, fault_bn; 39 | 40 | TMR_voter_fail #( 41 | .VoterType(0) 42 | ) i_dut_classic ( 43 | .a_i ( in[0] ), 44 | .b_i ( in[1] ), 45 | .c_i ( in[2] ), 46 | .majority_o ( out_classic ), 47 | .fault_detected_o ( fault_classic ) 48 | ); 49 | 50 | TMR_voter_fail #( 51 | .VoterType(1) 52 | ) i_dut_kp ( 53 | .a_i ( in[0] ), 54 | .b_i ( in[1] ), 55 | .c_i ( in[2] ), 56 | .majority_o ( out_kp ), 57 | .fault_detected_o ( fault_kp ) 58 | ); 59 | 60 | TMR_voter_fail #( 61 | .VoterType(2) 62 | ) i_dut_bn ( 63 | .a_i ( in[0] ), 64 | .b_i ( in[1] ), 65 | .c_i ( in[2] ), 66 | .majority_o ( out_bn ), 67 | .fault_detected_o ( fault_bn ) 68 | ); 69 | 70 | initial begin 71 | cycle_start(); 72 | in = 3'b000; 73 | cycle_end(); 74 | assert(out_classic == 1'b0); 75 | assert(out_kp == 1'b0); 76 | assert(out_bn == 1'b0); 77 | assert(fault_classic == 1'b0); 78 | assert(fault_kp == 1'b0); 79 | assert(fault_bn == 1'b0); 80 | cycle_start(); 81 | in = 3'b001; 82 | cycle_end(); 83 | assert(out_classic == 1'b0); 84 | assert(out_kp == 1'b0); 85 | assert(out_bn == 1'b0); 86 | assert(fault_classic == 1'b1); 87 | assert(fault_kp == 1'b1); 88 | assert(fault_bn == 1'b1); 89 | cycle_start(); 90 | in = 3'b010; 91 | cycle_end(); 92 | assert(out_classic == 1'b0); 93 | assert(out_kp == 1'b0); 94 | assert(out_bn == 1'b0); 95 | assert(fault_classic == 1'b1); 96 | assert(fault_kp == 1'b1); 97 | assert(fault_bn == 1'b1); 98 | cycle_start(); 99 | in = 3'b100; 100 | cycle_end(); 101 | assert(out_classic == 1'b0); 102 | assert(out_kp == 1'b0); 103 | assert(out_bn == 1'b0); 104 | assert(fault_classic == 1'b1); 105 | assert(fault_kp == 1'b1); 106 | assert(fault_bn == 1'b1); 107 | 108 | cycle_start(); 109 | in = 3'b111; 110 | cycle_end(); 111 | assert(out_classic == 1'b1); 112 | assert(out_kp == 1'b1); 113 | assert(out_bn == 1'b1); 114 | assert(fault_classic == 1'b0); 115 | assert(fault_kp == 1'b0); 116 | assert(fault_bn == 1'b0); 117 | cycle_start(); 118 | in = 3'b110; 119 | cycle_end(); 120 | assert(out_classic == 1'b1); 121 | assert(out_kp == 1'b1); 122 | assert(out_bn == 1'b1); 123 | assert(fault_classic == 1'b1); 124 | assert(fault_kp == 1'b1); 125 | assert(fault_bn == 1'b1); 126 | cycle_start(); 127 | in = 3'b101; 128 | cycle_end(); 129 | assert(out_classic == 1'b1); 130 | assert(out_kp == 1'b1); 131 | assert(out_bn == 1'b1); 132 | assert(fault_classic == 1'b1); 133 | assert(fault_kp == 1'b1); 134 | assert(fault_bn == 1'b1); 135 | cycle_start(); 136 | in = 3'b011; 137 | cycle_end(); 138 | assert(out_classic == 1'b1); 139 | assert(out_kp == 1'b1); 140 | assert(out_bn == 1'b1); 141 | assert(fault_classic == 1'b1); 142 | assert(fault_kp == 1'b1); 143 | assert(fault_bn == 1'b1); 144 | end 145 | 146 | endmodule 147 | 148 | -------------------------------------------------------------------------------- /util/lowrisc_opentitan/util/design/data/secded_cfg.hjson: -------------------------------------------------------------------------------- 1 | // Copyright lowRISC contributors. 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 3 | // SPDX-License-Identifier: Apache-2.0 4 | { cfgs: [ 5 | {k: 8, m: 5, code_type: "hsiao" }, 6 | {k: 16, m: 6, code_type: "hsiao" }, 7 | {k: 22, m: 6, code_type: "hsiao" }, 8 | {k: 32, m: 7, code_type: "hsiao" }, 9 | {k: 57, m: 7, code_type: "hsiao" }, 10 | {k: 64, m: 8, code_type: "hsiao" }, 11 | {k: 16, m: 6, code_type: "hamming"}, 12 | {k: 32, m: 7, code_type: "hamming"}, 13 | {k: 64, m: 8, code_type: "hamming"}, 14 | ], 15 | // This seed can be changed here if re-generation of ECC RTL 16 | // with a different seed is desired. 17 | seed: 1592631616 18 | } 19 | -------------------------------------------------------------------------------- /util/patches/lowrisc_data_dir/0001-edit-cfg.patch: -------------------------------------------------------------------------------- 1 | diff --git a/secded_cfg.hjson b/secded_cfg.hjson 2 | index d1aba6db1..5de93ce7d 100644 3 | --- a/secded_cfg.hjson 4 | +++ b/secded_cfg.hjson 5 | @@ -2,6 +2,7 @@ 6 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. 7 | // SPDX-License-Identifier: Apache-2.0 8 | { cfgs: [ 9 | + {k: 8, m: 5, code_type: "hsiao" }, 10 | {k: 16, m: 6, code_type: "hsiao" }, 11 | {k: 22, m: 6, code_type: "hsiao" }, 12 | {k: 32, m: 7, code_type: "hsiao" }, 13 | -------------------------------------------------------------------------------- /util/patches/lowrisc_secded_gen/0001-Add-Corrector-to-generation-script-and-update-testbe.patch: -------------------------------------------------------------------------------- 1 | From 2efe5a9d73fc7469dbb07b4b892e2bb94b604089 Mon Sep 17 00:00:00 2001 2 | From: Michael Rogenmoser 3 | Date: Fri, 7 Jul 2023 14:47:16 +0200 4 | Subject: [PATCH] Add Corrector to generation script and update testbench 5 | 6 | --- 7 | secded_gen.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 8 | 1 file changed, 60 insertions(+) 9 | 10 | diff --git a/secded_gen.py b/secded_gen.py 11 | index 4a32f6433..24056ce3d 100755 12 | --- a/secded_gen.py 13 | +++ b/secded_gen.py 14 | @@ -180,6 +180,47 @@ def print_dec(n, k, m, codes, codetype, print_type="logic"): 15 | outstr += " {}".format(preamble) + "err_o[1] = ~single_error & (|syndrome_o);\n" 16 | return outstr 17 | 18 | +def print_cor(n, k, m, codes, codetype, print_type="logic"): 19 | + 20 | + preamble = PRINT_OPTIONS[print_type] 21 | + 22 | + outstr = "" 23 | + if codetype == "hsiao": 24 | + outstr += " {}logic single_error;\n".format( 25 | + preamble if print_type == "function" else "") 26 | + 27 | + outstr += "\n" 28 | + outstr += " {}// Syndrome calculation\n".format( 29 | + preamble if print_type == "function" else "") 30 | + format_str = " {}".format(preamble) + "syndrome_o[{}] = ^(d_i & " \ 31 | + + str(n) + "'h{:0" + str((n + 3) // 4) + "X});\n" 32 | + 33 | + # Print syndrome computation 34 | + for j, mask in enumerate(calc_bitmasks(k, m, codes, True)): 35 | + outstr += format_str.format(j, mask) 36 | + outstr += "\n" 37 | + outstr += " {}// Corrected output calculation\n".format( 38 | + preamble if print_type == "function" else "") 39 | + for i in range(k): 40 | + outstr += " {}".format(preamble) + "d_o[%d] = (syndrome_o == %d'h%x) ^ d_i[%d];\n" % ( 41 | + i, m, calc_syndrome(codes[i]), i) 42 | + for i in range(n-k): 43 | + outstr += " {}".format(preamble) + "d_o[%d] = (syndrome_o == %d'h%x) ^ d_i[%d];\n" % ( 44 | + i+k, m, 2**i, i+k) 45 | + outstr += "\n" 46 | + outstr += " {}// err_o calc. bit0: single error, bit1: double error\n".format( 47 | + preamble if print_type == "function" else "") 48 | + # The Hsiao and Hamming syndromes are interpreted slightly differently. 49 | + if codetype == "hamming": 50 | + outstr += " {}".format(preamble) + "err_o[0] = syndrome_o[%d];\n" % (m - 1) 51 | + outstr += " {}".format(preamble) + "err_o[1] = |syndrome_o[%d:0] & ~syndrome_o[%d];\n" % ( 52 | + m - 2, m - 1) 53 | + else: 54 | + outstr += " {}".format(preamble) + "single_error = ^syndrome_o;\n" 55 | + outstr += " {}".format(preamble) + "err_o[0] = single_error;\n" 56 | + outstr += " {}".format(preamble) + "err_o[1] = ~single_error & (|syndrome_o);\n" 57 | + return outstr 58 | + 59 | 60 | # return whether an integer is a power of 2 61 | def is_pow2(n): 62 | @@ -440,6 +481,25 @@ endmodule : {}_dec 63 | (m - 1), dec_out, module_name) 64 | f.write(outstr) 65 | 66 | + cor_out = print_cor(n, k, m, codes, codetype) 67 | + 68 | + with open(outdir + "/" + module_name + "_cor.sv", "w") as f: 69 | + outstr = '''{}// SECDED Corrector generated by 70 | +// util/design/secded_gen.py -m {} -k {} -s {} -c {} 71 | + 72 | +module {}_cor ( 73 | + input [{}:0] d_i, 74 | + output logic [{}:0] d_o, 75 | + output logic [{}:0] syndrome_o, 76 | + output logic [1:0] err_o 77 | +); 78 | + 79 | +{} 80 | +endmodule : {}_cor 81 | +'''.format(COPYRIGHT, m, k, s, codetype, module_name, (n - 1), (n - 1), 82 | + (m - 1), cor_out, module_name) 83 | + f.write(outstr) 84 | + 85 | 86 | def write_fpv_files(n, k, m, codes, suffix, outdir): 87 | module_name = "prim_secded%s_%d_%d" % (suffix, n, k) 88 | -- 89 | 2.31.1 90 | 91 | -------------------------------------------------------------------------------- /util/patches/lowrisc_secded_gen/0002-Update-SECDED-Encoder-modules-to-prevent-circular-de.patch: -------------------------------------------------------------------------------- 1 | From 813ee7ccce1c1a1ee002721eb563e0efcd3ff1b5 Mon Sep 17 00:00:00 2001 2 | From: Michael Rogenmoser 3 | Date: Fri, 7 Jul 2023 14:45:02 +0200 4 | Subject: [PATCH] Update SECDED Encoder modules to prevent circular 5 | dependancies 6 | 7 | --- 8 | secded_gen.py | 12 ++++-------- 9 | 1 file changed, 4 insertions(+), 8 deletions(-) 10 | 11 | diff --git a/secded_gen.py b/secded_gen.py 12 | index 24056ce3d..1d1c6afbc 100755 13 | --- a/secded_gen.py 14 | +++ b/secded_gen.py 15 | @@ -128,9 +128,9 @@ def print_fn(n, k, m, codes, suffix, codetype): 16 | 17 | 18 | def print_enc(n, k, m, codes): 19 | - outstr = " out = {}'(in);\n".format(n) 20 | - format_str = " out[{}] = ^(out & " + str(n) + "'h{:0" + str( 21 | - (n + 3) // 4) + "X});\n" 22 | + outstr = " out[{}:0] = in;\n".format(k-1) 23 | + format_str = " out[{}] = ^(in & " + str(k) + "'h{:0" + str( 24 | + (k + 3) // 4) + "X});\n" 25 | # Print parity computation 26 | for j, mask in enumerate(calc_bitmasks(k, m, codes, False)): 27 | outstr += format_str.format(j + k, mask) 28 | @@ -412,16 +412,12 @@ def hamming_code(k, m): 29 | pos, parity_pos, parity_chk)) 30 | 31 | # valid for inclusion or final parity bit that includes everything 32 | - if is_odd(parity_chk) or p == m - 1: 33 | + if is_odd(parity_chk) or (p == m - 1 and (len(code) % 2) == 0): 34 | code = code + (p, ) 35 | log.info("add {} to tuple {}".format(p, code)) 36 | 37 | codes.append(code) 38 | 39 | - # final parity bit includes all ECC bits 40 | - for p in range(m - 1): 41 | - codes.append((m - 1, )) 42 | - 43 | log.info("Hamming codes {}".format(codes)) 44 | return codes 45 | 46 | -- 47 | 2.31.1 48 | 49 | -------------------------------------------------------------------------------- /util/patches/lowrisc_secded_gen/0003-secded-add-iterative-algorithm-for-secded-Hsiao-matr.patch: -------------------------------------------------------------------------------- 1 | From 155f364ab1efc6edcd6c1cdfe493700d1df322c4 Mon Sep 17 00:00:00 2001 2 | From: Michael Rogenmoser 3 | Date: Tue, 16 Jan 2024 15:37:31 +0100 4 | Subject: [PATCH] [secded] add iterative algorithm for secded Hsiao matrix 5 | 6 | --- 7 | secded_gen.py | 74 ++++++++++++++++++++++++++++++++++++--------------- 8 | 1 file changed, 53 insertions(+), 21 deletions(-) 9 | 10 | diff --git a/secded_gen.py b/secded_gen.py 11 | index 1d1c6afbcc..06f6cc8694 100755 12 | --- a/secded_gen.py 13 | +++ b/secded_gen.py 14 | @@ -344,31 +344,63 @@ def hsiao_code(k, m): 15 | 16 | # Calculate each row fan-in with current 17 | fanins = calc_fanin(m, codes) 18 | + 19 | + subset = [] 20 | + other = candidate[:] 21 | + 22 | + max_fanin = max(fanins) 23 | + 24 | while required_row != 0: 25 | - # Let's shuffle 26 | - # Shuffling makes the sequence randomized --> it reduces the 27 | - # fanin as the code takes randomly at the end of the round 28 | - 29 | - # TODO: There should be a clever way to find the subset without 30 | - # random retrying. 31 | - # Suggested this algorithm 32 | - # https://en.wikipedia.org/wiki/Assignment_problem 33 | - random.shuffle(candidate) 34 | - 35 | - # Take a subset 36 | - subset = candidate[0:required_row] 37 | - 38 | - subset_fanins = calc_fanin(m, subset) 39 | - # Check if it exceeds Ideal Fan-In 40 | - ideal = True 41 | + current_fanins = calc_fanin(m, subset) 42 | for i in range(m): 43 | - if fanins[i] + subset_fanins[i] > fanin_ideal: 44 | - # Exceeded. Retry 45 | - ideal = False 46 | + current_fanins[i] += fanins[i] 47 | + 48 | + added = False 49 | + 50 | + min_fanin = min(current_fanins) 51 | + 52 | + # First add to increase minimum while keeping max low 53 | + for i in range(len(other)): 54 | + tmp_fanins = current_fanins[:] 55 | + 56 | + for j in range(step): 57 | + tmp_fanins[other[i][j]] += 1 58 | + 59 | + if min(tmp_fanins) > min_fanin and max(tmp_fanins) <= max_fanin: 60 | + added = True 61 | + subset.append(other[i]) 62 | + other.pop(i) 63 | + required_row -= 1 64 | break 65 | 66 | - if ideal: 67 | - required_row = 0 68 | + if (added): 69 | + continue 70 | + 71 | + # Then add to increase maximum if previous did not work 72 | + for i in range(len(other)): 73 | + tmp_fanins = current_fanins[:] 74 | + 75 | + for j in range(step): 76 | + tmp_fanins[other[i][j]] += 1 77 | + if max(tmp_fanins) <= max_fanin: 78 | + added = True 79 | + subset.append(other[i]) 80 | + other.pop(i) 81 | + required_row -= 1 82 | + break 83 | + 84 | + if not added: 85 | + max_fanin += 1 86 | + 87 | + subset_fanins = calc_fanin(m, subset) 88 | + 89 | + # Check if it exceeds Ideal Fan-In 90 | + # ideal = True 91 | + for i in range(m): 92 | + if fanins[i] + subset_fanins[i] > fanin_ideal: 93 | + # Exceeded. Retry 94 | + # ideal = False 95 | + print("Not Ideal!!!") 96 | 97 | # Append to the code matrix 98 | codes.extend(subset) 99 | -- 100 | 2.39.3 101 | 102 | --------------------------------------------------------------------------------