feat(fpga): Add Ibex core IP and generation docs Change-Id: Ia89d87940b11e60e17c74669a36fc5cbe7694cb2
diff --git a/fpga/ip/README.md b/fpga/ip/README.md new file mode 100644 index 0000000..9c9cdb0 --- /dev/null +++ b/fpga/ip/README.md
@@ -0,0 +1,33 @@ +# Generating the Ibex Core + +This document describes the process for generating the custom `rv_core_ibex` IP block for the Kelvin SoC. + +The IP is generated using the `ipgen.py` script from the OpenTitan repository. This script takes an IP template and a configuration file as input and generates a concrete IP block in an output directory. + +## Generation Command + +To generate the `rv_core_ibex` IP, run the following command from the root of the repository: + +```bash +python3 opentitan/util/ipgen.py generate \ + -C opentitan/hw/ip_templates/rv_core_ibex \ + -c fpga/ip/kelvin_rv_core_ibex.ipconfig.hjson \ + -o fpga/ip/rv_core_ibex \ + --force +``` + +## Dependencies + +The `ipgen.py` script has several Python dependencies that must be installed: + +* `hjson` +* `mako` +* `semantic_version` +* `tabulate` +* `pycryptodome` + +## Output + +The script will generate the `rv_core_ibex` IP block in the `fpga/ip/rv_core_ibex` directory. This will include the `.core` file, the RTL files, and any other necessary files for the IP. + +``` \ No newline at end of file
diff --git a/fpga/ip/kelvin_rv_core_ibex.ipconfig.hjson b/fpga/ip/kelvin_rv_core_ibex.ipconfig.hjson new file mode 100644 index 0000000..207dd33 --- /dev/null +++ b/fpga/ip/kelvin_rv_core_ibex.ipconfig.hjson
@@ -0,0 +1,24 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +{ + instance_name: kelvin_rv_core_ibex + param_values: + { + racl_support: false + num_regions: 2 + module_instance_name: rv_core_ibex + topname: kelvin + uniquified_modules: {} + } +}
diff --git a/fpga/ip/rv_core_ibex/BUILD b/fpga/ip/rv_core_ibex/BUILD new file mode 100644 index 0000000..31d27e1 --- /dev/null +++ b/fpga/ip/rv_core_ibex/BUILD
@@ -0,0 +1,22 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "rtl_files", + srcs = glob( + ["**"], + exclude = [ + "dv/**", + "doc/**", + "README.md", + ], + ), +) + +filegroup( + name = "doc_files", + srcs = glob(["**/*.md"]), +)
diff --git a/fpga/ip/rv_core_ibex/README.md b/fpga/ip/rv_core_ibex/README.md new file mode 100644 index 0000000..359edf2 --- /dev/null +++ b/fpga/ip/rv_core_ibex/README.md
@@ -0,0 +1,32 @@ +# Ibex RISC-V Core Wrapper Technical Specification + +[`rv_core_ibex`](https://ibex.reports.lowrisc.org/opentitan/latest/report.html): + + + + + +# Overview + +This document specifies Ibex CPU core wrapper functionality. + +## Features + +* Instantiation of a [Ibex RV32 CPU Core](https://github.com/lowRISC/ibex). +* TileLink Uncached Light (TL-UL) host interfaces for the instruction and data ports. +* Simple address translation. +* NMI support for security alert events for watchdog bark. +* General error status collection and alert generation. +* Crash dump collection for software debug. + +## Description + +The Ibex RISC-V Core Wrapper instantiates an [Ibex RV32 CPU Core](https://github.com/lowRISC/ibex), and wraps its data and instruction memory interfaces to TileLink Uncached Light (TL-UL). +All configuration parameters of Ibex are passed through. +The pipelining of the bus adapters is configurable. + +## Compatibility + +Ibex is a compliant RV32 RISC-V CPU core, as [documented in the Ibex documentation](https://ibex-core.readthedocs.io/en/latest/01_overview/compliance.html). + +The TL-UL bus interfaces exposed by this wrapper block are compliant to the [TileLink Uncached Lite Specification version 1.7.1](https://sifive.cdn.prismic.io/sifive%2F57f93ecf-2c42-46f7-9818-bcdd7d39400a_tilelink-spec-1.7.1.pdf).
diff --git a/fpga/ip/rv_core_ibex/data/BUILD b/fpga/ip/rv_core_ibex/data/BUILD new file mode 100644 index 0000000..f7bfd91 --- /dev/null +++ b/fpga/ip/rv_core_ibex/data/BUILD
@@ -0,0 +1,15 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"]) + +exports_files(["kelvin_rv_core_ibex.ipconfig.hjson"]) + +filegroup( + name = "doc_files", + srcs = glob([ + "rv_core_ibex.hjson", + "*_testplan.hjson", + ]), +)
diff --git a/fpga/ip/rv_core_ibex/data/kelvin_rv_core_ibex.ipconfig.hjson b/fpga/ip/rv_core_ibex/data/kelvin_rv_core_ibex.ipconfig.hjson new file mode 100644 index 0000000..579f73c --- /dev/null +++ b/fpga/ip/rv_core_ibex/data/kelvin_rv_core_ibex.ipconfig.hjson
@@ -0,0 +1,23 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + instance_name: kelvin_rv_core_ibex + param_values: + { + racl_support: false + num_regions: 2 + module_instance_name: rv_core_ibex + topname: kelvin + uniquified_modules: {} + } + dtgen: + { + num_regions: + { + type: uint8 + name: num_regions + doc: Number of translatable regions per ibex bus + } + } +}
diff --git a/fpga/ip/rv_core_ibex/data/rv_core_ibex.hjson b/fpga/ip/rv_core_ibex/data/rv_core_ibex.hjson new file mode 100644 index 0000000..5356904 --- /dev/null +++ b/fpga/ip/rv_core_ibex/data/rv_core_ibex.hjson
@@ -0,0 +1,1082 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + name: "rv_core_ibex", + human_name: "RISC-V Core Wrapper for Ibex", + one_line_desc: "Dual-core lockstep 32-bit RISC-V processor running application and control software", + one_paragraph_desc: ''' + Ibex is a production-quality open source 32-bit RISC-V CPU core serving as main processor onto which OpenTitan application and control software is deployed. + The configuration used in OpenTitan implements the RV32IMCB ISA with a 3-stage pipeline and a single-cycle multiplier, user and machine execution modes, PMP+Smepmp, and a 4 KiB instruction cache with 2 ways and low-latency scrambling. + Further security features include dual-core lockstep operation, bus and register file integrity, PC hardening, data independent timing, and dummy instruction insertion. + Ibex integrates into OpenTitan through RISC-V Core Wrapper for Ibex, which wraps Ibex's data and instruction memory interfaces to TileLink Uncached Light (TL-UL) host interfaces and providing a set of configuration and status register for supporting simple address translation and access to random numbers provided by CSRNG. + In addition, RISC-V Core Wrapper for Ibex handles the forwarding of crash dump data. + Debug support is enabled through RISC-V Debug Module. + ''' + // Unique comportable IP identifier defined under KNOWN_CIP_IDS in the regtool. + cip_id: "23", + design_spec: "../doc", + hw_checklist: "../doc/checklist", + sw_checklist: "/sw/device/lib/dif/dif_rv_core_ibex", + dv_doc: "../doc/dv", + version: "2.1.0", + life_stage: "L1", + design_stage: "D2S", + verification_stage: "V2S", + dif_stage: "S2", + notes: "Ibex Verification is tracked in the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/03_reference/verification_stages.html)." + clocking: [{clock: "clk_i", reset: "rst_ni", primary: true}, + {clock: "clk_edn_i", reset: "rst_edn_ni"} + {clock: "clk_esc_i", reset: "rst_esc_ni"}, + {clock: "clk_otp_i", reset: "rst_otp_ni"}, + ], + bus_interfaces: [ + { protocol: "tlul", direction: "host", name: "corei" } + { protocol: "tlul", direction: "host", name: "cored" } + { protocol: "tlul", direction: "device", name: "cfg" } + ], + scan: "true", // Enable `scanmode_i` port + scan_reset: "true", // Enable `scan_rst_ni` port + interrupt_list: [], + alert_list: [ + { name: "fatal_sw_err", + desc: "Software triggered alert for fatal faults", + }, + { name: "recov_sw_err", + desc: "Software triggered Alert for recoverable faults", + }, + { name: "fatal_hw_err", + desc: ''' + Triggered when + - Ibex raises `alert_major_internal_o` + - Ibex raises `alert_major_bus_o` + - A double fault is seen (Ibex raises `double_fault_seen_o`) + - A bus integrity error is seen + ''' + }, + { name: "recov_hw_err", + desc: "Triggered when Ibex raises `alert_minor_o`", + }, + ], + + inter_signal_list: [ + { struct: "logic", + type: "uni", + name: "rst_cpu_n", + act: "req", + package: "", + }, + + { struct: "ram_1p_cfg", + type: "uni", + name: "ram_cfg_icache_tag", + act: "rcv", + package: "prim_ram_1p_pkg", + }, + + { struct: "ram_1p_cfg_rsp", + type: "uni", + name: "ram_cfg_rsp_icache_tag", + width: "ICacheNWays", + act: "req", + package: "prim_ram_1p_pkg", + }, + + { struct: "ram_1p_cfg", + type: "uni", + name: "ram_cfg_icache_data", + act: "rcv", + package: "prim_ram_1p_pkg", + }, + + { struct: "ram_1p_cfg_rsp", + type: "uni", + name: "ram_cfg_rsp_icache_data", + width: "ICacheNWays", + act: "req", + package: "prim_ram_1p_pkg", + }, + + { struct: "logic", + type: "uni", + name: "hart_id", + act: "rcv", + package: "", + width: "32", + }, + + { struct: "logic", + type: "uni", + name: "boot_addr", + act: "rcv", + package: "", + width: "32", + }, + + { struct: "logic", + type: "uni", + name: "irq_software", + act: "rcv", + package: "", + }, + + { struct: "logic", + type: "uni", + name: "irq_timer", + act: "rcv", + package: "", + }, + + { struct: "logic", + type: "uni", + name: "irq_external", + act: "rcv", + package: "", + }, + + { struct: "esc_tx", + type: "uni", + name: "esc_tx", + act: "rcv", + package: "prim_esc_pkg", + }, + + { struct: "esc_rx", + type: "uni", + name: "esc_rx", + act: "req", + package: "prim_esc_pkg", + }, + + { struct: "logic", + type: "uni", + name: "debug_req", + act: "rcv", + package: "", + }, + + { struct: "cpu_crash_dump", + type: "uni", + name: "crash_dump", + act: "req", + package: "rv_core_ibex_pkg", + }, + + { struct: "lc_tx", + type: "uni", + name: "lc_cpu_en", + act: "rcv", + package: "lc_ctrl_pkg", + default: "lc_ctrl_pkg::On", + }, + + { struct: "lc_tx", + type: "uni", + name: "pwrmgr_cpu_en", + act: "rcv", + package: "lc_ctrl_pkg", + }, + + { struct: "cpu_pwrmgr", + type: "uni", + name: "pwrmgr", + act: "req", + package: "rv_core_ibex_pkg", + }, + + { struct: "logic", + type: "uni", + name: "nmi_wdog", + act: "rcv", + package: "", + }, + + { struct: "edn", + type: "req_rsp", + name: "edn", + act: "req", + package: "edn_pkg", + }, + + { struct: "sram_otp_key", + type: "req_rsp", + name: "icache_otp_key", + act: "req", + package: "otp_ctrl_pkg", + }, + + { struct: "logic", + type: "uni", + name: "fpga_info", + act: "rcv", + width: "32", + package: "", + }, + + ], + param_list: [ + # Random netlist constants + { name: "RndCnstLfsrSeed", + type: "ibex_pkg::lfsr_seed_t", + desc: "Default seed of the PRNG used for random instructions." + randcount: "32", + randtype: "data" + }, + { name: "RndCnstLfsrPerm", + type: "ibex_pkg::lfsr_perm_t", + desc: "Permutation applied to the LFSR of the PRNG used for random instructions." + randcount: "32", + randtype: "perm" + }, + { name: "RndCnstIbexKeyDefault", + type: "logic [ibex_pkg::SCRAMBLE_KEY_W-1:0]", + desc: "Default icache scrambling key" + randcount: "128", + randtype: "data" + }, + { name: "RndCnstIbexNonceDefault", + type: "logic [ibex_pkg::SCRAMBLE_NONCE_W-1:0]", + desc: "Default icache scrambling nonce" + randcount: "64", + randtype: "data" + }, + + { name: "NEscalationSeverities" + type: "int unsigned" + default: "4" + desc: "Number of escalation severities" + local: "false" + }, + + { name: "WidthPingCounter" + type: "int unsigned" + default: "16" + desc: "Width of the ping counter" + local: "false" + }, + + { name: "PMPEnable" + type: "bit" + default: "1'b0" + desc: "Enable PMP" + local: "false" + expose: "true" + }, + + { name: "PMPGranularity" + type: "int unsigned" + default: "0" + desc: "PMP Granularity" + local: "false" + expose: "true" + }, + + { name: "PMPNumRegions" + type: "int unsigned" + default: "4" + desc: "PMP number of regions" + local: "false" + expose: "true" + }, + + { name: "MHPMCounterNum" + type: "int unsigned" + default: "10" + desc: "Number of the MHPM counter " + local: "false" + expose: "true" + }, + + { name: "MHPMCounterWidth" + type: "int unsigned" + default: "32" + desc: "Width of the MHPM Counter " + local: "false" + expose: "true" + }, + { name: "PMPRstCfg" + type: "ibex_pkg::pmp_cfg_t" + default: "ibex_pkg::PmpCfgRst" + desc: "Reset value of PMP config CSRs" + local: "false" + expose: "true" + unpacked_dimensions: "[16]" + }, + { name: "PMPRstAddr" + type: "logic [33:0]" + default: "ibex_pkg::PmpAddrRst" + desc: "Reset value of PMP address CSRs" + local: "false" + expose: "true" + unpacked_dimensions: "[16]" + }, + { name: "PMPRstMsecCfg" + type: "ibex_pkg::pmp_mseccfg_t" + default: "ibex_pkg::PmpMseccfgRst" + desc: "Reset value of MSECCFG CSR" + local: "false" + expose: "true" + }, + { name: "RV32E" + type: "bit" + default: "0" + desc: "RV32E" + local: "false" + expose: "true" + }, + + { name: "RV32M" + type: "ibex_pkg::rv32m_e" + default: "ibex_pkg::RV32MSingleCycle" + desc: "RV32M" + local: "false" + expose: "true" + }, + + { name: "RV32B" + type: "ibex_pkg::rv32b_e" + default: "ibex_pkg::RV32BNone" + desc: "RV32B" + local: "false" + expose: "true" + }, + + { name: "RegFile" + type: "ibex_pkg::regfile_e" + default: "ibex_pkg::RegFileFF" + desc: "Reg file" + local: "false" + expose: "true" + }, + + { name: "BranchTargetALU" + type: "bit" + default: "1'b1" + desc: "Branch target ALU" + local: "false" + expose: "true" + }, + + { name: "WritebackStage" + type: "bit" + default: "1'b1" + desc: "Write back stage" + local: "false" + expose: "true" + }, + + { name: "ICache" + type: "bit" + default: "0" + desc: "Instruction cache" + local: "false" + expose: "true" + }, + + { name: "ICacheECC" + type: "bit" + default: "0" + desc: "Instruction cache ECC" + local: "false" + expose: "true" + }, + + { name: "ICacheScramble" + type: "bit" + default: "0" + desc: "Scramble instruction cach" + local: "false" + expose: "true" + }, + + { name: "ICacheNWays" + type: "int unsigned" + default: "2" + desc: "Number of instruction cache ways" + local: "false" + expose: "true" + }, + + { name: "BranchPredictor" + type: "bit" + default: "0" + desc: "Branch predictor" + local: "false" + expose: "true" + }, + + { name: "DbgTriggerEn" + type: "bit" + default: "1" + desc: "Enable degug trigger" + local: "false" + expose: "true" + }, + + { name: "DbgHwBreakNum" + type: "int" + default: "1" + desc: "Number of debug hardware break" + local: "false" + expose: "true" + }, + + { name: "SecureIbex" + type: "bit" + default: "0" + desc: "Width of the MHPM Counter " + local: "false" + expose: "true" + }, + + { name: "DmBaseAddr" + type: "int unsigned" + default: "437321728" //"32'h1A110000" + desc: "Base address of Debug Module" + local: "false" + expose: "true" + } + + { name: "DmAddrMask" + type: "int unsigned" + default: "4095" //"32'h00000FFF" + desc: "Adress mask of Debug Module" + local: "false" + expose: "true" + } + + { name: "DmHaltAddr" + type: "int unsigned" + default: "437323776" //"32'h1A110800" + desc: "Halt address" + local: "false" + expose: "true" + }, + + { name: "DmExceptionAddr" + type: "int unsigned" + default: "437323784" //"32'h1A110808" + desc: "Exception address" + local: "false" + expose: "true" + }, + + { name: "PipeLine" + type: "bit" + default: "1'b0" + desc: "Pipe line" + local: "false" + expose: "true" + }, + + { name: "NumSwAlerts", + desc: "Number of software triggerable alerts", + type: "int", + default: "2", + local: "true" + }, + + { name: "NumRegions", + desc: "Number of translatable regions per ibex bus", + type: "int", + default: "2", + local: "true" + }, + { name: "NumScratchWords", + type: "int", + desc: "Number of scratch words maintained." + default: "8" + }, + { name: "TlulHostUserRsvdBits" + type: "logic [tlul_pkg::RsvdWidth-1:0]" + default: "'0" + desc: "TLUL user bits sent on outgoing transfers." + local: "false" + expose: "true" + }, + { name: "CsrMvendorId" + type: "logic [31:0]" + desc: ''' + mvendorid: encoding of manufacturer/provider + 0 indicates this field is not implemented. + Ibex implementors may wish to set their own JEDEC ID here. + ''' + default: "'0" + local: "false" + expose: "true" + }, + { name: "CsrMimpId" + type: "logic [31:0]" + desc: ''' + mimpid: encoding of processor implementation version + 0 indicates this field is not implemented. + Ibex implementors may wish to indicate an RTL/netlist version here using their own unique encoding (e.g. 32 bits of the git hash of the implemented commit). + ''' + default: "'0" + local: "false" + expose: "true" + } + ], + features: [ + { + name: "RV_CORE_IBEX.CPU.ISA", + desc: ''' + Implements a RISC-V core capable of executing RV32ICMB instructions (a subset of bitmanip is + implemented, see the Ibex core documentation for details). + ''' + }, + { + name: "RV_CORE_IBEX.CPU.EPMP", + desc: ''' + The RISC-V core implements the ePMP scheme specified in the RISC-V privileged architecture + specification, 16 regions are available for use. + ''' + }, + { + name: "RV_CORE_IBEX.CPU.ICACHE" + desc: ''' + The RISC-V core implements an instruction caches that utilizes scrambling. The scrambling + key is rotated on a FENCE.I instruction being executed. + ''' + } + { + name: "RV_CORE_IBEX.CPU.MEMORY" + desc: ''' + The RISC-V core can send transactions on the TL-UL interconnect and access all of the + address space that is available + ''' + } + { + name: "RV_CORE_IBEX.CPU.INTERRUPTS" + desc: ''' + The RISC-V core has a number of interrupt sources: + - Software interrupt, controlled by a memory mapped PLIC register + - External interrupt, from interrupts prioritise by the PLIC + - Timer interrupt, from rv_timer module + - Non-maskable interrupt, triggered by watchdog or alert handler + ''' + } + { + name: "RV_CORE_IBEX.RND" + desc: ''' + The core wrapper has a connection to the EDN that provides 32-bit random numbers via a + memory mapped register. + ''' + } + { + name: "RV_CORE_IBEX.ADDRESS_TRANSLATION" + desc: ''' + The core wrapper implements address translation. RISC-V core memory accesses that match a + given range will have an offset applied before being sent to the memory system + ''' + } + { + name: "RV_CORE_IBEX.CRASH_DUMP" + desc: ''' + The core wrapper provides a 'crash dump' to rstmgr providing information on what was being + executed and most recent exception taken on a reset event. Where the RISC-V core has + detected a double fault a crash dump will be stored for when the double fault was detect as + well as the crash dump at reset. + ''' + } + ], + + countermeasures: [ + { name: "BUS.INTEGRITY", + desc: "End-to-end bus integrity scheme." + } + { name: "SCRAMBLE.KEY.SIDELOAD", + desc: "The scrambling key for the icache is sideloaded from OTP and thus unreadable by SW." + } + { name: "CORE.DATA_REG_SW.SCA", + desc: "Data independent timing." + } + { name: "PC.CTRL_FLOW.CONSISTENCY" + desc: "Correct PC increment check." + } + { name: "CTRL_FLOW.UNPREDICTABLE" + desc: "Randomized dummy instruction insertion." + } + { name: "DATA_REG_SW.INTEGRITY" + desc: ''' + Register file integrity checking. Note that whilst the core itself is + duplicated (see LOGIC.SHADOW) the register file is not. Protection is + provided by an ECC. + ''' + } + { name: "DATA_REG_SW.GLITCH_DETECT" + desc: ''' + This countermeasure augments DATA_REG_SW.INTEGRITY and checks for spurious + write-enable signals on the register file by monitoring the one-hot0 property + of the individual write-enable strobes. + ''' + } + { name: "LOGIC.SHADOW" + desc: ''' + Shadow core run in lockstep to crosscheck CPU behaviour. This provides + broad protection for all assets with the Ibex core. + ''' + } + { name: "FETCH.CTRL.LC_GATED" + desc: "Fetch enable so core execution can be halted." + } + { name: "EXCEPTION.CTRL_FLOW.LOCAL_ESC" + desc: ''' + A mechanism to detect and act on double faults. Local escalation shuts + down the core when a double fault is seen. + ''' + } + { name: "EXCEPTION.CTRL_FLOW.GLOBAL_ESC" + desc: ''' + A mechanism to detect and act on double faults. Global escalation + sends a fatal alert when a double fault is seen. + ''' + } + { name: "ICACHE.MEM.SCRAMBLE" + desc: "ICache memory scrambling." + } + { name: "ICACHE.MEM.INTEGRITY" + desc: "ICache memory integrity checking." + } + ] + + regwidth: "32", + registers: { + cfg: [ + { name: "SW_RECOV_ERR", + desc: ''' + Software recoverable error + ''', + swaccess: "rw", + hwaccess: "hrw", + fields: [ + { bits: "3:0", + mubi: true, + name: "VAL", + resval: false, + desc: ''' + Software recoverable alert. + When set to any value other than kMultiBitBool4False, a recoverable alert is sent. + Once the alert is sent, the field is then reset to kMultiBitBool4False. + ''' + }, + ], + tags: [// This register will self clear when set + "excl:CsrNonInitTests:CsrExclWriteCheck"], + }, + + { name: "SW_FATAL_ERR", + desc: ''' + Software fatal error + ''', + swaccess: "rw1s", + hwaccess: "hro", + fields: [ + { bits: "3:0", + mubi: true, + name: "VAL", + resval: false, + desc: ''' + Software fatal alert. + When set to any value other than kMultiBitBool4False, a fatal alert is sent. + Note, this field once cleared cannot be set and will continuously cause alert events. + ''' + }, + ] + tags: [// This register is sticky and cannot be cleared after being set + "excl:CsrNonInitTests:CsrExclWrite"], + }, + + { multireg: { + cname: "IBUS_REGWEN", + name: "IBUS_REGWEN", + desc: "Ibus address control regwen.", + count: "NumRegions", + swaccess: "rw0c", + hwaccess: "none", + compact: false, + fields: [ + { bits: "0", + name: "EN", + resval: "1", + desc: "Ibus address controls write enable. Once set to 0, it can longer be configured to 1", + enum: [ + { value: "0", + name: "locked", + desc: ''' + Address controls can no longer be configured until next reset. + ''' + }, + { value: "1", + name: "enabled", + desc: ''' + Address controls can still be configured. + ''' + }, + ] + }, + ], + }, + }, + + { multireg: { + cname: "IBUS_ADDR_CFG", + name: "IBUS_ADDR_EN", + regwen: "IBUS_REGWEN", + regwen_multi: true, + desc: ''' + Enable Ibus address matching + ''', + count: "NumRegions", + compact: false, + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "EN", + desc: ''' + Enable ibus address matching. + ''', + resval: "0" + }, + ], + }, + }, + + { multireg: { + cname: "IBUS_ADDR_MATCHING", + name: "IBUS_ADDR_MATCHING", + regwen: "IBUS_REGWEN", + regwen_multi: true, + desc: ''' + Matching region programming for ibus. + + The value programmed is done at power-of-2 alignment. + For example, if the intended matching region is 0x8000_0000 to 0x8000_FFFF, the value programmed is 0x8000_7FFF. + + The value programmed can be determined from the translation granule. + Assume the user wishes to translate a specific 64KB block to a different address: + 64KB has a hex value of 0x10000. + Subtract 1 from this value and then right shift by one to obtain 0x7FFF. + This value is then logically OR'd with the upper address bits that would select which 64KB to translate. + + In this example, the user wishes to translate the 0x8000-th 64KB block. + The value programmed is then 0x8000_7FFF. + + If the user were to translate the 0x8001-th 64KB block, the value programmed would be 0x8001_7FFF. + ''', + count: "NumRegions", + compact: false, + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", + name: "VAL", + desc: ''' + Matching region value + ''', + resval: "0" + }, + ], + }, + }, + + { multireg: { + cname: "IBUS_REMAP_ADDR", + name: "IBUS_REMAP_ADDR", + regwen: "IBUS_REGWEN", + regwen_multi: true, + desc: ''' + The remap address after a match has been made. + The remap bits apply only to top portion of address bits not covered by the matching region. + + For example, if the translation region is 64KB, the remapped address applies only to the upper + address bits that select which 64KB to be translated. + ''', + count: "NumRegions", + compact: false, + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", + name: "VAL", + desc: ''' + Remap addr value + ''', + resval: "0" + }, + ], + }, + }, + + { multireg: { + cname: "DBUS_REGWEN", + name: "DBUS_REGWEN", + desc: "Dbus address control regwen.", + count: "NumRegions", + swaccess: "rw0c", + hwaccess: "none", + compact: false, + fields: [ + { bits: "0", + name: "EN", + resval: "1", + desc: "Ibus address controls write enable. Once set to 0, it can longer be configured to 1", + enum: [ + { value: "0", + name: "locked", + desc: ''' + Address controls can no longer be configured until next reset. + ''' + }, + { value: "1", + name: "enabled", + desc: ''' + Address controls can still be configured. + ''' + }, + ] + }, + ], + }, + }, + + { multireg: { + cname: "DBUS_ADDR_CFG", + name: "DBUS_ADDR_EN", + regwen: "DBUS_REGWEN", + regwen_multi: true, + desc: ''' + Enable dbus address matching + ''', + count: "NumRegions", + compact: false, + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "EN", + desc: ''' + Enable dbus address matching. + ''', + resval: "0" + }, + ], + }, + }, + + { multireg: { + cname: "DBUS_ADDR_MATCHING", + name: "DBUS_ADDR_MATCHING", + regwen: "DBUS_REGWEN", + regwen_multi: true, + desc: ''' + See !!IBUS_ADDR_MATCHING_0 for detailed description. + ''', + count: "NumRegions", + compact: false, + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", + name: "VAL", + desc: ''' + Matching region value + ''', + resval: "0" + }, + ], + }, + }, + + { multireg: { + cname: "DBUS_REMAP_ADDR", + name: "DBUS_REMAP_ADDR", + regwen: "DBUS_REGWEN", + regwen_multi: true, + desc: ''' + See !!IBUS_REMAP_ADDR_0 for a detailed description. + ''', + count: "NumRegions", + compact: false, + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:0", + name: "VAL", + desc: ''' + Remap addr value + ''', + resval: "0" + }, + ], + }, + }, + + { name: "NMI_ENABLE", + desc: ''' + Enable mask for NMI. + Once an enable mask is set, it cannot be disabled. + ''', + swaccess: "rw1s", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "ALERT_EN", + resval: "0x0", + desc: "Enable mask for alert NMI" + }, + { bits: "1", + name: "WDOG_EN", + resval: "0x0", + desc: "Enable mask for watchdog NMI" + }, + ] + }, + + { name: "NMI_STATE", + desc: ''' + Current NMI state + ''', + swaccess: "rw1c", + hwaccess: "hrw", + fields: [ + { bits: "0", + name: "ALERT", + resval: "0x0", + desc: "Current state for alert NMI" + }, + { bits: "1", + name: "WDOG", + resval: "0x0", + desc: "Current state for watchdog NMI" + }, + ] + tags: [// nmi could be updated by HW + "excl:CsrNonInitTests:CsrExclWriteCheck"], + }, + + { name: "ERR_STATUS", + desc: "error status", + swaccess: "rw1c", + hwaccess: "hwo", + fields: [ + { bits: "0", + name: "REG_INTG_ERR", + resval: "0x0" + desc: ''' + rv_core_ibex_peri detected a register transmission integrity error + ''' + }, + { bits: "8", + name: "FATAL_INTG_ERR", + resval: "0x0" + desc: ''' + rv_core_ibex detected a response integrity error + ''' + }, + { bits: "9", + name: "FATAL_CORE_ERR", + resval: "0x0" + desc: ''' + rv_core_ibex detected a fatal internal error + (``alert_major_internal_o`` from Ibex seen) + ''' + }, + { bits: "10", + name: "RECOV_CORE_ERR", + resval: "0x0" + desc: ''' + rv_core_ibex detected a recoverable internal error + (``alert_minor`` from Ibex seen) + ''' + }, + ] + }, + + { name: "RND_DATA", + desc: "Random data from EDN", + swaccess: "ro", + hwaccess: "hrw", + hwext: "true", + hwre: "true", + fields: [ + { bits: "31:0", + name: "DATA", + resval: "0x0", + desc: ''' + Random bits taken from the EDN. !!RND_STATUS.RND_DATA_VALID + indicates if this data is valid. When valid, reading from this + register invalidates the data and requests new data from the EDN. + The register becomes valid again when the EDN provides new data. + When invalid the register value will read as 0x0 with an EDN + request for new data pending. Upon reset the data will be invalid + with a new EDN request pending. + ''' + }, + ] + }, + + { name: "RND_STATUS", + desc: "Status of random data in !!RND_DATA", + swaccess: "ro", + hwaccess: "hwo", + hwext: "true", + fields: [ + { bits: "0", + resval: "0", + name: "RND_DATA_VALID", + desc: ''' + When set, the data in !!RND_DATA is valid. When clear an EDN + request for new data for !!RND_DATA is pending. + ''' + }, + { bits: "1", + resval: "0", + name: "RND_DATA_FIPS", + desc: ''' + When !!RND_STATUS.RND_DATA_VALID is 1, this bit indicates whether + !!RND_DATA is fips quality. + + When !!RND_STATUS.RND_DATA_VALID is 0, this bit has no meaning. + ''' + }, + ] + }, + + { name: "FPGA_INFO", + desc: ''' + FPGA build timestamp info. + This register only contains valid data for fpga, for all other variants it is simply 0. + ''', + swaccess: "ro", + hwaccess: "hwo", + hwext: "true" + fields: [ + { bits: "31:0", + name: "VAL", + resval: "0x0" + desc: ''' + FPGA build timestamp information. + ''' + }, + ] + }, + + // dv simulation window + { window: { + name: "DV_SIM_WINDOW", + items: "NumScratchWords", + validbits: "32", + byte-write: "true", + swaccess: "rw", + unusual: "true" + desc: ''' + Exposed tlul window for DV only purposes. + ''' + }, + }, + + ], + }, +}
diff --git a/fpga/ip/rv_core_ibex/data/rv_core_ibex_sec_cm_testplan.hjson b/fpga/ip/rv_core_ibex/data/rv_core_ibex_sec_cm_testplan.hjson new file mode 100644 index 0000000..766f8fc --- /dev/null +++ b/fpga/ip/rv_core_ibex/data/rv_core_ibex_sec_cm_testplan.hjson
@@ -0,0 +1,105 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Security countermeasures testplan extracted from the IP Hjson using reggen. +// +// This testplan is auto-generated only the first time it is created. This is +// because this testplan needs to be hand-editable. It is possible that these +// testpoints can go out of date if the spec is updated with new +// countermeasures. When `reggen` is invoked when this testplan already exists, +// It checks if the list of testpoints is up-to-date and enforces the user to +// make further manual updates. +// +// These countermeasures and their descriptions can be found here: +// .../rv_core_ibex/data/rv_core_ibex.hjson +// +// It is possible that the testing of some of these countermeasures may already +// be covered as a testpoint in a different testplan. This duplication is ok - +// the test would have likely already been developed. We simply map those tests +// to the testpoints below using the `tests` key. +// +// Please ensure that this testplan is imported in: +// .../rv_core_ibex/data/rv_core_ibex_testplan.hjson +{ + testpoints: [ + { + name: sec_cm_bus_integrity + desc: "Verify the countermeasure(s) BUS.INTEGRITY." + stage: V2S + tests: [] + } + { + name: sec_cm_scramble_key_sideload + desc: "Verify the countermeasure(s) SCRAMBLE.KEY.SIDELOAD." + stage: V2S + tests: [] + } + { + name: sec_cm_core_data_reg_sw_sca + desc: "Verify the countermeasure(s) CORE.DATA_REG_SW.SCA." + stage: V2S + tests: [] + } + { + name: sec_cm_pc_ctrl_flow_consistency + desc: "Verify the countermeasure(s) PC.CTRL_FLOW.CONSISTENCY." + stage: V2S + tests: [] + } + { + name: sec_cm_ctrl_flow_unpredictable + desc: "Verify the countermeasure(s) CTRL_FLOW.UNPREDICTABLE." + stage: V2S + tests: [] + } + { + name: sec_cm_data_reg_sw_integrity + desc: "Verify the countermeasure(s) DATA_REG_SW.INTEGRITY." + stage: V2S + tests: [] + } + { + name: sec_cm_data_reg_sw_glitch_detect + desc: "Verify the countermeasure(s) DATA_REG_SW.GLITCH_DETECT." + stage: V2S + tests: [] + } + { + name: sec_cm_logic_shadow + desc: "Verify the countermeasure(s) LOGIC.SHADOW." + stage: V2S + tests: [] + } + { + name: sec_cm_fetch_ctrl_lc_gated + desc: "Verify the countermeasure(s) FETCH.CTRL.LC_GATED." + stage: V2S + tests: [] + } + { + name: sec_cm_exception_ctrl_flow_local_esc + desc: "Verify the countermeasure(s) EXCEPTION.CTRL_FLOW.LOCAL_ESC." + stage: V2S + tests: [] + } + { + name: sec_cm_exception_ctrl_flow_global_esc + desc: "Verify the countermeasure(s) EXCEPTION.CTRL_FLOW.GLOBAL_ESC." + stage: V2S + tests: [] + } + { + name: sec_cm_icache_mem_scramble + desc: "Verify the countermeasure(s) ICACHE.MEM.SCRAMBLE." + stage: V2S + tests: [] + } + { + name: sec_cm_icache_mem_integrity + desc: "Verify the countermeasure(s) ICACHE.MEM.INTEGRITY." + stage: V2S + tests: [] + } + ] +}
diff --git a/fpga/ip/rv_core_ibex/data/rv_core_ibex_testplan.hjson b/fpga/ip/rv_core_ibex/data/rv_core_ibex_testplan.hjson new file mode 100644 index 0000000..dd1b140 --- /dev/null +++ b/fpga/ip/rv_core_ibex/data/rv_core_ibex_testplan.hjson
@@ -0,0 +1,347 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + name: "rv_core_ibex" + import_testplans: ["rv_core_ibex_sec_cm_testplan.hjson"] + testpoints: [ + { + name: riscv_arithmetic_basic_test + desc: ''' + Sanity test for basic RV32I instructions + - Generate instruction binary and load to memory model + - Only arithmetic instructions are generated + - Assert fetch enable to start the core execution + - Terminate the test after ecall instructinon in detected + - All instruction results are compared against spike simulation''' + stage: V1 + tests: ["riscv_arithmetic_basic_test"] + } + { + name: riscv_rand_instr_test + desc: ''' + Fully randomized RV32IMC instructions + - Including all types of instructions + - forward/backward branches + - directed sequence for various hazard conditions + - mixed load/store instructions + - random jump instructions + - fence instructions (treated as nop) + - mret instruction + - corner cases for each instruction (overflow, underflow, div by zero etc.)''' + stage: V1 + tests: ["riscv_rand_instr_test"] + } + { + name: riscv_machine_mode_rand_test + desc: ''' + Fully randomized RV32IMC instructions + - boot into Machine Mode''' + stage: V1 + tests: ["riscv_machine_mode_rand_test"] + } + { + name: riscv_rand_jump_test + desc: ''' + Stresses I-Fetch operation: + - Generates a large number of subprograms and frequently jumps between them''' + stage: V1 + tests: ["riscv_rand_jump_test"] + } + { + name: riscv_jump_stress_test + desc: ''' + Stresses I-Fetch operation: + - Generates sequences of many back-to-back jump instructions''' + stage: V1 + tests: ["riscv_jump_stress_test"] + } + { + name: riscv_loop_test + desc: ''' + Generate directed sequences of loops to test branch operations''' + stage: V1 + tests: ["riscv_loop_test"] + } + { + name: riscv_mmu_stress_test + desc: ''' + Create various load/store patterns to stress LSU + - load/store from random addresses + - load/store from dense or sparse locations + - back-to-back load/store instructions + - cover all byte/half-word/word load/store instructions + - load/store with hazard conditions''' + stage: V1 + tests: ["riscv_mmu_stress_test"] + } + { + name: riscv_unaligned_load_store_test + desc: ''' + Random mis-aligned half-word/word load/store instruction + Expect the core finishes the load/store properly with no exception raised''' + stage: V1 + tests: ["riscv_unaligned_load_store_test"] + } + { + name: riscv_mem_error_test + desc: ''' + Randomly assert error bit for instruction fetch and load/store. + Expect the core to raise memory access fault exception + Verify the fault load instruction won't modify GPR + Verify the context of the exception is captured correctly in privileged CSRs + - mstatus, mcause, mepc''' + stage: V1 + tests: ["riscv_mem_error_test"] + } + { + name: riscv_illegal_instr_test + desc: ''' + Randomly inject below illegal instructions in the instruction stream + - Instructions which not belong to RV32IMC + - Reserved instructions as specified in RISC-V user mode spec + - CSR instruction to not implemented CSR + - Execute S/U mode instructions in machine mode + Verify the illlegal instruction exception is raised and the context is captured correctly in privieged mode CSRs + - mstatus, mcause, mepc + Verify the core can resume execution after returning from trap handling''' + stage: V1 + tests: ["riscv_illegal_instr_test"] + } + { + name: riscv_hint_instr_test + desc: ''' + Randomly inject HINT instructions as specified in RISC-V user mode specification 5.4 + Verify the core execute it as NOP and no exception is raised''' + stage: V1 + tests: ["riscv_hint_instr_test"] + } + { + name: riscv_ebreak_test + desc: ''' + Generate random instructions including ebreak, expect core to raise ebreak exception''' + stage: V1 + tests: ["riscv_ebreak_test"] + } + { + name: riscv_debug_basic_test + desc: ''' + Randomly assert debug_req_i signal + - in debug_rom, insert normal random instruction sequence + excluding control transfer instructions + - verify wfi instructions act as NOPs + - ensure normal execution finishes successfully''' + stage: V1 + tests: ["riscv_debug_basic_test"] + } + { + name: riscv_debug_stress_test + desc: ''' + Randomly assert debug_req signal + - debug rom will consist of just a dret instructions, so any switches into + debug mode will immediately return + - will use this jointly with full instruction checking with spike''' + stage: V1 + tests: ["riscv_debug_stress_test"] + } + { + name: riscv_debug_branch_jump_test + desc: ''' + Randomly assert debug_req_i signal + - in debug_rom, insert random instruction sequence, + including control transfer instructions and multiple subprograms to + jump between''' + stage: V1 + tests: ["riscv_debug_branch_jump_test"] + } + { + name: riscv_debug_interrupt_test + desc: ''' + Randomly assert debug_req_i signal + - in debug_rom, insert random instruction sequence + - randomly toggle interrupts during debug code + - verify that execution of debug_rom continues as normal, interrupts are + ignored''' + stage: V2 + tests: ["riscv_debug_interrupt_test"] + } + { + name: riscv_debug_illegal_instr_test + desc: ''' + - insert illegal instruction into debug rom to trigger internal exception + - verify that no registers have been updated + - verify that execution of debug rom ends''' + stage: V2 + tests: ["riscv_debug_illegal_instr_test"] + } + { + name: riscv_debug_wfi_test + desc: ''' + Insert random generation of wfi instructions + - while core is in wfi sleep state, assert debug request + - verify core jumps to debug mode + - debug rom consists of random generation instructions''' + stage: V1 + tests: ["riscv_debug_wfi_test"] + } + { + name: riscv_dret_test + desc: ''' + Randomly insert dret instructions into M mode instructions + - verify that ibex treats them as illegal instructions''' + stage: V1 + tests: ["riscv_dret_test"] + } + { + name: riscv_debug_ebreak_test + desc: ''' + - insert ebreak instructions in M mode code, should be handled normally + - assert debug request + - in debug mode, insert ebreak instruction, verify that ibex re-enter debug mode''' + stage: V1 + tests: ["riscv_debug_ebreak_test"] + } + { + name: riscv_debug_ebreakmu_test + desc: ''' + - set dcsr.ebreakm/u at begining of test + - randomly insert ebreak instructions in generated code + - boot randomly into either M/U modes + - verify that ebreak instructions (in either mode) now enter debug mode''' + stage: V1 + tests: ["riscv_debug_ebreakmu_test"] + } + { + name: riscv_debug_single_step_test + desc: ''' + Randomly assert debug_req_i signal to force core into debug mode. + - in debug_rom, set dcsr.step + - after exiting debug mode, core will execute one instruction and re-enter + debug mode''' + stage: V1 + tests: ["riscv_debug_single_step_test"] + } + { + name: riscv_debug_csr_entry_test + desc: ''' + Inject debug stimulus during CSR modification operations, + core should jump to debug mode and return without any issues''' + stage: V1 + tests: ["riscv_debug_csr_entry_test"] + } + { + name: riscv_irq_in_debug_mode_test + desc: ''' + Randomly assert interrupt lines while the core is in debug mode execution, + verify that these interrupts are all completely ignored''' + stage: V1 + tests: ["riscv_irq_in_debug_mode_test"] + } + { + name: riscv_single_interrupt_test + desc: ''' + Randomly assert a single interrupt line during program execution, core + should jump to proper handler''' + stage: V1 + tests: ["riscv_single_interrupt_test"] + } + { + name: riscv_multiple_interrupt_test + desc: ''' + Randomly assert multiple interrupt lines during program execution, + core should jump to handler of highest priority interrupt''' + stage: V1 + tests: ["riscv_multiple_interrupt_test"] + } + { + name: riscv_interrupt_wfi_test + desc: ''' + Randomly assert interrupt lines while the core is sleeping due to a WFI instruction''' + stage: V1 + tests: ["riscv_interrupt_wfi_test"] + } + { + name: riscv_interrupt_csr_test + desc: ''' + Randomly assert interrupt lines during CSR modification operations, + core should jump to proper handler''' + stage: V1 + tests: ["riscv_interrupt_csr_test"] + } + { + name: riscv_interrupt_nested_test + desc: ''' + - randomly assert interrupt lines during program execution + - verify that jumps to interrupt handler + - trigger another interrupt during first intr_handler execution + - verify that core takes this nested interrupt and handles it, then restores previous interrupt + state and finishes executing first interrupt handler - ibex implements nonstandard MSTACK csrs to + save/restore state in case of nested interrupt''' + stage: V2 + tests: ["riscv_interrupt_nested_test"] + } + { + name: riscv_csr_test + desc: ''' + Perform all CSR instructions to implemented privileged CSR + Verify the reset value of the privileged CSR + Verify WARL field can be upated properly''' + stage: V1 + tests: ["riscv_csr_test"] + } + { + name: riscv_reset_test + desc: ''' + Reset the core a random number of times during program execution, core + should jump back to start address and re-enter the program. + Ensure to flush all testbench state to prevent contamination after reset.''' + stage: V1 + tests: ["riscv_reset_test"] + } + { + name: riscv_perf_counter_test + desc: ''' + Run random instruction test, and dump performance counters for checking''' + stage: V1 + tests: ["riscv_perf_counter_test"] + } + { + name: riscv_rv32im_instr_test + desc: ''' + Specify RV32IM architecture to compiler to generate target specific + instructions (no compressed instructions).''' + stage: V1 + tests: ["riscv_rv32im_instr_test"] + } + { + name: riscv_user_mode_rand_test + desc: ''' + Fully randomized RV32IMC instructions, boot in U-mode, + test should finish successfully + - includes all types of instructions + - no external debug/irq stimulus, exceptions, security aspects are checked here''' + stage: V2 + tests: ["riscv_user_mode_rand_test"] + } + { + name: riscv_umode_tw_test + desc: ''' + Set mstatus.tw, and enable random generation of WFI instructions. + Upon encountering WFI in U-mode, core should trap to M-mode + illegal instruction exception handler.''' + stage: V2 + tests: ["riscv_umode_tw_test"] + } + { + name: riscv_invalid_csr_test + desc: ''' + Boot core into a random privilege mode and generate accesses to higher level CSRs, + expect to throw an illegal instruction exception for each of these accesses.''' + stage: V2 + tests: ["riscv_invalid_csr_test"] + } + { + // TODO: Need to add testplan entries for PMP and nested trap tests + } + ] +}
diff --git a/fpga/ip/rv_core_ibex/doc/checklist.md b/fpga/ip/rv_core_ibex/doc/checklist.md new file mode 100644 index 0000000..dde199e --- /dev/null +++ b/fpga/ip/rv_core_ibex/doc/checklist.md
@@ -0,0 +1,148 @@ +# Ibex Processor Core Checklist + +This checklist is for [Hardware Stage][] transitions for the [Ibex Processor Core.](../README.md) +All checklist items refer to the content in the [Checklist.](../../../../../doc/project_governance/checklist/README.md) + +[Hardware Stage]: ../../../../../doc/project_governance/development_stages.md + + +## Design Checklist + +### D1 + +Type | Item | Resolution | Note/Collaterals +--------------|--------------------------------|-------------|------------------ +Documentation | [SPEC_COMPLETE][] | Done | +Documentation | [CSR_DEFINED][] | Done | lowRISC/ibex#307 +RTL | [CLKRST_CONNECTED][] | Done | +RTL | [IP_TOP][] | Done | +RTL | [IP_INSTANTIABLE][] | Done | +RTL | [PHYSICAL_MACROS_DEFINED_80][] | N/A | +RTL | [FUNC_IMPLEMENTED][] | Done | +RTL | [ASSERT_KNOWN_ADDED][] | Done | +Code Quality | [LINT_SETUP][] | Done | + + +[SPEC_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#spec_complete +[CSR_DEFINED]: ../../../../../doc/project_governance/checklist/README.md#csr_defined +[CLKRST_CONNECTED]: ../../../../../doc/project_governance/checklist/README.md#clkrst_connected +[IP_TOP]: ../../../../../doc/project_governance/checklist/README.md#ip_top +[IP_INSTANTIABLE]: ../../../../../doc/project_governance/checklist/README.md#ip_instantiable +[PHYSICAL_MACROS_DEFINED_80]: ../../../../../doc/project_governance/checklist/README.md#physical_macros_defined_80 +[FUNC_IMPLEMENTED]: ../../../../../doc/project_governance/checklist/README.md#func_implemented +[ASSERT_KNOWN_ADDED]: ../../../../../doc/project_governance/checklist/README.md#assert_known_added +[LINT_SETUP]: ../../../../../doc/project_governance/checklist/README.md#lint_setup + +### D1 Exceptions + +[PHYSICAL_MACROS_DEFINED_80][] is waived as Ibex doesn't have memories inside. + +### D2 + +Type | Item | Resolution | Note/Collaterals +--------------|---------------------------|-------------|------------------ +Documentation | [NEW_FEATURES][] | N/A | +Documentation | [BLOCK_DIAGRAM][] | Done | +Documentation | [DOC_INTERFACE][] | Done | +Documentation | [DOC_INTEGRATION_GUIDE][] | Waived | This checklist item has been added retrospectively. +Documentation | [MISSING_FUNC][] | N/A | +Documentation | [FEATURE_FROZEN][] | Done | +RTL | [FEATURE_COMPLETE][] | Done | +RTL | [PORT_FROZEN][] | Done | +RTL | [ARCHITECTURE_FROZEN][] | Done | +RTL | [REVIEW_TODO][] | Done | Minor TODOs remain, waived +RTL | [STYLE_X][] | Done | will be reworked (#366) +RTL | [CDC_SYNCMACRO][] | Done | +Code Quality | [LINT_PASS][] | Done | Lint waivers created, not finalized +Code Quality | [CDC_SETUP][] | Waived | No block-level flow available - waived to top-level signoff. +Code Quality | [RDC_SETUP][] | Waived | No block-level flow available - waived to top-level signoff. +Code Quality | [AREA_CHECK][] | Done | Area smoke check done (on FPGA) +Code Quality | [TIMING_CHECK][] | Done | FPGA timing acceptable +Security | [SEC_CM_DOCUMENTED][] | Done | + +[NEW_FEATURES]: ../../../../../doc/project_governance/checklist/README.md#new_features +[BLOCK_DIAGRAM]: ../../../../../doc/project_governance/checklist/README.md#block_diagram +[DOC_INTERFACE]: ../../../../../doc/project_governance/checklist/README.md#doc_interface +[DOC_INTEGRATION_GUIDE]: ../../../../../doc/project_governance/checklist/README.md#doc_integration_guide +[MISSING_FUNC]: ../../../../../doc/project_governance/checklist/README.md#missing_func +[FEATURE_FROZEN]: ../../../../../doc/project_governance/checklist/README.md#feature_frozen +[FEATURE_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#feature_complete +[PORT_FROZEN]: ../../../../../doc/project_governance/checklist/README.md#port_frozen +[ARCHITECTURE_FROZEN]: ../../../../../doc/project_governance/checklist/README.md#architecture_frozen +[REVIEW_TODO]: ../../../../../doc/project_governance/checklist/README.md#review_todo +[STYLE_X]: ../../../../../doc/project_governance/checklist/README.md#style_x +[CDC_SYNCMACRO]: ../../../../../doc/project_governance/checklist/README.md#cdc_syncmacro +[LINT_PASS]: ../../../../../doc/project_governance/checklist/README.md#lint_pass +[CDC_SETUP]: ../../../../../doc/project_governance/checklist/README.md#cdc_setup +[RDC_SETUP]: ../../../../../doc/project_governance/checklist/README.md#rdc_setup +[AREA_CHECK]: ../../../../../doc/project_governance/checklist/README.md#area_check +[TIMING_CHECK]: ../../../../../doc/project_governance/checklist/README.md#timing_check +[SEC_CM_DOCUMENTED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_documented + +### D2S + + Type | Item | Resolution | Note/Collaterals +--------------|------------------------------|-------------|------------------ +Security | [SEC_CM_ASSETS_LISTED][] | Done | +Security | [SEC_CM_IMPLEMENTED][] | Done | +Security | [SEC_CM_RND_CNST][] | Done | +Security | [SEC_CM_NON_RESET_FLOPS][] | Done | +Security | [SEC_CM_SHADOW_REGS][] | Done | +Security | [SEC_CM_RTL_REVIEWED][] | Done | +Security | [SEC_CM_COUNCIL_REVIEWED][] | Done | + +[SEC_CM_ASSETS_LISTED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_assets_listed +[SEC_CM_IMPLEMENTED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_implemented +[SEC_CM_RND_CNST]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_rnd_cnst +[SEC_CM_NON_RESET_FLOPS]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_non_reset_flops +[SEC_CM_SHADOW_REGS]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_shadow_regs +[SEC_CM_RTL_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_rtl_reviewed +[SEC_CM_COUNCIL_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_council_reviewed + +### D3 + + Type | Item | Resolution | Note/Collaterals +--------------|-------------------------|-------------|------------------ +Documentation | [NEW_FEATURES_D3][] | Not Started | +RTL | [TODO_COMPLETE][] | Not Started | +Code Quality | [LINT_COMPLETE][] | Not Started | +Code Quality | [CDC_COMPLETE][] | Not Started | +Code Quality | [RDC_COMPLETE][] | Not Started | +Review | [REVIEW_RTL][] | Not Started | +Review | [REVIEW_DELETED_FF][] | Not Started | +Review | [REVIEW_SW_CHANGE][] | Not Started | +Review | [REVIEW_SW_ERRATA][] | Not Started | + +[NEW_FEATURES_D3]: ../../../../../doc/project_governance/checklist/README.md#new_features_d3 +[TODO_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#todo_complete +[LINT_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#lint_complete +[CDC_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#cdc_complete +[RDC_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#rdc_complete +[REVIEW_RTL]: ../../../../../doc/project_governance/checklist/README.md#review_rtl +[REVIEW_DELETED_FF]: ../../../../../doc/project_governance/checklist/README.md#review_deleted_ff +[REVIEW_SW_CHANGE]: ../../../../../doc/project_governance/checklist/README.md#review_sw_change +[REVIEW_SW_ERRATA]: ../../../../../doc/project_governance/checklist/README.md#review_sw_errata + +## Verification Checklist + +Ibex verification is tracked in the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/03_reference/verification_stages.html). +Ibex is at **V2S**. + +Features specific to rv_core_ibex do not have block-level verification. +Top-level testing suffices for these, see the [rv_core_ibex DV document](../dv/README.md) for more details. + +### V1 + +The V1 checklist may be found in the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/03_reference/verification_stages.html#v1-checklist). + +### V2 + +The V2 checklist may be found in the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/03_reference/verification_stages.html#v2-checklist). + +### V2S + +The V2S checklist may be found in the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/03_reference/verification_stages.html#v2s-checklist). + +### V3 + +The V3 checklist may be found in the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/03_reference/verification_stages.html#v3-checklist).
diff --git a/fpga/ip/rv_core_ibex/doc/interfaces.md b/fpga/ip/rv_core_ibex/doc/interfaces.md new file mode 100644 index 0000000..65a3e80 --- /dev/null +++ b/fpga/ip/rv_core_ibex/doc/interfaces.md
@@ -0,0 +1,47 @@ +# Hardware Interfaces + +All ports and parameters of Ibex are exposed through this wrapper module, except for the instruction and data memory interfaces (signals starting with `instr_` and `data_`). +Refer to the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/02_user/integration.html) for a detailed description of these signals and parameters. + +The instruction and data memory ports are exposed as TL-UL ports. +The table below lists other signals and the TL-UL ports. + +Signal | Direction | Type | Description +---------------------|------------------|----------------------------------------|--------------- +`rst_cpu_n_o` | `output` | `logic` | Outgoing indication to reset manager that the process has reset. +`ram_cfg_i` | `input` | `prim_ram_1p_pkg::ram_1p_cfg_t` | Incoming memory configuration that is technology dependent. +`hart_id_i` | `input` | `logic [31:0]` | Static Hard ID input signal. +`boot_addr_i` | `input` | `logic [31:0]` | Static boot address input signal. +`fpga_info_i` | `input` | `logic [31:0]` | Fpga info input signal, coming from a Xilinx USR_ACCESSE2 primitive for example. +`irq_software_i` | `input` | `logic` | Software interrupt input. +`irq_timer_i` | `input` | `logic` | Timer interrupt input. +`irq_external_i` | `input` | `logic` | External interrupt input. +`debug_req_i` | `input` | `logic` | Debug request from the debug module. +`corei_tl_h_o` | `output` | `tlul_pkg::tl_h2d_t` | Outgoing instruction tlul request. +`corei_tl_h_i` | `input` | `tlul_pkg::tl_d2h_t` | Incoming instruction tlul response. +`cored_tl_h_o` | `output` | `tlul_pkg::tl_h2d_t` | Outgoing data tlul request. +`cored_tl_h_i` | `input` | `tlul_pkg::tl_d2h_t` | Incoming data tlul response. +`cfg_tl_d_i` | `output` | `tlul_pkg::tl_h2d_t` | Outgoing data tlul request for peripheral registers. +`cfg_tl_d_o` | `input` | `tlul_pkg::tl_d2h_t` | Incoming data tlul response for peripheral registers. +`alert_rx_i` | `input` | `prim_alert_pkg::alert_rx_t` | Incoming alert response / ping. +`alert_tx_o` | `output` | `prim_alert_pkg::alert_tx_t` | Outgoing alert request. +`esc_tx_i` | `input` | `prim_esc_pkg::esc_tx_t` | Incoming escalation request / ping. +`esc_rx_o` | `output` | `prim_esc_pkg::esc_rx_t` | Outgoing escalation response. +`nmi_wdog_i` | `input` | `logic` | Incoming watchdog NMI bark. +`crash_dump_o` | `output` | `ibex_pkg::crash_dump_t` | Outgoing crash dump information to rstmgr. +`cfg_tl_d_i` | `input` | `tlul_pkg::tl_h2d_t` | Incoming configuration bus request. +`cfg_tl_d_o ` | `output` | `tlul_pkg::tl_d2h_t` | Outgoing configuration bus response. +`lc_cpu_en_i` | `input` | `lc_ctrl_pkg::lc_tx_t` | CPU enable signal from life cycle controller. +`pwrmgr_cpu_en_i` | `input` | `lc_ctrl_pkg::lc_tx_t` | CPU enable signal from power manager. +`pwrmgr_o` | `output` | `pwrmgr_pkg::cpu_pwrmgr_t` | Low-power CPU status to power manager. +`edn_i` | `input` | `edn_pkg::edn_rsp_t` | Incoming entropy response from entropy distribution network. +`edn_o` | `output` | `edn_pkg::edn_req_t` | Outgoing entropy request to entropy distribution network. +`icache_otp_key_i` | `input` | `otp_ctrl_pkg::sram_otp_key_rsp_t` | Incoming scrambling key response from OTP to icache. +`icache_otp_key_o` | `output` | `otp_ctrl_pkg::sram_otp_key_req_t` | Outgoing scrambling key request from icache to OTP. + + +The `PipeLine` parameter can be used to configure the bus adapter pipelining. + +* Setting `PipeLine` to `0` disables pipelining, which gives minimal latency between the bus and the core, at the cost of a combinatorial path into the core. +* Setting `PipeLine` to `1` introduces a pipelining FIFO between the core instruction/data interfaces and the bus. + This setting increases the memory access latency, but improves timing.
diff --git a/fpga/ip/rv_core_ibex/doc/programmers_guide.md b/fpga/ip/rv_core_ibex/doc/programmers_guide.md new file mode 100644 index 0000000..6872202 --- /dev/null +++ b/fpga/ip/rv_core_ibex/doc/programmers_guide.md
@@ -0,0 +1,5 @@ +# Programmer's Guide + +## Device Interface Functions (DIFs) + +- [Device Interface Functions](../../../../../sw/device/lib/dif/dif_rv_core_ibex.h)
diff --git a/fpga/ip/rv_core_ibex/doc/theory_of_operation.md b/fpga/ip/rv_core_ibex/doc/theory_of_operation.md new file mode 100644 index 0000000..3df205f --- /dev/null +++ b/fpga/ip/rv_core_ibex/doc/theory_of_operation.md
@@ -0,0 +1,105 @@ +# Theory of Operation + +## Simple Address Translation + +The wrapper supports a simple address translation scheme. +The goal of the scheme is to provide hardware support for A/B software copies. + +Each copy of the software is stored at a different location. +Depending upon which execution slot is active, a different copy is used. +This creates an issue because each copy of software has different addresses and thus must be linked differently. +Ideally, software should be able to assume one address all the time, and the hardware should remap to the appropriate physical location. + +The translation scheme is based on NAPOT (natural alignment to power of two). +Software picks a matching region and also a remap address. +When an incoming transaction matches the selected power-of-2 region, it is redirected to the new address. +If a transaction does not match, then it is directly passed through. + +This allows software to place the executable code at a virtual address in the system and re-map that to the appropriate physical block. + +There are separate translations controls for instruction and data. +Each control contains two programmable regions (2 for instruction and 2 for data). +If a transaction matches multiple regions, the lowest indexed region has priority. + +For details on how to program the related registers, please see [`IBUS_ADDR_MATCHING_0`](registers.md#ibus_addr_matching) and [`IBUS_REMAP_ADDR_0`](registers.md#ibus_remap_addr). + +### Translation and Instruction Caching + +The simple address translation scheme used in this design is not aware of the processor context, specifically, any instruction caching done in the core. +This means if the address translation scheme were to change, instructions that are already cached may not reflect the updated address setting. + +In order to correctly utilize simple address translation along with instruction caching, it is recommended that after the address is updated a `FENCE.I` instruction is issued. +The `FENCE.I` instruction forces the instruction cache to flush, and this aligns the core to the new address setting. + +## Random Number Generation + +The wrapper has a connection to the [Entropy Distribution Network (EDN)](../../../../ip/edn/README.md) with a register based interface. +The [`RND_DATA`](registers.md#rnd_data) register provides 32-bits directly from the EDN. +[`RND_STATUS.RND_DATA_VALID`](registers.md#rnd_status) indicates if the data in [`RND_DATA`](registers.md#rnd_data) is valid or not. +A polling style interface is used to get new random data. +Any read to [`RND_DATA`](registers.md#rnd_data) when it is valid invalidates the data and triggers an EDN request for new data. +Software should poll [`RND_STATUS.RND_DATA_VALID`](registers.md#rnd_status) until it is valid and then read from [`RND_DATA`](registers.md#rnd_data) to get the new random data. +Either the data is valid or a request for new data is pending. +It is not possible to have a state where there is no valid data without new data being requested. + +Upon reset [`RND_DATA`](registers.md#rnd_data) is invalid. +A request is made to the EDN immediately out of reset, this will not be answered until the EDN is enabled. +Software should take care not to enable the EDN until the entropy complex configuration is as desired. +When the entropy complex configuration is changed reading [`RND_DATA`](registers.md#rnd_data) when it is valid will suffice to flush any old random data to trigger a new request under the new configuration. +If a EDN request is pending when the entropy complex configuration is changed ([`RND_STATUS.RND_DATA_VALID`](registers.md#rnd_status) is clear), it is advisable to wait until it is complete and then flush out the data to ensure the fresh value was produced under the new configuration. + +## Crash Dump Collection + +In general, when the CPU encounters an error, it is software's responsibility to collect error status and supply it for debug. + +However, there are situations where it may not be possible for software to collect any error logging. +These situations include but are not limited to: +* A hung transaction that causes watchdog to expire. +* A double fault that causes the processor to stop execution. +* An alert escalation that directly resets the system without any software intervention. + +Under these situations, the software has no hints as to where the error occurred. +To mitigate this issue, Ibex provides crash dump information that can be directly captured in the `rstmgr` for last resort debug after the reset event. + +The Ibex crash dump state contains 5 words of debug data: +* word 0: The last exception address (`mtval`) +* word 1: The last exception PC (`mepc`) +* word 2: The last data access address +* word 3: The next PC +* word 4: The current PC + +The crash dump information transmitted to the `rstmgr` contains 7 words of debug data and a 1-bit valid indication: +* words 0-4: The current crash dump state +* word 5: The previous exception address (`mtval`) +* word 6: The previous exception PC (`mepc`) +* MSB: Previous state valid indication. + +Under normal circumstances, only the current crash dump state is valid. +When the CPU encounters a double fault, the current crash dump is moved to previous, and the new crash dump is shown in current. + +This allows the software to see both fault locations and debug accordingly. + +In terms of how the crash state information can be used, the following are a few examples. + +### Hung Transaction + +Assuming the system has a watchdog counter setup, when a CPU transaction hangs the bus (accessing a device whose clock is not turned on or is under reset), the PC and bus access freeze in place until the watchdog resets the system. +Upon reset release, software can check the last PC and data access address to get an idea of what transaction might have caused the bus to hang. + +### Double Exception + +If the software has some kind of error and encounters two exceptions in a row, the previous exception PC and address show the location of the first exception, while the current exception address and PC show the location of the most recent exception. + + +## Fetch Enable + +Ibex has a top-level fetch enable input (``fetch_enable_i``), which uses the same multi-bit encoding used by the lifecycle controller. +When Ibex fetch is disabled it will cease to execute, but will complete instructions currently in the pipeline. +Ibex fetch is enabled when all of the following conditions are met: + - The lifecycle controller has enabled it + - The power manager has enabled it + - A ``fatal_hw_err`` alert hasn't been raised + +### Local Escalation Path + +When the ``fatal_hw_err`` alert is raised Ibex fetch is disabled and will remain disabled until ``rv_core_ibex`` is reset.
diff --git a/fpga/ip/rv_core_ibex/dv/README.md b/fpga/ip/rv_core_ibex/dv/README.md new file mode 100644 index 0000000..9a5c037 --- /dev/null +++ b/fpga/ip/rv_core_ibex/dv/README.md
@@ -0,0 +1,41 @@ +# Ibex RISC-V Core Wrapper DV document + +## Goals + * Verify compliance with the RISC-V specifications used by OpenTitan. + * Verify Ibex's security hardening features. + * Ensure correct functionality is maintained across all possible behaviours of Ibex's external interfaces when integrated into OpenTitan. + * Verify additional features provided by the wrapper. + +## Design features + +`rv_core_ibex` wraps a dual core lockstep configuration of [Ibex](https://www.github.com/lowrisc/ibex), an RV32IMC CPU with security hardening features. +The wrapper adapts Ibex's top-level interfaces to be suitable for use with OpenTitan. +In addition rv_core_ibex provides some extra functionality controlled via bus accessible registers. + +For more information please see the [Ibex RISC-V Core Wrapper Technical Specification](../README.md). + +## Current Status + +* Ibex Verification is tracked in the [Ibex documentation](https://ibex-core.readthedocs.io/en/latest/03_reference/verification_stages.html) + * Verification follows the OpenTitan [HW development stages](../../../../../doc/project_governance/development_stages.md) +* [Nightly regression results](https://dev.azure.com/lowrisc/lowrisc-private/_build?definitionId=11) + * These are from the Ibex private-ci which is restricted to OpenTitan project members + +## Verification strategy + +The main Ibex testbench is not contained in the OpenTitan repository. +Verification is primarily done by the testbench in the Ibex repository, see the [Ibex Testplan](https://ibex-core.readthedocs.io/en/latest/03_reference/testplan.html) for more details. + +The additional features provided by the RISC-V Core Wrapper are verified at a chip level only (See the [Earlgrey Chip DV testplan](../../../../top_earlgrey/dv/README.md) for example). +As they are simple features chip level only verification suffices to meet our goals. + +Similarly there is no specific verification for the TL-UL <-> Ibex memory protocol wrappers (provided by the separate [TLUL IP](../../../../ip/tlul/README.md)). +These are exercised extensively by all chip-level testing that runs software on Ibex providing comprehensive verification. + +## Coverage + +Due to the simplicity of the additional `rv_core_ibex` features, the existence of self checking chip-level tests combined with code and expression coverage is sufficient to be confident of their verification without functional coverpoints. + +The TL-UL <-> Ibex memory protocol contains minimal logic so again code and expression coverage will suffice with one exception. +The iside and dside Ibex interfaces can have up to 8 or 2 outstanding requests respectively, we need to ensure these scenarios are seen. +An SVA cover expression will be used to produce coverage for this.
diff --git a/fpga/ip/rv_core_ibex/dv/sva/rv_core_ibex_bind.sv b/fpga/ip/rv_core_ibex/dv/sva/rv_core_ibex_bind.sv new file mode 100644 index 0000000..b2a842e --- /dev/null +++ b/fpga/ip/rv_core_ibex/dv/sva/rv_core_ibex_bind.sv
@@ -0,0 +1,25 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module rv_core_ibex_bind; + + bind rv_core_ibex tlul_assert #( + .EndpointType("Host") + ) tlul_assert_host_instr ( + .clk_i, + .rst_ni, + .h2d (tl_i_o), + .d2h (tl_i_i) + ); + + bind rv_core_ibex tlul_assert #( + .EndpointType("Host") + ) tlul_assert_host_data ( + .clk_i, + .rst_ni, + .h2d (tl_d_o), + .d2h (tl_d_i) + ); + +endmodule
diff --git a/fpga/ip/rv_core_ibex/dv/sva/rv_core_ibex_sva.core b/fpga/ip/rv_core_ibex/dv/sva/rv_core_ibex_sva.core new file mode 100644 index 0000000..28232cb --- /dev/null +++ b/fpga/ip/rv_core_ibex/dv/sva/rv_core_ibex_sva.core
@@ -0,0 +1,40 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: lowrisc:kelvin_dv:rv_core_ibex_sva:0.1 +description: "RV_CORE_IBEX assertion modules and bind file." +filesets: + files_dv: + depend: + - lowrisc:fpv:csr_assert_gen + - lowrisc:kelvin_ip:rv_core_ibex:0.1 + - lowrisc:tlul:headers + - lowrisc:prim:assert + files: + - rv_core_ibex_bind.sv + file_type: systemVerilogSource + + files_formal: + depend: + - lowrisc:kelvin_ip:rv_core_ibex:0.1 + +generate: + csr_assert_gen: + generator: csr_assert_gen + parameters: + spec: ../../data/rv_core_ibex.hjson + +targets: + default: &default_target + filesets: + - files_dv + generate: + - csr_assert_gen + + formal: + <<: *default_target + filesets: + - files_formal + - files_dv + toplevel: rv_core_ibex
diff --git a/fpga/ip/rv_core_ibex/lint/rv_core_ibex.vbl b/fpga/ip/rv_core_ibex/lint/rv_core_ibex.vbl new file mode 100644 index 0000000..81e6a68 --- /dev/null +++ b/fpga/ip/rv_core_ibex/lint/rv_core_ibex.vbl
@@ -0,0 +1,9 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for rv_core_ibex + +# Waive Ibex formal DV environment +waive --rule=interface-name-style --location="mem.sv" +waive --rule=module-port --location="spec_instance.sv"
diff --git a/fpga/ip/rv_core_ibex/lint/rv_core_ibex.vlt b/fpga/ip/rv_core_ibex/lint/rv_core_ibex.vlt new file mode 100644 index 0000000..939bb3f --- /dev/null +++ b/fpga/ip/rv_core_ibex/lint/rv_core_ibex.vlt
@@ -0,0 +1,79 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Lint waivers for Verilator +// See https://verilator.org/guide/latest/exe_verilator.html#configuration-files +// for documentation. +// +// Important: This file must included *before* any other Verilog file is read. +// Otherwise, only global waivers are applied, but not file-specific waivers. + +`verilator_config +lint_off -rule PINCONNECTEMPTY + +// We have some boolean top-level parameters in e.g. ibex_core_tracing.sv. +// When building with fusesoc, these get set with defines like +// -GRV32M=1 (rather than -GRV32M=1'b1), leading to warnings like: +// +// Operator VAR '<varname>' expects 1 bits on the Initial value, but +// Initial value's CONST '32'h1' generates 32 bits. +// +// This signoff rule ignores errors like this. Note that it only +// matches when you set a 1-bit value to a literal 1, so it won't hide +// silly mistakes like setting it to 2. +// +lint_off -rule WIDTH -file "*/rtl/ibex_top_tracing.sv" + -match "*expects 1 bits*Initial value's CONST '32'h1'*" + +// Operator expects 1 bit on initial value but initial value's CONST generates +// 32 bits, need a specific RV32B waiver as it uses enums so the above catch-all +// waiver doesn't work. +lint_off -rule WIDTH -file "*/rtl/ibex_top_tracing.sv" -match "*'RV32B'*" + +// Bits of signal are not used: be_i[3:1] +// Bits of signal are not used: addr_i[31:10,1:0] +// Bits of signal are not used: wdata_i[31:8] +// +// simulator_ctrl exposes a 32-bit write-only interface to its control +// registers, but actually only looks at the bottom byte and rounds addresses +// down to be 4-byte aligned. +// +lint_off -rule UNUSED -file "*/rtl/sim/simulator_ctrl.sv" -match "*'be_i'[3:1]*" +lint_off -rule UNUSED -file "*/rtl/sim/simulator_ctrl.sv" -match "*'addr_i'[31:10,1:0]*" +lint_off -rule UNUSED -file "*/rtl/sim/simulator_ctrl.sv" -match "*'wdata_i'[31:8]*" + +// Bits of signal are not used: timer_addr_i[31:10] +// +// The upper bits of this address are used to select whether the timer is +// addressed at all (encoded in the timer_req_i input). However, we pass the +// entire 32-bit address around to make the code a bit cleaner. +lint_off -rule UNUSED -file "*/rtl/timer.sv" -match "*'timer_addr_i'[31:10]*" + +// Signal is not used: clk_i +// leaving clk and reset connected in-case we want to add assertions +lint_off -rule UNUSED -file "*/rtl/ibex_pmp.sv" -match "*clk_i*" +lint_off -rule UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -match "*clk_i*" +lint_off -rule UNUSED -file "*/rtl/ibex_decoder.sv" -match "*clk_i*" +lint_off -rule UNUSED -file "*/rtl/ibex_branch_predict.sv" -match "*clk_i*" + +// Signal is not used: rst_ni +// leaving clk and reset connected in-case we want to add assertions +lint_off -rule UNUSED -file "*/rtl/ibex_pmp.sv" -match "*rst_ni*" +lint_off -rule UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -match "*rst_ni*" +lint_off -rule UNUSED -file "*/rtl/ibex_decoder.sv" -match "*rst_ni*" +lint_off -rule UNUSED -file "*/rtl/ibex_branch_predict.sv" -match "*rst_ni*" + +// Don't worry about the fact that decoded_str and data_accessed appear to be +// written by multiple processes that might race with each other. They can't +// race with each other (everything is a descendent of the always_comb block), +// but Verilator doesn't notice this. +lint_off -rule MULTIDRIVEN -file "*/rtl/ibex_tracer.sv" -match "*decoded_str*" +lint_off -rule MULTIDRIVEN -file "*/rtl/ibex_tracer.sv" -match "*data_accessed*" + +// Temporary waivers until OpenTitan primitives are lint-clean +// https://github.com/lowRISC/opentitan/issues/2313 +lint_off -file "*/lowrisc_prim_*/rtl/*.sv" + +lint_off -rule UNUSED -file "*/rtl/ibex_top_tracing.sv" -match "*RndCnstLfsrSeed*" +lint_off -rule UNUSED -file "*/rtl/ibex_top_tracing.sv" -match "*RndCnstLfsrPerm*"
diff --git a/fpga/ip/rv_core_ibex/lint/rv_core_ibex.waiver b/fpga/ip/rv_core_ibex/lint/rv_core_ibex.waiver new file mode 100644 index 0000000..1b51105 --- /dev/null +++ b/fpga/ip/rv_core_ibex/lint/rv_core_ibex.waiver
@@ -0,0 +1,148 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# waiver file for Ibex core + +waive -rules EXPLICIT_BITLEN -location {ibex_top.sv} -regexp {Bit length not specified for constant .*h2} \ + -comment "better way to write it?" +waive -rules HIER_BRANCH_NOT_READ -location {ibex_decoder.sv} -regexp {Net 'instr_rdata_i.*is not read from in module} \ + -comment "not all bits are used" +waive -rules INPUT_NOT_READ -location {ibex_decoder.sv} -regexp {Input port 'instr_rdata_i.*is not read from in module} \ + -comment "not all bits are used" +waive -rules HIER_BRANCH_NOT_READ -location {ibex_id_stage.sv} -regexp {[nN]et 'test_en_i' .* is not read from} \ + -comment "testability signal used in some versions of register file" +waive -rules INPUT_NOT_READ -location {ibex_register_file_ff.sv} -regexp {Input port 'test_en_i' is not read from} \ + -comment "testability signal used in some versions of register file" +waive -rules INPUT_NOT_READ -location {ibex_register_file_fpga.sv} -regexp {Input port 'test_en_i' is not read from} \ + -comment "testability signal used in some versions of register file" +waive -rules INPUT_NOT_READ -location {ibex_top.sv} -regexp {Input port 'clock_en_i' is not read from} \ + -comment "clock enable signal used in behavioral code" +waive -rules HIER_NET_NOT_READ -location {rv_core_ibex.sv} -regexp {Net 'instr_addr_o.1.0.' is not read from} \ + -comment "Bottom bits not needed, cleaner to keep them as inputs" +waive -rules NOT_READ -location {rv_core_ibex.sv} -regexp {Signal 'instr_addr_o.1.0.' is not read from} \ + -comment "Bottom bits not needed, cleaner to keep them as inputs" +waive -rules HIER_NET_NOT_READ -location {rv_core_ibex.sv} -regexp {Net 'data_addr_o.1.0.' is not read from} \ + -comment "Bottom bits not needed, cleaner to keep them as inputs" +waive -rules NOT_READ -location {rv_core_ibex.sv} -regexp {Signal 'data_addr_o.1.0.' is not read from} \ + -comment "Bottom bits not needed, cleaner to keep them as inputs" +waive -rules HIER_NET_NOT_READ -location {ibex_ex_block.sv} -regexp {Net 'alu_adder_result_ext.0.' .* is not read from} \ + -comment "Bottom bit is round, not needed" +waive -rules HIER_NET_NOT_READ -location {ibex_ex_block.sv} -regexp {Connected net 'alu_adder_ext_i.0.' .* is not read from} \ + -comment "Bottom bit is round, not needed" +waive -rules HIER_NET_NOT_READ -location {ibex_top.sv} -regexp {[nN]et 'boot_addr_i.7:0.' .* is not read from} \ + -comment "Boot address is 256B aligned, cleaner to pass all bits in" +waive -rules {INPUT_NOT_READ HIER_BRANCH_NOT_READ} -location {ibex_if_stage.sv} -regexp {'boot_addr_i.7:0.' is not read from} \ + -comment "Boot address is 256B aligned, cleaner to pass all bits in" +waive -rules HIER_NET_NOT_READ -location {ibex_ex_block.sv} -regexp {[nN]et 'alu_adder.*0' is not read from} \ + -comment "LSB is not needed here, shifting off before using" +waive -rules INPUT_NOT_READ -location {ibex_multdiv_fast.sv} -regexp {Input port 'alu_adder_ext_i.0.' is not read from} \ + -comment "LSB is not needed here, shifting off before using" +waive -rules HIER_NET_NOT_READ -location {rv_core_ibex.sv} -regexp {Net 'tl_._fifo2ibex.d_(error|opcode|param|sink|size|source|user).*' is not read} \ + -comment "Not all bits of instruction response needed" +waive -rules NOT_READ -location {rv_core_ibex.sv} -regexp {Signal 'tl_._fifo2ibex.d_(error|opcode|param|sink|size|source|user).*' is not read} \ + -comment "Not all bits of instruction response needed" +waive -rules NOT_READ -location {ibex_if_stage.sv} -regexp {Signal 'fetch_addr_n.0.' is not read from} \ + -comment "cleaner to write all bits even if not all are used" +waive -rules NOT_READ -location {ibex_multdiv_fast.sv} -regexp {Signal 'mac_res_ext.34.' is not read from} \ + -comment "cleaner to write all bits even if not all are used" +waive -rules NOT_READ -location {ibex_multdiv_fast.sv} -regexp {Signal 'res_adder_h.32.' is not read from} \ + -comment "cleaner to write all bits even if not all are used" +waive -rules MULTIPLY -location {ibex_multdiv_fast.sv} -regexp {Multiply operation.*encountered} \ + -comment "got to pay the price for the multiplier" +waive -rules CONST_OUTPUT -location {rv_core_ibex.sv} -regexp {Output 'tl_(i|d)_o..*' is driven by constant} \ + -comment "not all bus constructs are used" +waive -rules SIGNED_RANGE -location {ibex_controller.sv} -msg {Part select of signed signal 'i[3:0]' encountered} \ + -comment "switching the loop variable i to unsigned would require loop restructuring to not change interrupt priorities, making the code less readable" +waive -rules SIGNED_RANGE -location {ibex_cs_registers.sv} -regexp {Part select of signed signal 'i\[11:0\]' encountered} \ + -comment "'i' is the loop variable of a genvar loop running from 0 to 'PMPNumRegions' which is an unsigned integer number. There is no issue with the part select." +waive -rules SIGNED_RANGE -location {ibex_cs_registers.sv} -regexp {Part select of signed signal 'i\[DbgHwNumLen \- 1:0\]' encountered} \ + -comment "'i' is the loop variable of a genvar loop running from 0 to 'DbgHwBreakNum' which is an unsigned integer number. There is no issue with the part select." +waive -rules SIGNED_RANGE -location {ibex_icache.sv} -regexp {Part select of signed signal 'b\[IC_LINE_BEATS_W \- 1:0\]' encountered} \ + -comment "'b' is the loop variable of a genvar loop running from 0 to 'IC_LINE_BEATS' which is an unsigned integer number. There is no issue with the part select." +waive -rules CONST_OUTPUT -location {ibex_controller.sv} -regexp {Output 'exc_cause_o.5.' is driven by constant} \ + -comment "easier to write with enum, not all causes used yet" +waive -rules CONST_OUTPUT -location {ibex_decoder.sv} -regexp {Output 'data_reg_offset_o' is driven by constant} \ + -comment "fixed register offset" +waive -rules CONST_OUTPUT -location {ibex_decoder.sv} -regexp {Output 'alu_op_._mux_sel_o.*' is driven by constant} \ + -comment "not all possible mux select values are used in enum" +waive -rules CONST_OUTPUT -location {ibex_multdiv_fast.sv} -regexp {Output 'alu_operand_._o.0.' is driven by constant} \ + -comment "bottom bit set to 1 for rounding" +waive -rules VAR_INDEX -location {ibex_multdiv_fast.sv} -regexp {Variable index expression 'op_numerator_q.div_counter_n.' encountered} \ + -comment "TODO: discuss: I don't think this is a problem" +waive -rules VAR_INDEX -location {ibex_register_file_ff.sv} -regexp {Variable index expression 'rf_reg.raddr_._i.' encountered} \ + -comment "TODO: discuss: I don't think this is a problem" +waive -rules NOT_READ -location {ibex_cs_registers.sv} -regexp {Signal 'pccr_index' is not read from} \ + -comment "Used in non synthesis scenario" +waive -rules NOT_READ -location {ibex_cs_registers.sv} -regexp {Signal 'pccr_all_sel' is not read from} \ + -comment "Used in non synthesis scenario" +waive -rules NOT_USED -location {ibex_cs_registers.sv} -regexp {Signal 'PCCR_inc.*11.1.' is not used} \ + -comment "Used in non synthesis scenario" +waive -rules NOT_READ -location {ibex_alu.sv} -regexp {Signal 'shift_right_result_ext.32.' is not read from} \ + -comment "As mentioned in the RTL, MSB of shift_right_result_ext can be safely ignored" +waive -rules NOT_READ -location {ibex_id_stage.sv} -regexp {Signal 'operand_b_fw_id' is not read from in module 'ibex_id_stage'} \ + -comment "This signal is actually used (not via a port but through hierarchical path) in ibex_top.sv" +waive -rules INTEGER -location {ibex_register_file_ff.sv rv_core_ibex.sv} -msg {'i' of type int used as a non-constant value} \ + -comment "This assigns int i (signed) to a multibit logic variable (unsigned), which is fine" +waive -rules ONE_BIT_MEM_WIDTH -location {ibex_core.sv} -regexp {Memory 'pmp_req_err' has word width which is single bit wide} \ + -comment "For consistency with related signals, we use an unpacked array for this signal." +waive -rules HIER_BRANCH_NOT_READ -location {ibex_branch_predict.sv ibex_decoder.sv ibex_compressed_decoder.sv} -regexp {Net '(clk_i|rst_ni)' is not read from in module '(ibex_branch_predict|ibex_decoder|ibex_compressed_decoder)'.*} \ + -comment "These signals are only used for assertions inside these three modules" +waive -rules INPUT_NOT_READ -location {ibex_branch_predict.sv ibex_decoder.sv ibex_compressed_decoder.sv} -regexp {Input port '(clk_i|rst_ni)' is not read from in module '(ibex_branch_predict|ibex_decoder|ibex_compressed_decoder)'.*} \ + -comment "These signals are only used for assertions inside these two modules" +waive -rules IFDEF_CODE -location {ibex_core.sv} -regexp {Assignment to 'unused_instr_new_id' contained within `else block} \ + -comment "Declaration of signal and assignment to it are in same `else block" +waive -rules IFDEF_CODE -location {ibex_core.sv} -regexp {Assignment to 'unused_instr_id_done' contained within `else block} \ + -comment "Declaration of signal and assignment to it are in same `else block" +waive -rules IFDEF_CODE -location {ibex_core.sv} -regexp {Assignment to 'unused_instr_done_wb' contained within `else block} \ + -comment "Declaration of signal and assignment to it are in same `else block" +waive -rules IFDEF_CODE -location {rv_core_ibex.sv} -regexp {Assignment to 'tl_win_d2h' contained within `else block} \ + -comment "DV environment will drive things when `else block isn't used so assignment only occurs in `else block" +waive -rules IFDEF_CODE -location {ibex_multdiv_fast.sv} -regexp {Assignment to 'unused_sva_mul_fsm_idle' contained within `else block at ibex_multdiv_fast.sv} \ + -comment "Declaration of signal and assignment to it are in same `else block" +waive -rules CLOCK_USE -location {ibex_id_stage.sv} -regexp {'clk_i' is connected to 'ibex_decoder' port 'clk_i'} \ + -comment "clk_i is unused in ibex_decoder configurations without RV32B and isn't connected to logic" +waive -rules RESET_USE -location {ibex_id_stage.sv} -regexp {'rst_ni' is connected to 'ibex_decoder' port 'rst_ni'} \ + -comment "rst_ni is unused in ibex_decoder configurations without RV32B and isn't connected to logic" +waive -rules {ZERO_REP} -location {ibex_icache.sv} -regexp {Replication count is zero in '{22 - IC_TAG_SIZE{1'b0}}'} \ + -comment "if IC_TAG_SIZE=22, no padding is needed" +waive -rules {ZERO_REP} -location {ibex_icache.sv} -regexp {Replication count is zero in '{IC_LINE_BEATS_W - 1{1'b0}}'} \ + -comment "if IC_LINE_BEATS=2, IC_LINE_BEATS_W=1 and no padding is needed" +waive -rules {ARITH_CONTEXT} -location {ibex_icache.sv} -msg {Bitlength of arithmetic operation '(output_addr_q[IC_LINE_W - 1:BUS_W] + {{IC_LINE_BEATS_W - 1{1'b0}},skid_valid_q})' is self-determined in this context} \ + -comment "The bitlengths are determined but the zero replication count (IC_LINE_BEATS_W=1) seems to confuse the tool" +waive -rules MIXED_SIGN -location {ibex_lockstep.sv} -regexp {Unsigned operand 'rst_shadow_cnt_q' and signed 'LockstepOffsetW'(1)' encountered in a binary expression} \ + -comment "In line with our style guide, LockstepOffsetW'(1) results in a signed operand" +waive -rules UNSIZED_BIT_CONTEXT -location {ibex_lockstep.sv} -regexp {Bitlength of unsized bit literal "'0" is self determined in this context} \ + -comment {In line with our style guide, writing this as {$bits(delayed_inputs_t){1'b0}} would be much less readable} +waive -rules CONST_FF -location {ibex_icache.sv} -regexp {Flip-flop 'reset_inval_q' is driven by constant one} \ + -comment "The only purpose of the flop is to initiate the cache invalidation after reset" +waive -rules RESET_DRIVER -location {ibex_lockstep.sv} -regexp {'(rst_shadow_set_q|rst_shadow_n)' is driven here, and used as an asynchronous reset 'rst_ni' at} + -comment "A synchronous counter is needed to release the shadow core reset with a delay of LockstepOffset clock cycles" +waive -rules RESET_DRIVER -location {ibex_lockstep.sv} -regexp {'(rst_shadow_set_q|rst_shadow_n)' driven in module 'ibex_lockstep'} + -comment "A synchronous counter is needed to release the shadow core reset with a delay of LockstepOffset clock cycles" +waive -rules RESET_DRIVER -location {ibex_lockstep.sv} -regexp {'rst_shadow_set_q\[0\]' is driven by instance 'u_prim_rst_shadow_set_flop' of module 'prim_flop', and used as an asynchronous reset 'rst_ni' at} + -comment "A synchronous counter is needed to release the shadow core reset with a delay of LockstepOffset clock cycles" +waive -rules RESET_DRIVER -location {ibex_lockstep.sv} -regexp {'q_o\[0\]' is driven in module '(prim_flop|prim_generic_flop)'} + -comment "A synchronous counter is needed to release the shadow core reset with a delay of LockstepOffset clock cycles" +waive -rules RESET_MUX -location {ibex_lockstep.sv} -regexp {Asynchronous reset 'rst_shadow_n' is driven by a multiplexer here} + -comment "The test enable input used to control the bypass can be considered static" +waive -rules RESET_USE -location {ibex_lockstep.sv} -regexp {'rst_shadow_set_q' is used for some other purpose, and as asynchronous reset 'rst_ni' at} + -comment "A synchronous counter is needed to release the shadow core reset with a delay of LockstepOffset clock cycles and start the comparison logic one clock cycle later" +waive -rules RESET_USE -location {ibex_lockstep.sv} -regexp {'enable_cmp_d\[0\]' is connected to 'prim_flop' port 'd_i\[0\]', and used as an asynchronous reset or set 'rst_ni' at} + -comment "enable_cmp_d[0] is assigned to rst_shadow_set_q[0] which is drive by a synchronous counter which is needed to release the shadow core reset with a delay of LockstepOffset clock cycles" +waive -rules {CLOCK_USE RESET_USE} -location {ibex_register_file_ff.sv} \ + -regexp {'(clk_i|rst_ni)' is connected to '(prim_onehot_mux)' port} \ + -comment {The module is fully combinatorial, clk/rst are only used for assertions.} + +# Highlighting my main concerns here, documenting areas to review in next dive +# +# data_err_i is not used in load/store unit beyond assertions; this signal is +# true when bus requests return in error. What is the right way to handle? +# +# lsu_load_err/lsu_store_err: similar above, except that the condition is +# tied to false in ibex_load_store_unit and is unused in ID stage. Dead +# code that should be removed? Or is this an indication of missing error +# handling logic? +# +# output signal out_valid_stored_o from ibex_fetch_fifo is not used. Dead +# code or indicating a bigger problem?
diff --git a/fpga/ip/rv_core_ibex/rtl/rv_core_ibex.sv b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex.sv new file mode 100644 index 0000000..0db48d4 --- /dev/null +++ b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex.sv
@@ -0,0 +1,1045 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Ibex RISC-V core + * + * 32 bit RISC-V core supporting the RV32I + optionally EMC instruction sets. + * Instruction and data bus are 32 bit wide TileLink-UL (TL-UL). + */ +module rv_core_ibex + import rv_core_ibex_pkg::*; + import rv_core_ibex_reg_pkg::*; +#( + parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}}, + // Number of cycles a differential skew is tolerated on the alert and escalation signal + parameter int unsigned AlertSkewCycles = 1, + parameter bit PMPEnable = 1'b1, + parameter int unsigned PMPGranularity = 0, + parameter int unsigned PMPNumRegions = 16, + parameter int unsigned MHPMCounterNum = 10, + parameter int unsigned MHPMCounterWidth = 32, + parameter ibex_pkg::pmp_cfg_t PMPRstCfg[16] = ibex_pkg::PmpCfgRst, + parameter logic [33:0] PMPRstAddr[16] = ibex_pkg::PmpAddrRst, + parameter ibex_pkg::pmp_mseccfg_t PMPRstMsecCfg = ibex_pkg::PmpMseccfgRst, + parameter bit RV32E = 0, + parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MSingleCycle, + parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BOTEarlGrey, + parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF, + parameter bit BranchTargetALU = 1'b1, + parameter bit WritebackStage = 1'b1, + parameter bit ICache = 1'b1, + parameter bit ICacheECC = 1'b1, + parameter bit ICacheScramble = 1'b1, + parameter int unsigned ICacheNWays = 2, + parameter bit BranchPredictor = 1'b0, + parameter bit DbgTriggerEn = 1'b1, + parameter int unsigned DbgHwBreakNum = 4, + parameter bit SecureIbex = 1'b1, + parameter ibex_pkg::lfsr_seed_t RndCnstLfsrSeed = ibex_pkg::RndCnstLfsrSeedDefault, + parameter ibex_pkg::lfsr_perm_t RndCnstLfsrPerm = ibex_pkg::RndCnstLfsrPermDefault, + parameter int unsigned DmBaseAddr = 32'h1A110000, + parameter int unsigned DmAddrMask = 32'h00000FFF, + parameter int unsigned DmHaltAddr = 32'h1A110800, + parameter int unsigned DmExceptionAddr = 32'h1A110808, + parameter bit PipeLine = 1'b0, + parameter logic [ibex_pkg::SCRAMBLE_KEY_W-1:0] RndCnstIbexKeyDefault = + ibex_pkg::RndCnstIbexKeyDefault, + parameter logic [ibex_pkg::SCRAMBLE_NONCE_W-1:0] RndCnstIbexNonceDefault = + ibex_pkg::RndCnstIbexNonceDefault, + parameter int unsigned NEscalationSeverities = 4, + parameter int unsigned WidthPingCounter = 16, + parameter logic [tlul_pkg::RsvdWidth-1:0] TlulHostUserRsvdBits = 0, + parameter logic [31:0] CsrMvendorId = 32'b0, + parameter logic [31:0] CsrMimpId = 32'b0 +) ( + // Clock and Reset + input logic clk_i, + input logic rst_ni, + // Clock domain for edn + input logic clk_edn_i, + input logic rst_edn_ni, + // Clock domain for escalation receiver + input logic clk_esc_i, + input logic rst_esc_ni, + // Reset feedback to rstmgr + output logic rst_cpu_n_o, + + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_tag_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ICacheNWays-1:0] ram_cfg_rsp_icache_tag_o, + input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_icache_data_i, + output prim_ram_1p_pkg::ram_1p_cfg_rsp_t [ICacheNWays-1:0] ram_cfg_rsp_icache_data_o, + + input logic [31:0] hart_id_i, + input logic [31:0] boot_addr_i, + + // Instruction memory interface + output tlul_pkg::tl_h2d_t corei_tl_h_o, + input tlul_pkg::tl_d2h_t corei_tl_h_i, + + // Data memory interface + output tlul_pkg::tl_h2d_t cored_tl_h_o, + input tlul_pkg::tl_d2h_t cored_tl_h_i, + + // Interrupt inputs + input logic irq_software_i, + input logic irq_timer_i, + input logic irq_external_i, + + // Escalation input for NMI + input prim_esc_pkg::esc_tx_t esc_tx_i, + output prim_esc_pkg::esc_rx_t esc_rx_o, + + // watchdog NMI input + input logic nmi_wdog_i, + + // Debug Interface + input logic debug_req_i, + + // Crash dump information + output cpu_crash_dump_t crash_dump_o, + + // CPU Control Signals + input lc_ctrl_pkg::lc_tx_t lc_cpu_en_i, + input lc_ctrl_pkg::lc_tx_t pwrmgr_cpu_en_i, + output cpu_pwrmgr_t pwrmgr_o, + + // dft bypass + input scan_rst_ni, + input prim_mubi_pkg::mubi4_t scanmode_i, + + // peripheral interface access + input tlul_pkg::tl_h2d_t cfg_tl_d_i, + output tlul_pkg::tl_d2h_t cfg_tl_d_o, + + // connection to edn + output edn_pkg::edn_req_t edn_o, + input edn_pkg::edn_rsp_t edn_i, + + // connection to otp scramble interface + input clk_otp_i, + input rst_otp_ni, + output otp_ctrl_pkg::sram_otp_key_req_t icache_otp_key_o, + input otp_ctrl_pkg::sram_otp_key_rsp_t icache_otp_key_i, + + // fpga build info + input [31:0] fpga_info_i, + + // interrupts and alerts + input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i, + output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o + +); + + import top_pkg::*; + import tlul_pkg::*; + + // Register module + rv_core_ibex_cfg_reg2hw_t reg2hw; + rv_core_ibex_cfg_hw2reg_t hw2reg; + + // if pipeline=1, do not allow pass through and always break the path + // if pipeline is 0, passthrough the fifo completely + localparam bit FifoPass = PipeLine ? 1'b0 : 1'b1; + localparam int unsigned FifoDepth = PipeLine ? 2 : 0; + // ICache creates more outstanding transactions + localparam int NumOutstandingReqs = ICache ? 8 : 2; + + // Instruction interface (internal) + logic instr_req; + logic instr_gnt; + logic instr_rvalid; + logic [31:0] instr_addr; + logic [31:0] instr_rdata; + logic [6:0] instr_rdata_intg; + logic instr_err; + + // Data interface (internal) + logic data_req; + logic data_gnt; + logic data_rvalid; + logic data_we; + logic [3:0] data_be; + logic [31:0] data_addr; + logic [31:0] data_wdata; + logic [6:0] data_wdata_intg; + logic [31:0] data_rdata; + logic [6:0] data_rdata_intg; + logic data_err; + + // Pipeline interfaces + tl_h2d_t tl_i_ibex2fifo; + tl_d2h_t tl_i_fifo2ibex; + tl_h2d_t tl_d_ibex2fifo; + tl_d2h_t tl_d_fifo2ibex; + +`ifdef RVFI + logic rvfi_valid; + logic [63:0] rvfi_order; + logic [31:0] rvfi_insn; + logic rvfi_trap; + logic rvfi_halt; + logic rvfi_intr; + logic [ 1:0] rvfi_mode; + logic [ 1:0] rvfi_ixl; + logic [ 4:0] rvfi_rs1_addr; + logic [ 4:0] rvfi_rs2_addr; + logic [ 4:0] rvfi_rs3_addr; + logic [31:0] rvfi_rs1_rdata; + logic [31:0] rvfi_rs2_rdata; + logic [31:0] rvfi_rs3_rdata; + logic [ 4:0] rvfi_rd_addr; + logic [31:0] rvfi_rd_wdata; + logic [31:0] rvfi_pc_rdata; + logic [31:0] rvfi_pc_wdata; + logic [31:0] rvfi_mem_addr; + logic [ 3:0] rvfi_mem_rmask; + logic [ 3:0] rvfi_mem_wmask; + logic [31:0] rvfi_mem_rdata; + logic [31:0] rvfi_mem_wdata; +`endif + + // core sleeping + logic core_sleep; + + // The following intermediate signals are created to aid in simulations. + // + // If a parent port is connected directly to a port of sub-modules, the implicit wire connection + // can have only one procedural driver (assign, force etc). What that means is, it prevents us + // from forcing the sub-module port without impacting the same port on other sub-modules. The + // reason for this is, regardless of which hierarchy the port signal is forced, it is a singular + // wire-connected entity - the effect of the force ends up getting reflected on the same port of + // sub-modules, as well as the parent port. To achieve the behavior of a force on a sub-module + // port not impacting (i.e. back-propagating to) the same port on parent / peer sub-modules, we + // need to add an extra `logic` type variables between the port-port connections. + logic ibex_top_clk_i; + logic addr_trans_rst_ni; + assign ibex_top_clk_i = clk_i; + assign addr_trans_rst_ni = rst_ni; + + // errors and core alert events + logic ibus_intg_err, dbus_intg_err; + logic alert_minor, alert_major_internal, alert_major_bus; + logic double_fault; + logic fatal_intg_err, fatal_core_err, recov_core_err; + + // alert events to peripheral module + logic fatal_intg_event; + logic fatal_core_event; + logic recov_core_event; + // SEC_CM: BUS.INTEGRITY + assign fatal_intg_event = ibus_intg_err | dbus_intg_err | alert_major_bus; + assign fatal_core_event = alert_major_internal | double_fault; + assign recov_core_event = alert_minor; + + // configurations for address translation + region_cfg_t [NumRegions-1:0] ibus_region_cfg; + region_cfg_t [NumRegions-1:0] dbus_region_cfg; + + // Reset feedback to clkmgr + assign rst_cpu_n_o = rst_ni; + + // Escalation receiver that converts differential + // protocol into single ended signal. + logic esc_irq_nm; + prim_esc_receiver #( + .N_ESC_SEV (NEscalationSeverities), + .PING_CNT_DW (WidthPingCounter), + .SkewCycles (AlertSkewCycles) + ) u_prim_esc_receiver ( + .clk_i ( clk_esc_i ), + .rst_ni ( rst_esc_ni ), + .esc_req_o ( esc_irq_nm ), + .esc_rx_o, + .esc_tx_i + ); + + // Synchronize to fast Ibex clock domain. + logic alert_irq_nm; + prim_flop_2sync #( + .Width(1) + ) u_alert_nmi_sync ( + .clk_i, + .rst_ni, + .d_i(esc_irq_nm), + .q_o(alert_irq_nm) + ); + + logic wdog_irq_nm; + prim_flop_2sync #( + .Width(1) + ) u_wdog_nmi_sync ( + .clk_i, + .rst_ni, + .d_i(nmi_wdog_i), + .q_o(wdog_irq_nm) + ); + + assign hw2reg.nmi_state.alert.d = 1'b1; + assign hw2reg.nmi_state.alert.de = alert_irq_nm; + assign hw2reg.nmi_state.wdog.d = 1'b1; + assign hw2reg.nmi_state.wdog.de = wdog_irq_nm; + + logic irq_nm; + assign irq_nm = |(reg2hw.nmi_state & reg2hw.nmi_enable); + + lc_ctrl_pkg::lc_tx_t [0:0] lc_cpu_en; + prim_lc_sync u_lc_sync ( + .clk_i, + .rst_ni, + .lc_en_i(lc_cpu_en_i), + .lc_en_o(lc_cpu_en) + ); + + lc_ctrl_pkg::lc_tx_t [0:0] pwrmgr_cpu_en; + prim_lc_sync u_pwrmgr_sync ( + .clk_i, + .rst_ni, + .lc_en_i(pwrmgr_cpu_en_i), + .lc_en_o(pwrmgr_cpu_en) + ); + + // timer interrupts do not come from + // rv_plic and may not be synchronous to the ibex core + logic irq_timer_sync; + prim_flop_2sync #( + .Width(1) + ) u_intr_timer_sync ( + .clk_i, + .rst_ni, + .d_i(irq_timer_i), + .q_o(irq_timer_sync) + ); + + + logic irq_software; + logic irq_timer; + logic irq_external; + + prim_sec_anchor_buf #( + .Width(3) + ) u_prim_buf_irq ( + .in_i({irq_software_i, + irq_timer_sync, + irq_external_i}), + .out_o({irq_software, + irq_timer, + irq_external}) + ); + + + logic key_req, key_ack; + logic [ibex_pkg::SCRAMBLE_KEY_W-1:0] key; + logic [ibex_pkg::SCRAMBLE_NONCE_W-1:0] nonce; + logic unused_seed_valid; + localparam int PayLoadW = ibex_pkg::SCRAMBLE_KEY_W + ibex_pkg::SCRAMBLE_NONCE_W + 1; + prim_sync_reqack_data #( + .Width(PayLoadW), + .DataSrc2Dst(1'b0) + ) u_prim_sync_reqack_data ( + .clk_src_i ( clk_i ), + .rst_src_ni ( rst_ni ), + .clk_dst_i ( clk_otp_i ), + .rst_dst_ni ( rst_otp_ni ), + .req_chk_i ( 1'b1 ), + .src_req_i ( key_req ), + .src_ack_o ( key_ack ), + .dst_req_o ( icache_otp_key_o.req ), + .dst_ack_i ( icache_otp_key_i.ack ), + .data_i ( {icache_otp_key_i.key, + icache_otp_key_i.nonce[ibex_pkg::SCRAMBLE_NONCE_W-1:0], + icache_otp_key_i.seed_valid} ), + .data_o ( {key, + nonce, + unused_seed_valid} ) + ); + + logic unused_nonce; + assign unused_nonce = |icache_otp_key_i.nonce; + + // Local fetch enable control. + // Whenever a fatal core error is seen disable local fetch enable. + lc_ctrl_pkg::lc_tx_t local_fetch_enable_d, local_fetch_enable_q; + + assign local_fetch_enable_d = fatal_core_err ? lc_ctrl_pkg::Off : local_fetch_enable_q; + + prim_lc_sender #( + .AsyncOn(1), // this instantiates a register + .ResetValueIsOn(1) + ) u_prim_lc_sender ( + .clk_i, + .rst_ni, + .lc_en_i(local_fetch_enable_d), + .lc_en_o(local_fetch_enable_q) + ); + + // Multibit AND computation for fetch enable. Fetch is only enabled when local fetch enable, + // lifecycle CPU enable and power manager CPU enable are all enabled. + lc_ctrl_pkg::lc_tx_t fetch_enable; + assign fetch_enable = lc_ctrl_pkg::lc_tx_and_hi(local_fetch_enable_q, + lc_ctrl_pkg::lc_tx_and_hi(lc_cpu_en[0], + pwrmgr_cpu_en[0])); + + ibex_pkg::crash_dump_t crash_dump; + ibex_top #( + .PMPEnable ( PMPEnable ), + .PMPGranularity ( PMPGranularity ), + .PMPNumRegions ( PMPNumRegions ), + .MHPMCounterNum ( MHPMCounterNum ), + .MHPMCounterWidth ( MHPMCounterWidth ), + .PMPRstCfg ( PMPRstCfg ), + .PMPRstAddr ( PMPRstAddr ), + .PMPRstMsecCfg ( PMPRstMsecCfg ), + .RV32E ( RV32E ), + .RV32M ( RV32M ), + .RV32B ( RV32B ), + .RegFile ( RegFile ), + .BranchTargetALU ( BranchTargetALU ), + .WritebackStage ( WritebackStage ), + .ICache ( ICache ), + // Our automatic SEC_CM label check doesn't look at vendored code so the SEC_CM labels need + // to be mentioned here. The real locations can be found by grepping the vendored code. + // TODO(#10071): this should be fixed. + // SEC_CM: ICACHE.MEM.INTEGRITY + .ICacheECC ( ICacheECC ), + // SEC_CM: ICACHE.MEM.SCRAMBLE, SCRAMBLE.KEY.SIDELOAD + .ICacheScramble ( ICacheScramble ), + // Reduce the number of PRINCE half rounds to 2 (5 effective rounds) to ease timing. This is + // acceptable for the instruction cache, whereas 3 half rounds (7 effective rounds) are used + // elsewhere in the design. + .ICacheScrNumPrinceRoundsHalf( 2 ), + .BranchPredictor ( BranchPredictor ), + .DbgTriggerEn ( DbgTriggerEn ), + .DbgHwBreakNum ( DbgHwBreakNum ), + // SEC_CM: LOGIC.SHADOW + // SEC_CM: PC.CTRL_FLOW.CONSISTENCY, CTRL_FLOW.UNPREDICTABLE, CORE.DATA_REG_SW.SCA + // SEC_CM: EXCEPTION.CTRL_FLOW.GLOBAL_ESC, EXCEPTION.CTRL_FLOW.LOCAL_ESC + // SEC_CM: DATA_REG_SW.INTEGRITY, DATA_REG_SW.GLITCH_DETECT + .SecureIbex ( SecureIbex ), + .RndCnstLfsrSeed ( RndCnstLfsrSeed ), + .RndCnstLfsrPerm ( RndCnstLfsrPerm ), + .RndCnstIbexKey ( RndCnstIbexKeyDefault ), + .RndCnstIbexNonce ( RndCnstIbexNonceDefault ), + .DmBaseAddr ( DmBaseAddr ), + .DmAddrMask ( DmAddrMask ), + .DmHaltAddr ( DmHaltAddr ), + .DmExceptionAddr ( DmExceptionAddr ), + .CsrMvendorId ( CsrMvendorId ), + .CsrMimpId ( CsrMimpId ) + ) u_core ( + .clk_i (ibex_top_clk_i), + .rst_ni, + + + .test_en_i (prim_mubi_pkg::mubi4_test_true_strict(scanmode_i)), + .scan_rst_ni, + + .ram_cfg_icache_tag_i, + .ram_cfg_rsp_icache_tag_o, + .ram_cfg_icache_data_i, + .ram_cfg_rsp_icache_data_o, + + .hart_id_i, + .boot_addr_i, + + .instr_req_o ( instr_req ), + .instr_gnt_i ( instr_gnt ), + .instr_rvalid_i ( instr_rvalid ), + .instr_addr_o ( instr_addr ), + .instr_rdata_i ( instr_rdata ), + .instr_rdata_intg_i ( instr_rdata_intg ), + .instr_err_i ( instr_err ), + + .data_req_o ( data_req ), + .data_gnt_i ( data_gnt ), + .data_rvalid_i ( data_rvalid ), + .data_we_o ( data_we ), + .data_be_o ( data_be ), + .data_addr_o ( data_addr ), + .data_wdata_o ( data_wdata ), + .data_wdata_intg_o ( data_wdata_intg ), + .data_rdata_i ( data_rdata ), + .data_rdata_intg_i ( data_rdata_intg ), + .data_err_i ( data_err ), + + .irq_software_i ( irq_software ), + .irq_timer_i ( irq_timer ), + .irq_external_i ( irq_external ), + .irq_fast_i ( '0 ), + .irq_nm_i ( irq_nm ), + + .debug_req_i, + .crash_dump_o ( crash_dump ), + + // icache scramble interface + .scramble_key_valid_i (key_ack), + .scramble_key_i (key), + .scramble_nonce_i (nonce), + .scramble_req_o (key_req), + + // double fault + .double_fault_seen_o (double_fault), + +`ifdef RVFI + .rvfi_valid, + .rvfi_order, + .rvfi_insn, + .rvfi_trap, + .rvfi_halt, + .rvfi_intr, + .rvfi_mode, + .rvfi_ixl, + .rvfi_rs1_addr, + .rvfi_rs2_addr, + .rvfi_rs3_addr, + .rvfi_rs1_rdata, + .rvfi_rs2_rdata, + .rvfi_rs3_rdata, + .rvfi_rd_addr, + .rvfi_rd_wdata, + .rvfi_pc_rdata, + .rvfi_pc_wdata, + .rvfi_mem_addr, + .rvfi_mem_rmask, + .rvfi_mem_wmask, + .rvfi_mem_rdata, + .rvfi_mem_wdata, + // Unused ports from the RVFI interface + .rvfi_ext_pre_mip (), + .rvfi_ext_post_mip (), + .rvfi_ext_nmi (), + .rvfi_ext_nmi_int (), + .rvfi_ext_debug_req (), + .rvfi_ext_debug_mode (), + .rvfi_ext_rf_wr_suppress (), + .rvfi_ext_mcycle (), + .rvfi_ext_mhpmcounters (), + .rvfi_ext_mhpmcountersh (), + .rvfi_ext_ic_scr_key_valid(), + .rvfi_ext_irq_valid (), +`endif + // SEC_CM: FETCH.CTRL.LC_GATED + .fetch_enable_i (fetch_enable), + .alert_minor_o (alert_minor), + .alert_major_internal_o (alert_major_internal), + .alert_major_bus_o (alert_major_bus), + .core_sleep_o (core_sleep) + ); + + logic core_sleep_q; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + core_sleep_q <= '0; + end else begin + core_sleep_q <= core_sleep; + end + end + + prim_buf #( + .Width(1) + ) u_core_sleeping_buf ( + .in_i(core_sleep_q), + .out_o(pwrmgr_o.core_sleeping) + ); + + + + logic prev_valid; + logic [31:0] prev_exception_pc; + logic [31:0] prev_exception_addr; + + assign crash_dump_o.current = crash_dump; + assign crash_dump_o.prev_valid = prev_valid; + assign crash_dump_o.prev_exception_pc = prev_exception_pc; + assign crash_dump_o.prev_exception_addr = prev_exception_addr; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + prev_valid <= '0; + prev_exception_pc <= '0; + prev_exception_addr <= '0; + end else if (double_fault) begin + prev_valid <= 1'b1; + prev_exception_pc <= crash_dump.exception_pc; + prev_exception_addr <= crash_dump.exception_addr; + end + end + + + // + // Convert ibex data/instruction bus to TL-UL + // + logic [31:0] instr_addr_trans; + rv_core_ibex_addr_trans #( + .AddrWidth(32), + .NumRegions(NumRegions) + ) u_ibus_trans ( + .clk_i, + .rst_ni(addr_trans_rst_ni), + .region_cfg_i(ibus_region_cfg), + .addr_i(instr_addr), + .addr_o(instr_addr_trans) + ); + + logic [6:0] instr_wdata_intg; + logic [top_pkg::TL_DW-1:0] unused_data; + // tl_adapter_host_i_ibex only reads instruction. a_data is always 0 + assign {instr_wdata_intg, unused_data} = prim_secded_pkg::prim_secded_inv_39_32_enc('0); + // SEC_CM: BUS.INTEGRITY + tlul_adapter_host #( + .MAX_REQS(NumOutstandingReqs), + // if secure ibex is not set, data integrity is not generated + // from ibex, therefore generate it in the gasket instead. + .EnableDataIntgGen(~SecureIbex) + ) tl_adapter_host_i_ibex ( + .clk_i, + .rst_ni, + .req_i (instr_req), + .instr_type_i (prim_mubi_pkg::MuBi4True), + .gnt_o (instr_gnt), + .addr_i (instr_addr_trans), + .we_i (1'b0), + .wdata_i (32'b0), + .wdata_intg_i (instr_wdata_intg), + .be_i (4'hF), + .user_rsvd_i (TlulHostUserRsvdBits), + .valid_o (instr_rvalid), + .rdata_o (instr_rdata), + .rdata_intg_o (instr_rdata_intg), + .err_o (instr_err), + .intg_err_o (ibus_intg_err), + .tl_o (tl_i_ibex2fifo), + .tl_i (tl_i_fifo2ibex) + ); + + tlul_fifo_sync #( + .ReqPass(FifoPass), + .RspPass(FifoPass), + .ReqDepth(FifoDepth), + .RspDepth(FifoDepth) + ) fifo_i ( + .clk_i, + .rst_ni, + .tl_h_i (tl_i_ibex2fifo), + .tl_h_o (tl_i_fifo2ibex), + .tl_d_o (corei_tl_h_o), + .tl_d_i (corei_tl_h_i), + .spare_req_i (1'b0), + .spare_req_o (), + .spare_rsp_i (1'b0), + .spare_rsp_o ()); + + logic [31:0] data_addr_trans; + rv_core_ibex_addr_trans #( + .AddrWidth(32), + .NumRegions(NumRegions) + ) u_dbus_trans ( + .clk_i, + .rst_ni(addr_trans_rst_ni), + .region_cfg_i(dbus_region_cfg), + .addr_i(data_addr), + .addr_o(data_addr_trans) + ); + + // SEC_CM: BUS.INTEGRITY + tlul_adapter_host #( + .MAX_REQS(2), + .EnableDataIntgGen(~SecureIbex) + ) tl_adapter_host_d_ibex ( + .clk_i, + .rst_ni, + .req_i (data_req), + .instr_type_i (prim_mubi_pkg::MuBi4False), + .gnt_o (data_gnt), + .addr_i (data_addr_trans), + .we_i (data_we), + .wdata_i (data_wdata), + .wdata_intg_i (data_wdata_intg), + .be_i (data_be), + .user_rsvd_i (TlulHostUserRsvdBits), + .valid_o (data_rvalid), + .rdata_o (data_rdata), + .rdata_intg_o (data_rdata_intg), + .err_o (data_err), + .intg_err_o (dbus_intg_err), + .tl_o (tl_d_ibex2fifo), + .tl_i (tl_d_fifo2ibex) + ); + + tlul_fifo_sync #( + .ReqPass(FifoPass), + .RspPass(FifoPass), + .ReqDepth(FifoDepth), + .RspDepth(FifoDepth) + ) fifo_d ( + .clk_i, + .rst_ni, + .tl_h_i (tl_d_ibex2fifo), + .tl_h_o (tl_d_fifo2ibex), + .tl_d_o (cored_tl_h_o), + .tl_d_i (cored_tl_h_i), + .spare_req_i (1'b0), + .spare_req_o (), + .spare_rsp_i (1'b0), + .spare_rsp_o ()); + +`ifdef RVFI + ibex_tracer ibex_tracer_i ( + .clk_i, + .rst_ni, + + .hart_id_i, + + .rvfi_valid, + .rvfi_order, + .rvfi_insn, + .rvfi_trap, + .rvfi_halt, + .rvfi_intr, + .rvfi_mode, + .rvfi_ixl, + .rvfi_rs1_addr, + .rvfi_rs2_addr, + .rvfi_rs3_addr, + .rvfi_rs1_rdata, + .rvfi_rs2_rdata, + .rvfi_rs3_rdata, + .rvfi_rd_addr, + .rvfi_rd_wdata, + .rvfi_pc_rdata, + .rvfi_pc_wdata, + .rvfi_mem_addr, + .rvfi_mem_rmask, + .rvfi_mem_wmask, + .rvfi_mem_rdata, + .rvfi_mem_wdata + ); +`endif + + ////////////////////////////////// + // Peripheral functions + ////////////////////////////////// + + logic intg_err; + tlul_pkg::tl_h2d_t tl_win_h2d; + tlul_pkg::tl_d2h_t tl_win_d2h; + rv_core_ibex_cfg_reg_top u_reg_cfg ( + .clk_i, + .rst_ni, + .tl_i(cfg_tl_d_i), + .tl_o(cfg_tl_d_o), + .reg2hw, + .hw2reg, + .intg_err_o (intg_err), + .tl_win_o(tl_win_h2d), + .tl_win_i(tl_win_d2h) + ); + + /////////////////////// + // Region assignments + /////////////////////// + + for(genvar i = 0; i < NumRegions; i++) begin : gen_ibus_region_cfgs + assign ibus_region_cfg[i].en = reg2hw.ibus_addr_en[i]; + assign ibus_region_cfg[i].matching_region = reg2hw.ibus_addr_matching[i]; + assign ibus_region_cfg[i].remap_addr = reg2hw.ibus_remap_addr[i]; + end + + for(genvar i = 0; i < NumRegions; i++) begin : gen_dbus_region_cfgs + assign dbus_region_cfg[i].en = reg2hw.dbus_addr_en[i]; + assign dbus_region_cfg[i].matching_region = reg2hw.dbus_addr_matching[i]; + assign dbus_region_cfg[i].remap_addr = reg2hw.dbus_remap_addr[i]; + end + + /////////////////////// + // Error assignment + /////////////////////// + + assign fatal_intg_err = fatal_intg_event; + assign fatal_core_err = fatal_core_event; + assign recov_core_err = recov_core_event; + + assign hw2reg.err_status.reg_intg_err.d = 1'b1; + assign hw2reg.err_status.reg_intg_err.de = intg_err; + assign hw2reg.err_status.fatal_intg_err.d = 1'b1; + assign hw2reg.err_status.fatal_intg_err.de = fatal_intg_err; + assign hw2reg.err_status.fatal_core_err.d = 1'b1; + assign hw2reg.err_status.fatal_core_err.de = fatal_core_err; + assign hw2reg.err_status.recov_core_err.d = 1'b1; + assign hw2reg.err_status.recov_core_err.de = recov_core_err; + + /////////////////////// + // Alert generation + /////////////////////// + + logic [NumAlerts-1:0] alert_test; + assign alert_test[0] = reg2hw.alert_test.fatal_sw_err.q & + reg2hw.alert_test.fatal_sw_err.qe; + assign alert_test[1] = reg2hw.alert_test.recov_sw_err.q & + reg2hw.alert_test.recov_sw_err.qe; + assign alert_test[2] = reg2hw.alert_test.fatal_hw_err.q & + reg2hw.alert_test.fatal_hw_err.qe; + assign alert_test[3] = reg2hw.alert_test.recov_hw_err.q & + reg2hw.alert_test.recov_hw_err.qe; + + localparam bit [NumAlerts-1:0] AlertFatal = '{1'b0, 1'b1, 1'b0, 1'b1}; + + logic [NumAlerts-1:0] alert_events; + logic [NumAlerts-1:0] alert_acks; + + import prim_mubi_pkg::mubi4_test_true_loose; + import prim_mubi_pkg::mubi4_t; + assign alert_events[0] = mubi4_test_true_loose(mubi4_t'(reg2hw.sw_fatal_err.q)); + assign alert_events[1] = mubi4_test_true_loose(mubi4_t'(reg2hw.sw_recov_err.q)); + assign alert_events[2] = intg_err | fatal_intg_err | fatal_core_err; + assign alert_events[3] = recov_core_err; + + logic unused_alert_acks; + assign unused_alert_acks = |alert_acks; + + // recoverable alerts are sent once and silenced until activated again. + assign hw2reg.sw_recov_err.de = alert_acks[1]; + assign hw2reg.sw_recov_err.d = prim_mubi_pkg::MuBi4False; + + for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_senders + prim_alert_sender #( + .AsyncOn(AlertAsyncOn[0]), + .SkewCycles(AlertSkewCycles), + .IsFatal(AlertFatal[i]) + ) u_alert_sender ( + .clk_i, + .rst_ni, + .alert_test_i(alert_test[i]), + .alert_req_i(alert_events[i]), + .alert_ack_o(alert_acks[i]), + .alert_state_o(), + .alert_rx_i(alert_rx_i[i]), + .alert_tx_o(alert_tx_o[i]) + ); + end + + ////////////// + // RND Data // + ////////////// + + logic [31:0] rnd_data_q, rnd_data_d; + logic rnd_valid_q, rnd_valid_d; + logic rnd_fips_q, rnd_fips_d; + logic edn_req; + logic [31:0] edn_data; + logic edn_ack; + logic edn_fips; + + always_comb begin + rnd_valid_d = rnd_valid_q; + rnd_data_d = rnd_data_q; + rnd_fips_d = rnd_fips_q; + + if (reg2hw.rnd_data.re) begin + rnd_valid_d = '0; + rnd_data_d = '0; + rnd_fips_d = '0; + end else if (edn_req && edn_ack) begin + rnd_valid_d = 1'b1; + rnd_data_d = edn_data; + rnd_fips_d = edn_fips; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rnd_valid_q <= '0; + rnd_data_q <= '0; + rnd_fips_q <= '0; + end else begin + rnd_valid_q <= rnd_valid_d; + rnd_data_q <= rnd_data_d; + rnd_fips_q <= rnd_fips_d; + end + end + + assign edn_req = ~rnd_valid_q; + + prim_edn_req #( + .OutWidth(32) + ) u_edn_if ( + .clk_i, + .rst_ni, + .req_chk_i(1'b1), + .req_i(edn_req), + .ack_o(edn_ack), + .data_o(edn_data), + .fips_o(edn_fips), + .err_o(), + .clk_edn_i, + .rst_edn_ni, + .edn_o, + .edn_i + ); + + assign hw2reg.rnd_data.d = rnd_data_q; + assign hw2reg.rnd_status.rnd_data_valid.d = rnd_valid_q; + assign hw2reg.rnd_status.rnd_data_fips.d = rnd_fips_q; + + logic unused_reg2hw; + assign unused_reg2hw = |reg2hw.rnd_data.q; + + + // fpga build info hook-up + assign hw2reg.fpga_info.d = fpga_info_i; + + ///////////////////////////////////// + // The carved out space is for DV emulation purposes only + ///////////////////////////////////// + + import tlul_pkg::tl_h2d_t; + import tlul_pkg::tl_d2h_t; + localparam int TlH2DWidth = $bits(tl_h2d_t); + localparam int TlD2HWidth = $bits(tl_d2h_t); + + logic [TlH2DWidth-1:0] tl_win_h2d_int; + logic [TlD2HWidth-1:0] tl_win_d2h_int; + tl_d2h_t tl_win_d2h_err_rsp; + + prim_buf #( + .Width(TlH2DWidth) + ) u_tlul_req_buf ( + .in_i(tl_win_h2d), + .out_o(tl_win_h2d_int) + ); + + prim_buf #( + .Width(TlD2HWidth) + ) u_tlul_rsp_buf ( + .in_i(tl_win_d2h_err_rsp), + .out_o(tl_win_d2h_int) + ); + + // Interception point for connecting simulation SRAM by disconnecting the tl_d output. The + // disconnection is done only if `SYNTHESIS is NOT defined AND `RV_CORE_IBEX_SIM_SRAM is + // defined. + // This define is used only for verilator as verilator does not support forces. +`ifdef RV_CORE_IBEX_SIM_SRAM +`ifdef SYNTHESIS + // Induce a compilation error by instantiating a non-existent module. + illegal_preprocessor_branch_taken u_illegal_preprocessor_branch_taken(); +`endif +`else + assign tl_win_d2h = tl_d2h_t'(tl_win_d2h_int); +`endif + + tlul_err_resp u_sim_win_rsp ( + .clk_i, + .rst_ni, + .tl_h_i(tl_h2d_t'(tl_win_h2d_int)), + .tl_h_o(tl_win_d2h_err_rsp) + ); + + `ASSERT_INIT(ICacheNWaysCorrect_A, ICacheNWays == ibex_pkg::IC_NUM_WAYS) + + // Assertions for CPU enable + // Allow 2 or 3 cycles for input to enable due to synchronizers + `ASSERT(FpvSecCmIbexFetchEnable0_A, + fatal_core_err + |=> + lc_ctrl_pkg::lc_tx_test_false_loose(fetch_enable)) + `ASSERT(FpvSecCmIbexFetchEnable1_A, + lc_ctrl_pkg::lc_tx_test_false_loose(lc_cpu_en_i) + |-> + ##[2:3] lc_ctrl_pkg::lc_tx_test_false_loose(fetch_enable)) + `ASSERT(FpvSecCmIbexFetchEnable2_A, + lc_ctrl_pkg::lc_tx_test_false_loose(pwrmgr_cpu_en_i) + |-> + ##[2:3] lc_ctrl_pkg::lc_tx_test_false_loose(fetch_enable)) + `ASSERT(FpvSecCmIbexFetchEnable3_A, + lc_ctrl_pkg::lc_tx_test_true_strict(lc_cpu_en_i) && + lc_ctrl_pkg::lc_tx_test_true_strict(pwrmgr_cpu_en_i) ##1 + lc_ctrl_pkg::lc_tx_test_true_strict(local_fetch_enable_q) && + !fatal_core_err + |=> + ##[0:1] lc_ctrl_pkg::lc_tx_test_true_strict(fetch_enable)) + `ASSERT(FpvSecCmIbexFetchEnable3Rev_A, + ##2 lc_ctrl_pkg::lc_tx_test_true_strict(fetch_enable) + |-> + ($past(lc_ctrl_pkg::lc_tx_test_true_strict(lc_cpu_en_i), 2) || + $past(lc_ctrl_pkg::lc_tx_test_true_strict(lc_cpu_en_i), 3)) && + ($past(lc_ctrl_pkg::lc_tx_test_true_strict(pwrmgr_cpu_en_i), 2) || + $past(lc_ctrl_pkg::lc_tx_test_true_strict(pwrmgr_cpu_en_i), 3)) && + $past(!fatal_core_err)) + + // Alert assertions for reg_we onehot check + `ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(RegWeOnehotCheck_A, u_reg_cfg, alert_tx_o[2]) + `ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT(RvCoreRegWeOnehotCheck_A, + u_core.gen_regfile_ff.register_file_i.gen_wren_check.u_prim_onehot_check, alert_tx_o[2]) + `ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT(RvCoreRegWeOnehotCheckRAddrA_A, + u_core.gen_regfile_ff.register_file_i.gen_rdata_mux_check.u_prim_onehot_check_raddr_a, + alert_tx_o[2]) + `ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT(RvCoreRegWeOnehotCheckRAddrB_A, + u_core.gen_regfile_ff.register_file_i.gen_rdata_mux_check.u_prim_onehot_check_raddr_b, + alert_tx_o[2]) + +`ifdef INC_ASSERT + if (ICache && ICacheScramble) begin : gen_icache_scramble_asserts + + // Sample icache scramble key for use in assertions below. + // pragma coverage off + //VCS coverage off + logic [ibex_pkg::SCRAMBLE_KEY_W-1:0] icache_otp_key_q; + always_ff @(posedge clk_i, negedge rst_ni) begin + if (!rst_ni) begin + icache_otp_key_q <= '0; + end else if (icache_otp_key_i.ack) begin + icache_otp_key_q <= icache_otp_key_i.key; + end + end + //VCS coverage on + // pragma coverage on + + // Ensure that when a scramble key is received, it is correctly forwarded to the core. The core + // will then internally ensure that the key is correctly applied to the icache scrambled + // memory primitives. + `ASSERT(IbexIcacheScrambleKeyForwardedToCore_A, + icache_otp_key_i.ack + |-> ##[0:10] // upper bound is not exact, but it should not take more than 10 cycles + u_core.scramble_key_valid_i && (u_core.scramble_key_i == icache_otp_key_q) + ) + + // Ensure that when a FENCE.I is executed, a new icache scramble key is requested. + `ASSERT(IbexIcacheScrambleKeyRequestAfterFenceI_A, + u_core.u_ibex_core.id_stage_i.instr_valid_i + && u_core.u_ibex_core.id_stage_i.decoder_i.opcode == ibex_pkg::OPCODE_MISC_MEM + && u_core.u_ibex_core.id_stage_i.decoder_i.instr[14:12] == 3'b001 // FENCE.I + |-> ##[0:14] // upper bound is not exact, but it should not take more than a few cycles + icache_otp_key_o.req + ) + + end + + `define ASSERT_IBEX_CORE_ERROR_TRIGGER_ALERT(__assert_name, __alert_name, _hier, __error_name) \ + if (1) begin : g_``__error_name``_assert_signals \ + logic __error_name; \ + assign __error_name = u_core._hier``.__error_name; \ + \ + logic unused_assert_connected; \ + `ASSERT_INIT_NET(AssertConnected_A, unused_assert_connected === 1'b1) \ + end \ + `ASSERT_ERROR_TRIGGER_ALERT(__assert_name, g_``__error_name``_assert_signals, __alert_name, 0, \ + 30, // MAX_CYCLES_, use a large value as ibex clock is 4x faster than clk in alert_handler \ + __error_name) + + `ASSERT_IBEX_CORE_ERROR_TRIGGER_ALERT(IbexPcMismatchCheck_A, alert_tx_o[2], + u_ibex_core.if_stage_i, pc_mismatch_alert_o) + `ASSERT_IBEX_CORE_ERROR_TRIGGER_ALERT(IbexRfEccErrCheck_A, alert_tx_o[2], u_ibex_core, + rf_ecc_err_comb) + `ASSERT_IBEX_CORE_ERROR_TRIGGER_ALERT(IbexLoadRespIntgErrCheck_A, alert_tx_o[2], u_ibex_core, + lsu_load_resp_intg_err) + `ASSERT_IBEX_CORE_ERROR_TRIGGER_ALERT(IbexStoreRespIntgErrCheck_A, alert_tx_o[2], u_ibex_core, + lsu_store_resp_intg_err) + `ASSERT_IBEX_CORE_ERROR_TRIGGER_ALERT(IbexInstrIntgErrCheck_A, alert_tx_o[2], u_ibex_core, + instr_intg_err) + `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(IbexLockstepResetCountAlertCheck_A, + u_core.gen_lockstep.u_ibex_lockstep.u_rst_shadow_cnt, alert_tx_o[2]) + +`endif // ifdef INC_ASSERT +endmodule
diff --git a/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_addr_trans.sv b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_addr_trans.sv new file mode 100644 index 0000000..ab9ce68 --- /dev/null +++ b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_addr_trans.sv
@@ -0,0 +1,86 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Simple address translation for rv_core_ibex + * This performs a configurable address translation, please see + * https://docs.google.com/document/d/1uU2Zh46SJtoaOqZ9dCRO7oAQnhTUcWWZ7CstOa1PZiM/edit?usp=sharing + */ + +module rv_core_ibex_addr_trans import rv_core_ibex_pkg::*; #( + parameter int AddrWidth = 32, + parameter int NumRegions = 2 +) ( + input logic clk_i, + input logic rst_ni, + input region_cfg_t [NumRegions-1:0] region_cfg_i, + input logic [AddrWidth-1:0] addr_i, + output logic [AddrWidth-1:0] addr_o +); + + typedef struct packed { + logic [AddrWidth-1:0] output_mask; + logic [AddrWidth-1:0] remap_addr; + } region_ctrls_t; + + region_ctrls_t region_ctrls [NumRegions] ; + logic [NumRegions-1:0][AddrWidth-1:0] input_masks; + + // Mask generation is based on the matching region configuration + // Since matching is done on a power-of-2 alignment, the mechanism is similar + // to RISC-V pmp's power-of-2 usage. + // As an example: + // If a matching region is programmed as 0x8007_FFFF, + // The matching input mask is 0xFFF0_0000 + // The output mask is simply inverted 0x000F_FFFF + for (genvar i = 0; i < NumRegions; i++) begin : gen_region_ctrls + assign input_masks[i][0] = 1'b0; + + for (genvar j = 1; j < AddrWidth; j++) begin : gen_addr_masks_lower_bits + assign input_masks[i][j] = ~®ion_cfg_i[i].matching_region[j-1:0]; + end + + // pack things into region controls + assign region_ctrls[i].output_mask = ~input_masks[i]; + assign region_ctrls[i].remap_addr = region_cfg_i[i].remap_addr; + end + + logic [NumRegions-1:0] all_matches; + for (genvar i = 0; i < NumRegions; i++) begin : gen_region_matches + assign all_matches[i] = region_cfg_i[i].en & + ((region_cfg_i[i].matching_region & input_masks[i]) == + (addr_i & input_masks[i])); + end + + logic sel_match; + region_ctrls_t sel_region; + prim_arbiter_fixed #( + .N(NumRegions), + .DW($bits(region_ctrls_t)), + .EnDataPort(1) + ) u_sel_region ( + .clk_i, + .rst_ni, + .req_i(all_matches), + .data_i(region_ctrls), + .gnt_o(), + .idx_o(), + .valid_o(sel_match), + .data_o(sel_region), + .ready_i(1'b1) + ); + + // if there is a match, mask off the address bits and remap + // if there is no match, just use incoming address + assign addr_o = sel_match ? + (addr_i & sel_region.output_mask) | (sel_region.remap_addr & ~sel_region.output_mask) : + addr_i; + + // unused clock/reset, only needed for assertions + logic unused_clk; + logic unused_rst_n; + assign unused_clk = clk_i; + assign unused_rst_n = rst_ni; + +endmodule // rv_core_ibex_addr_trans
diff --git a/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_cfg_reg_top.sv b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_cfg_reg_top.sv new file mode 100644 index 0000000..f6421ab --- /dev/null +++ b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_cfg_reg_top.sv
@@ -0,0 +1,1496 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + +`include "prim_assert.sv" + +module rv_core_ibex_cfg_reg_top ( + input clk_i, + input rst_ni, + input tlul_pkg::tl_h2d_t tl_i, + output tlul_pkg::tl_d2h_t tl_o, + + // Output port for window + output tlul_pkg::tl_h2d_t tl_win_o, + input tlul_pkg::tl_d2h_t tl_win_i, + + // To HW + output rv_core_ibex_reg_pkg::rv_core_ibex_cfg_reg2hw_t reg2hw, // Write + input rv_core_ibex_reg_pkg::rv_core_ibex_cfg_hw2reg_t hw2reg, // Read + + // Integrity check errors + output logic intg_err_o +); + + import rv_core_ibex_reg_pkg::* ; + + localparam int AW = 8; + localparam int DW = 32; + localparam int DBW = DW/8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [AW-1:0] reg_addr; + logic [DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + logic reg_busy; + + tlul_pkg::tl_h2d_t tl_reg_h2d; + tlul_pkg::tl_d2h_t tl_reg_d2h; + + + // incoming payload check + logic intg_err; + tlul_cmd_intg_chk u_chk ( + .tl_i(tl_i), + .err_o(intg_err) + ); + + // also check for spurious write enables + logic reg_we_err; + logic [24:0] reg_we_check; + prim_reg_we_check #( + .OneHotWidth(25) + ) u_prim_reg_we_check ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .oh_i (reg_we_check), + .en_i (reg_we && !addrmiss), + .err_o (reg_we_err) + ); + + logic err_q; + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + err_q <= '0; + end else if (intg_err || reg_we_err) begin + err_q <= 1'b1; + end + end + + // integrity error output is permanent and should be used for alert generation + // register errors are transactional + assign intg_err_o = err_q | intg_err | reg_we_err; + + // outgoing integrity generation + tlul_pkg::tl_d2h_t tl_o_pre; + tlul_rsp_intg_gen #( + .EnableRspIntgGen(1), + .EnableDataIntgGen(1) + ) u_rsp_intg_gen ( + .tl_i(tl_o_pre), + .tl_o(tl_o) + ); + + tlul_pkg::tl_h2d_t tl_socket_h2d [2]; + tlul_pkg::tl_d2h_t tl_socket_d2h [2]; + + logic [0:0] reg_steer; + + // socket_1n connection + assign tl_reg_h2d = tl_socket_h2d[1]; + assign tl_socket_d2h[1] = tl_reg_d2h; + + assign tl_win_o = tl_socket_h2d[0]; + assign tl_socket_d2h[0] = tl_win_i; + + // Create Socket_1n + tlul_socket_1n #( + .N (2), + .HReqPass (1'b1), + .HRspPass (1'b1), + .DReqPass ({2{1'b1}}), + .DRspPass ({2{1'b1}}), + .HReqDepth (4'h0), + .HRspDepth (4'h0), + .DReqDepth ({2{4'h0}}), + .DRspDepth ({2{4'h0}}), + .ExplicitErrs (1'b0) + ) u_socket ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .tl_h_i (tl_i), + .tl_h_o (tl_o_pre), + .tl_d_o (tl_socket_h2d), + .tl_d_i (tl_socket_d2h), + .dev_select_i (reg_steer) + ); + + // Create steering logic + always_comb begin + reg_steer = + tl_i.a_address[AW-1:0] inside {[128:159]} ? 1'd0 : + // Default set to register + 1'd1; + + // Override this in case of an integrity error + if (intg_err) begin + reg_steer = 1'd1; + end + end + + tlul_adapter_reg #( + .RegAw(AW), + .RegDw(DW), + .EnableDataIntgGen(0) + ) u_reg_if ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + .tl_i (tl_reg_h2d), + .tl_o (tl_reg_d2h), + + .en_ifetch_i(prim_mubi_pkg::MuBi4False), + .intg_error_o(), + + .we_o (reg_we), + .re_o (reg_re), + .addr_o (reg_addr), + .wdata_o (reg_wdata), + .be_o (reg_be), + .busy_i (reg_busy), + .rdata_i (reg_rdata), + .error_i (reg_error) + ); + + // cdc oversampling signals + + assign reg_rdata = reg_rdata_next ; + assign reg_error = addrmiss | wr_err | intg_err; + + // Define SW related signals + // Format: <reg>_<field>_{wd|we|qs} + // or <reg>_{wd|we|qs} if field == 1 or 0 + logic alert_test_we; + logic alert_test_fatal_sw_err_wd; + logic alert_test_recov_sw_err_wd; + logic alert_test_fatal_hw_err_wd; + logic alert_test_recov_hw_err_wd; + logic sw_recov_err_we; + logic [3:0] sw_recov_err_qs; + logic [3:0] sw_recov_err_wd; + logic sw_fatal_err_we; + logic [3:0] sw_fatal_err_qs; + logic [3:0] sw_fatal_err_wd; + logic ibus_regwen_0_we; + logic ibus_regwen_0_qs; + logic ibus_regwen_0_wd; + logic ibus_regwen_1_we; + logic ibus_regwen_1_qs; + logic ibus_regwen_1_wd; + logic ibus_addr_en_0_we; + logic ibus_addr_en_0_qs; + logic ibus_addr_en_0_wd; + logic ibus_addr_en_1_we; + logic ibus_addr_en_1_qs; + logic ibus_addr_en_1_wd; + logic ibus_addr_matching_0_we; + logic [31:0] ibus_addr_matching_0_qs; + logic [31:0] ibus_addr_matching_0_wd; + logic ibus_addr_matching_1_we; + logic [31:0] ibus_addr_matching_1_qs; + logic [31:0] ibus_addr_matching_1_wd; + logic ibus_remap_addr_0_we; + logic [31:0] ibus_remap_addr_0_qs; + logic [31:0] ibus_remap_addr_0_wd; + logic ibus_remap_addr_1_we; + logic [31:0] ibus_remap_addr_1_qs; + logic [31:0] ibus_remap_addr_1_wd; + logic dbus_regwen_0_we; + logic dbus_regwen_0_qs; + logic dbus_regwen_0_wd; + logic dbus_regwen_1_we; + logic dbus_regwen_1_qs; + logic dbus_regwen_1_wd; + logic dbus_addr_en_0_we; + logic dbus_addr_en_0_qs; + logic dbus_addr_en_0_wd; + logic dbus_addr_en_1_we; + logic dbus_addr_en_1_qs; + logic dbus_addr_en_1_wd; + logic dbus_addr_matching_0_we; + logic [31:0] dbus_addr_matching_0_qs; + logic [31:0] dbus_addr_matching_0_wd; + logic dbus_addr_matching_1_we; + logic [31:0] dbus_addr_matching_1_qs; + logic [31:0] dbus_addr_matching_1_wd; + logic dbus_remap_addr_0_we; + logic [31:0] dbus_remap_addr_0_qs; + logic [31:0] dbus_remap_addr_0_wd; + logic dbus_remap_addr_1_we; + logic [31:0] dbus_remap_addr_1_qs; + logic [31:0] dbus_remap_addr_1_wd; + logic nmi_enable_we; + logic nmi_enable_alert_en_qs; + logic nmi_enable_alert_en_wd; + logic nmi_enable_wdog_en_qs; + logic nmi_enable_wdog_en_wd; + logic nmi_state_we; + logic nmi_state_alert_qs; + logic nmi_state_alert_wd; + logic nmi_state_wdog_qs; + logic nmi_state_wdog_wd; + logic err_status_we; + logic err_status_reg_intg_err_qs; + logic err_status_reg_intg_err_wd; + logic err_status_fatal_intg_err_qs; + logic err_status_fatal_intg_err_wd; + logic err_status_fatal_core_err_qs; + logic err_status_fatal_core_err_wd; + logic err_status_recov_core_err_qs; + logic err_status_recov_core_err_wd; + logic rnd_data_re; + logic [31:0] rnd_data_qs; + logic rnd_status_re; + logic rnd_status_rnd_data_valid_qs; + logic rnd_status_rnd_data_fips_qs; + logic fpga_info_re; + logic [31:0] fpga_info_qs; + + // Register instances + // R[alert_test]: V(True) + logic alert_test_qe; + logic [3:0] alert_test_flds_we; + assign alert_test_qe = &alert_test_flds_we; + // F[fatal_sw_err]: 0:0 + prim_subreg_ext #( + .DW (1) + ) u_alert_test_fatal_sw_err ( + .re (1'b0), + .we (alert_test_we), + .wd (alert_test_fatal_sw_err_wd), + .d ('0), + .qre (), + .qe (alert_test_flds_we[0]), + .q (reg2hw.alert_test.fatal_sw_err.q), + .ds (), + .qs () + ); + assign reg2hw.alert_test.fatal_sw_err.qe = alert_test_qe; + + // F[recov_sw_err]: 1:1 + prim_subreg_ext #( + .DW (1) + ) u_alert_test_recov_sw_err ( + .re (1'b0), + .we (alert_test_we), + .wd (alert_test_recov_sw_err_wd), + .d ('0), + .qre (), + .qe (alert_test_flds_we[1]), + .q (reg2hw.alert_test.recov_sw_err.q), + .ds (), + .qs () + ); + assign reg2hw.alert_test.recov_sw_err.qe = alert_test_qe; + + // F[fatal_hw_err]: 2:2 + prim_subreg_ext #( + .DW (1) + ) u_alert_test_fatal_hw_err ( + .re (1'b0), + .we (alert_test_we), + .wd (alert_test_fatal_hw_err_wd), + .d ('0), + .qre (), + .qe (alert_test_flds_we[2]), + .q (reg2hw.alert_test.fatal_hw_err.q), + .ds (), + .qs () + ); + assign reg2hw.alert_test.fatal_hw_err.qe = alert_test_qe; + + // F[recov_hw_err]: 3:3 + prim_subreg_ext #( + .DW (1) + ) u_alert_test_recov_hw_err ( + .re (1'b0), + .we (alert_test_we), + .wd (alert_test_recov_hw_err_wd), + .d ('0), + .qre (), + .qe (alert_test_flds_we[3]), + .q (reg2hw.alert_test.recov_hw_err.q), + .ds (), + .qs () + ); + assign reg2hw.alert_test.recov_hw_err.qe = alert_test_qe; + + + // R[sw_recov_err]: V(False) + prim_subreg #( + .DW (4), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (4'h9), + .Mubi (1'b1) + ) u_sw_recov_err ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (sw_recov_err_we), + .wd (sw_recov_err_wd), + + // from internal hardware + .de (hw2reg.sw_recov_err.de), + .d (hw2reg.sw_recov_err.d), + + // to internal hardware + .qe (), + .q (reg2hw.sw_recov_err.q), + .ds (), + + // to register interface (read) + .qs (sw_recov_err_qs) + ); + + + // R[sw_fatal_err]: V(False) + prim_subreg #( + .DW (4), + .SwAccess(prim_subreg_pkg::SwAccessW1S), + .RESVAL (4'h9), + .Mubi (1'b1) + ) u_sw_fatal_err ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (sw_fatal_err_we), + .wd (sw_fatal_err_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.sw_fatal_err.q), + .ds (), + + // to register interface (read) + .qs (sw_fatal_err_qs) + ); + + + // Subregister 0 of Multireg ibus_regwen + // R[ibus_regwen_0]: V(False) + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW0C), + .RESVAL (1'h1), + .Mubi (1'b0) + ) u_ibus_regwen_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_regwen_0_we), + .wd (ibus_regwen_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (ibus_regwen_0_qs) + ); + + + // Subregister 1 of Multireg ibus_regwen + // R[ibus_regwen_1]: V(False) + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW0C), + .RESVAL (1'h1), + .Mubi (1'b0) + ) u_ibus_regwen_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_regwen_1_we), + .wd (ibus_regwen_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (ibus_regwen_1_qs) + ); + + + // Subregister 0 of Multireg ibus_addr_en + // R[ibus_addr_en_0]: V(False) + // Create REGWEN-gated WE signal + logic ibus_addr_en_0_gated_we; + assign ibus_addr_en_0_gated_we = ibus_addr_en_0_we & ibus_regwen_0_qs; + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_ibus_addr_en_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_addr_en_0_gated_we), + .wd (ibus_addr_en_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ibus_addr_en[0].q), + .ds (), + + // to register interface (read) + .qs (ibus_addr_en_0_qs) + ); + + + // Subregister 1 of Multireg ibus_addr_en + // R[ibus_addr_en_1]: V(False) + // Create REGWEN-gated WE signal + logic ibus_addr_en_1_gated_we; + assign ibus_addr_en_1_gated_we = ibus_addr_en_1_we & ibus_regwen_1_qs; + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_ibus_addr_en_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_addr_en_1_gated_we), + .wd (ibus_addr_en_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ibus_addr_en[1].q), + .ds (), + + // to register interface (read) + .qs (ibus_addr_en_1_qs) + ); + + + // Subregister 0 of Multireg ibus_addr_matching + // R[ibus_addr_matching_0]: V(False) + // Create REGWEN-gated WE signal + logic ibus_addr_matching_0_gated_we; + assign ibus_addr_matching_0_gated_we = ibus_addr_matching_0_we & ibus_regwen_0_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_ibus_addr_matching_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_addr_matching_0_gated_we), + .wd (ibus_addr_matching_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ibus_addr_matching[0].q), + .ds (), + + // to register interface (read) + .qs (ibus_addr_matching_0_qs) + ); + + + // Subregister 1 of Multireg ibus_addr_matching + // R[ibus_addr_matching_1]: V(False) + // Create REGWEN-gated WE signal + logic ibus_addr_matching_1_gated_we; + assign ibus_addr_matching_1_gated_we = ibus_addr_matching_1_we & ibus_regwen_1_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_ibus_addr_matching_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_addr_matching_1_gated_we), + .wd (ibus_addr_matching_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ibus_addr_matching[1].q), + .ds (), + + // to register interface (read) + .qs (ibus_addr_matching_1_qs) + ); + + + // Subregister 0 of Multireg ibus_remap_addr + // R[ibus_remap_addr_0]: V(False) + // Create REGWEN-gated WE signal + logic ibus_remap_addr_0_gated_we; + assign ibus_remap_addr_0_gated_we = ibus_remap_addr_0_we & ibus_regwen_0_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_ibus_remap_addr_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_remap_addr_0_gated_we), + .wd (ibus_remap_addr_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ibus_remap_addr[0].q), + .ds (), + + // to register interface (read) + .qs (ibus_remap_addr_0_qs) + ); + + + // Subregister 1 of Multireg ibus_remap_addr + // R[ibus_remap_addr_1]: V(False) + // Create REGWEN-gated WE signal + logic ibus_remap_addr_1_gated_we; + assign ibus_remap_addr_1_gated_we = ibus_remap_addr_1_we & ibus_regwen_1_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_ibus_remap_addr_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (ibus_remap_addr_1_gated_we), + .wd (ibus_remap_addr_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.ibus_remap_addr[1].q), + .ds (), + + // to register interface (read) + .qs (ibus_remap_addr_1_qs) + ); + + + // Subregister 0 of Multireg dbus_regwen + // R[dbus_regwen_0]: V(False) + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW0C), + .RESVAL (1'h1), + .Mubi (1'b0) + ) u_dbus_regwen_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_regwen_0_we), + .wd (dbus_regwen_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (dbus_regwen_0_qs) + ); + + + // Subregister 1 of Multireg dbus_regwen + // R[dbus_regwen_1]: V(False) + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW0C), + .RESVAL (1'h1), + .Mubi (1'b0) + ) u_dbus_regwen_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_regwen_1_we), + .wd (dbus_regwen_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (dbus_regwen_1_qs) + ); + + + // Subregister 0 of Multireg dbus_addr_en + // R[dbus_addr_en_0]: V(False) + // Create REGWEN-gated WE signal + logic dbus_addr_en_0_gated_we; + assign dbus_addr_en_0_gated_we = dbus_addr_en_0_we & dbus_regwen_0_qs; + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_dbus_addr_en_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_addr_en_0_gated_we), + .wd (dbus_addr_en_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.dbus_addr_en[0].q), + .ds (), + + // to register interface (read) + .qs (dbus_addr_en_0_qs) + ); + + + // Subregister 1 of Multireg dbus_addr_en + // R[dbus_addr_en_1]: V(False) + // Create REGWEN-gated WE signal + logic dbus_addr_en_1_gated_we; + assign dbus_addr_en_1_gated_we = dbus_addr_en_1_we & dbus_regwen_1_qs; + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_dbus_addr_en_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_addr_en_1_gated_we), + .wd (dbus_addr_en_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.dbus_addr_en[1].q), + .ds (), + + // to register interface (read) + .qs (dbus_addr_en_1_qs) + ); + + + // Subregister 0 of Multireg dbus_addr_matching + // R[dbus_addr_matching_0]: V(False) + // Create REGWEN-gated WE signal + logic dbus_addr_matching_0_gated_we; + assign dbus_addr_matching_0_gated_we = dbus_addr_matching_0_we & dbus_regwen_0_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_dbus_addr_matching_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_addr_matching_0_gated_we), + .wd (dbus_addr_matching_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.dbus_addr_matching[0].q), + .ds (), + + // to register interface (read) + .qs (dbus_addr_matching_0_qs) + ); + + + // Subregister 1 of Multireg dbus_addr_matching + // R[dbus_addr_matching_1]: V(False) + // Create REGWEN-gated WE signal + logic dbus_addr_matching_1_gated_we; + assign dbus_addr_matching_1_gated_we = dbus_addr_matching_1_we & dbus_regwen_1_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_dbus_addr_matching_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_addr_matching_1_gated_we), + .wd (dbus_addr_matching_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.dbus_addr_matching[1].q), + .ds (), + + // to register interface (read) + .qs (dbus_addr_matching_1_qs) + ); + + + // Subregister 0 of Multireg dbus_remap_addr + // R[dbus_remap_addr_0]: V(False) + // Create REGWEN-gated WE signal + logic dbus_remap_addr_0_gated_we; + assign dbus_remap_addr_0_gated_we = dbus_remap_addr_0_we & dbus_regwen_0_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_dbus_remap_addr_0 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_remap_addr_0_gated_we), + .wd (dbus_remap_addr_0_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.dbus_remap_addr[0].q), + .ds (), + + // to register interface (read) + .qs (dbus_remap_addr_0_qs) + ); + + + // Subregister 1 of Multireg dbus_remap_addr + // R[dbus_remap_addr_1]: V(False) + // Create REGWEN-gated WE signal + logic dbus_remap_addr_1_gated_we; + assign dbus_remap_addr_1_gated_we = dbus_remap_addr_1_we & dbus_regwen_1_qs; + prim_subreg #( + .DW (32), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (32'h0), + .Mubi (1'b0) + ) u_dbus_remap_addr_1 ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (dbus_remap_addr_1_gated_we), + .wd (dbus_remap_addr_1_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.dbus_remap_addr[1].q), + .ds (), + + // to register interface (read) + .qs (dbus_remap_addr_1_qs) + ); + + + // R[nmi_enable]: V(False) + // F[alert_en]: 0:0 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1S), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_nmi_enable_alert_en ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (nmi_enable_we), + .wd (nmi_enable_alert_en_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.nmi_enable.alert_en.q), + .ds (), + + // to register interface (read) + .qs (nmi_enable_alert_en_qs) + ); + + // F[wdog_en]: 1:1 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1S), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_nmi_enable_wdog_en ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (nmi_enable_we), + .wd (nmi_enable_wdog_en_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.nmi_enable.wdog_en.q), + .ds (), + + // to register interface (read) + .qs (nmi_enable_wdog_en_qs) + ); + + + // R[nmi_state]: V(False) + // F[alert]: 0:0 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_nmi_state_alert ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (nmi_state_we), + .wd (nmi_state_alert_wd), + + // from internal hardware + .de (hw2reg.nmi_state.alert.de), + .d (hw2reg.nmi_state.alert.d), + + // to internal hardware + .qe (), + .q (reg2hw.nmi_state.alert.q), + .ds (), + + // to register interface (read) + .qs (nmi_state_alert_qs) + ); + + // F[wdog]: 1:1 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_nmi_state_wdog ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (nmi_state_we), + .wd (nmi_state_wdog_wd), + + // from internal hardware + .de (hw2reg.nmi_state.wdog.de), + .d (hw2reg.nmi_state.wdog.d), + + // to internal hardware + .qe (), + .q (reg2hw.nmi_state.wdog.q), + .ds (), + + // to register interface (read) + .qs (nmi_state_wdog_qs) + ); + + + // R[err_status]: V(False) + // F[reg_intg_err]: 0:0 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_err_status_reg_intg_err ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (err_status_we), + .wd (err_status_reg_intg_err_wd), + + // from internal hardware + .de (hw2reg.err_status.reg_intg_err.de), + .d (hw2reg.err_status.reg_intg_err.d), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (err_status_reg_intg_err_qs) + ); + + // F[fatal_intg_err]: 8:8 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_err_status_fatal_intg_err ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (err_status_we), + .wd (err_status_fatal_intg_err_wd), + + // from internal hardware + .de (hw2reg.err_status.fatal_intg_err.de), + .d (hw2reg.err_status.fatal_intg_err.d), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (err_status_fatal_intg_err_qs) + ); + + // F[fatal_core_err]: 9:9 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_err_status_fatal_core_err ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (err_status_we), + .wd (err_status_fatal_core_err_wd), + + // from internal hardware + .de (hw2reg.err_status.fatal_core_err.de), + .d (hw2reg.err_status.fatal_core_err.d), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (err_status_fatal_core_err_qs) + ); + + // F[recov_core_err]: 10:10 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_err_status_recov_core_err ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (err_status_we), + .wd (err_status_recov_core_err_wd), + + // from internal hardware + .de (hw2reg.err_status.recov_core_err.de), + .d (hw2reg.err_status.recov_core_err.d), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (err_status_recov_core_err_qs) + ); + + + // R[rnd_data]: V(True) + prim_subreg_ext #( + .DW (32) + ) u_rnd_data ( + .re (rnd_data_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.rnd_data.d), + .qre (reg2hw.rnd_data.re), + .qe (), + .q (reg2hw.rnd_data.q), + .ds (), + .qs (rnd_data_qs) + ); + + + // R[rnd_status]: V(True) + // F[rnd_data_valid]: 0:0 + prim_subreg_ext #( + .DW (1) + ) u_rnd_status_rnd_data_valid ( + .re (rnd_status_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.rnd_status.rnd_data_valid.d), + .qre (), + .qe (), + .q (), + .ds (), + .qs (rnd_status_rnd_data_valid_qs) + ); + + // F[rnd_data_fips]: 1:1 + prim_subreg_ext #( + .DW (1) + ) u_rnd_status_rnd_data_fips ( + .re (rnd_status_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.rnd_status.rnd_data_fips.d), + .qre (), + .qe (), + .q (), + .ds (), + .qs (rnd_status_rnd_data_fips_qs) + ); + + + // R[fpga_info]: V(True) + prim_subreg_ext #( + .DW (32) + ) u_fpga_info ( + .re (fpga_info_re), + .we (1'b0), + .wd ('0), + .d (hw2reg.fpga_info.d), + .qre (), + .qe (), + .q (), + .ds (), + .qs (fpga_info_qs) + ); + + + + logic [24:0] addr_hit; + always_comb begin + addr_hit[ 0] = (reg_addr == RV_CORE_IBEX_ALERT_TEST_OFFSET); + addr_hit[ 1] = (reg_addr == RV_CORE_IBEX_SW_RECOV_ERR_OFFSET); + addr_hit[ 2] = (reg_addr == RV_CORE_IBEX_SW_FATAL_ERR_OFFSET); + addr_hit[ 3] = (reg_addr == RV_CORE_IBEX_IBUS_REGWEN_0_OFFSET); + addr_hit[ 4] = (reg_addr == RV_CORE_IBEX_IBUS_REGWEN_1_OFFSET); + addr_hit[ 5] = (reg_addr == RV_CORE_IBEX_IBUS_ADDR_EN_0_OFFSET); + addr_hit[ 6] = (reg_addr == RV_CORE_IBEX_IBUS_ADDR_EN_1_OFFSET); + addr_hit[ 7] = (reg_addr == RV_CORE_IBEX_IBUS_ADDR_MATCHING_0_OFFSET); + addr_hit[ 8] = (reg_addr == RV_CORE_IBEX_IBUS_ADDR_MATCHING_1_OFFSET); + addr_hit[ 9] = (reg_addr == RV_CORE_IBEX_IBUS_REMAP_ADDR_0_OFFSET); + addr_hit[10] = (reg_addr == RV_CORE_IBEX_IBUS_REMAP_ADDR_1_OFFSET); + addr_hit[11] = (reg_addr == RV_CORE_IBEX_DBUS_REGWEN_0_OFFSET); + addr_hit[12] = (reg_addr == RV_CORE_IBEX_DBUS_REGWEN_1_OFFSET); + addr_hit[13] = (reg_addr == RV_CORE_IBEX_DBUS_ADDR_EN_0_OFFSET); + addr_hit[14] = (reg_addr == RV_CORE_IBEX_DBUS_ADDR_EN_1_OFFSET); + addr_hit[15] = (reg_addr == RV_CORE_IBEX_DBUS_ADDR_MATCHING_0_OFFSET); + addr_hit[16] = (reg_addr == RV_CORE_IBEX_DBUS_ADDR_MATCHING_1_OFFSET); + addr_hit[17] = (reg_addr == RV_CORE_IBEX_DBUS_REMAP_ADDR_0_OFFSET); + addr_hit[18] = (reg_addr == RV_CORE_IBEX_DBUS_REMAP_ADDR_1_OFFSET); + addr_hit[19] = (reg_addr == RV_CORE_IBEX_NMI_ENABLE_OFFSET); + addr_hit[20] = (reg_addr == RV_CORE_IBEX_NMI_STATE_OFFSET); + addr_hit[21] = (reg_addr == RV_CORE_IBEX_ERR_STATUS_OFFSET); + addr_hit[22] = (reg_addr == RV_CORE_IBEX_RND_DATA_OFFSET); + addr_hit[23] = (reg_addr == RV_CORE_IBEX_RND_STATUS_OFFSET); + addr_hit[24] = (reg_addr == RV_CORE_IBEX_FPGA_INFO_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[ 0] & (|(RV_CORE_IBEX_CFG_PERMIT[ 0] & ~reg_be))) | + (addr_hit[ 1] & (|(RV_CORE_IBEX_CFG_PERMIT[ 1] & ~reg_be))) | + (addr_hit[ 2] & (|(RV_CORE_IBEX_CFG_PERMIT[ 2] & ~reg_be))) | + (addr_hit[ 3] & (|(RV_CORE_IBEX_CFG_PERMIT[ 3] & ~reg_be))) | + (addr_hit[ 4] & (|(RV_CORE_IBEX_CFG_PERMIT[ 4] & ~reg_be))) | + (addr_hit[ 5] & (|(RV_CORE_IBEX_CFG_PERMIT[ 5] & ~reg_be))) | + (addr_hit[ 6] & (|(RV_CORE_IBEX_CFG_PERMIT[ 6] & ~reg_be))) | + (addr_hit[ 7] & (|(RV_CORE_IBEX_CFG_PERMIT[ 7] & ~reg_be))) | + (addr_hit[ 8] & (|(RV_CORE_IBEX_CFG_PERMIT[ 8] & ~reg_be))) | + (addr_hit[ 9] & (|(RV_CORE_IBEX_CFG_PERMIT[ 9] & ~reg_be))) | + (addr_hit[10] & (|(RV_CORE_IBEX_CFG_PERMIT[10] & ~reg_be))) | + (addr_hit[11] & (|(RV_CORE_IBEX_CFG_PERMIT[11] & ~reg_be))) | + (addr_hit[12] & (|(RV_CORE_IBEX_CFG_PERMIT[12] & ~reg_be))) | + (addr_hit[13] & (|(RV_CORE_IBEX_CFG_PERMIT[13] & ~reg_be))) | + (addr_hit[14] & (|(RV_CORE_IBEX_CFG_PERMIT[14] & ~reg_be))) | + (addr_hit[15] & (|(RV_CORE_IBEX_CFG_PERMIT[15] & ~reg_be))) | + (addr_hit[16] & (|(RV_CORE_IBEX_CFG_PERMIT[16] & ~reg_be))) | + (addr_hit[17] & (|(RV_CORE_IBEX_CFG_PERMIT[17] & ~reg_be))) | + (addr_hit[18] & (|(RV_CORE_IBEX_CFG_PERMIT[18] & ~reg_be))) | + (addr_hit[19] & (|(RV_CORE_IBEX_CFG_PERMIT[19] & ~reg_be))) | + (addr_hit[20] & (|(RV_CORE_IBEX_CFG_PERMIT[20] & ~reg_be))) | + (addr_hit[21] & (|(RV_CORE_IBEX_CFG_PERMIT[21] & ~reg_be))) | + (addr_hit[22] & (|(RV_CORE_IBEX_CFG_PERMIT[22] & ~reg_be))) | + (addr_hit[23] & (|(RV_CORE_IBEX_CFG_PERMIT[23] & ~reg_be))) | + (addr_hit[24] & (|(RV_CORE_IBEX_CFG_PERMIT[24] & ~reg_be))))); + end + + // Generate write-enables + assign alert_test_we = addr_hit[0] & reg_we & !reg_error; + + assign alert_test_fatal_sw_err_wd = reg_wdata[0]; + + assign alert_test_recov_sw_err_wd = reg_wdata[1]; + + assign alert_test_fatal_hw_err_wd = reg_wdata[2]; + + assign alert_test_recov_hw_err_wd = reg_wdata[3]; + assign sw_recov_err_we = addr_hit[1] & reg_we & !reg_error; + + assign sw_recov_err_wd = reg_wdata[3:0]; + assign sw_fatal_err_we = addr_hit[2] & reg_we & !reg_error; + + assign sw_fatal_err_wd = reg_wdata[3:0]; + assign ibus_regwen_0_we = addr_hit[3] & reg_we & !reg_error; + + assign ibus_regwen_0_wd = reg_wdata[0]; + assign ibus_regwen_1_we = addr_hit[4] & reg_we & !reg_error; + + assign ibus_regwen_1_wd = reg_wdata[0]; + assign ibus_addr_en_0_we = addr_hit[5] & reg_we & !reg_error; + + assign ibus_addr_en_0_wd = reg_wdata[0]; + assign ibus_addr_en_1_we = addr_hit[6] & reg_we & !reg_error; + + assign ibus_addr_en_1_wd = reg_wdata[0]; + assign ibus_addr_matching_0_we = addr_hit[7] & reg_we & !reg_error; + + assign ibus_addr_matching_0_wd = reg_wdata[31:0]; + assign ibus_addr_matching_1_we = addr_hit[8] & reg_we & !reg_error; + + assign ibus_addr_matching_1_wd = reg_wdata[31:0]; + assign ibus_remap_addr_0_we = addr_hit[9] & reg_we & !reg_error; + + assign ibus_remap_addr_0_wd = reg_wdata[31:0]; + assign ibus_remap_addr_1_we = addr_hit[10] & reg_we & !reg_error; + + assign ibus_remap_addr_1_wd = reg_wdata[31:0]; + assign dbus_regwen_0_we = addr_hit[11] & reg_we & !reg_error; + + assign dbus_regwen_0_wd = reg_wdata[0]; + assign dbus_regwen_1_we = addr_hit[12] & reg_we & !reg_error; + + assign dbus_regwen_1_wd = reg_wdata[0]; + assign dbus_addr_en_0_we = addr_hit[13] & reg_we & !reg_error; + + assign dbus_addr_en_0_wd = reg_wdata[0]; + assign dbus_addr_en_1_we = addr_hit[14] & reg_we & !reg_error; + + assign dbus_addr_en_1_wd = reg_wdata[0]; + assign dbus_addr_matching_0_we = addr_hit[15] & reg_we & !reg_error; + + assign dbus_addr_matching_0_wd = reg_wdata[31:0]; + assign dbus_addr_matching_1_we = addr_hit[16] & reg_we & !reg_error; + + assign dbus_addr_matching_1_wd = reg_wdata[31:0]; + assign dbus_remap_addr_0_we = addr_hit[17] & reg_we & !reg_error; + + assign dbus_remap_addr_0_wd = reg_wdata[31:0]; + assign dbus_remap_addr_1_we = addr_hit[18] & reg_we & !reg_error; + + assign dbus_remap_addr_1_wd = reg_wdata[31:0]; + assign nmi_enable_we = addr_hit[19] & reg_we & !reg_error; + + assign nmi_enable_alert_en_wd = reg_wdata[0]; + + assign nmi_enable_wdog_en_wd = reg_wdata[1]; + assign nmi_state_we = addr_hit[20] & reg_we & !reg_error; + + assign nmi_state_alert_wd = reg_wdata[0]; + + assign nmi_state_wdog_wd = reg_wdata[1]; + assign err_status_we = addr_hit[21] & reg_we & !reg_error; + + assign err_status_reg_intg_err_wd = reg_wdata[0]; + + assign err_status_fatal_intg_err_wd = reg_wdata[8]; + + assign err_status_fatal_core_err_wd = reg_wdata[9]; + + assign err_status_recov_core_err_wd = reg_wdata[10]; + assign rnd_data_re = addr_hit[22] & reg_re & !reg_error; + assign rnd_status_re = addr_hit[23] & reg_re & !reg_error; + assign fpga_info_re = addr_hit[24] & reg_re & !reg_error; + + // Assign write-enables to checker logic vector. + always_comb begin + reg_we_check[0] = alert_test_we; + reg_we_check[1] = sw_recov_err_we; + reg_we_check[2] = sw_fatal_err_we; + reg_we_check[3] = ibus_regwen_0_we; + reg_we_check[4] = ibus_regwen_1_we; + reg_we_check[5] = ibus_addr_en_0_gated_we; + reg_we_check[6] = ibus_addr_en_1_gated_we; + reg_we_check[7] = ibus_addr_matching_0_gated_we; + reg_we_check[8] = ibus_addr_matching_1_gated_we; + reg_we_check[9] = ibus_remap_addr_0_gated_we; + reg_we_check[10] = ibus_remap_addr_1_gated_we; + reg_we_check[11] = dbus_regwen_0_we; + reg_we_check[12] = dbus_regwen_1_we; + reg_we_check[13] = dbus_addr_en_0_gated_we; + reg_we_check[14] = dbus_addr_en_1_gated_we; + reg_we_check[15] = dbus_addr_matching_0_gated_we; + reg_we_check[16] = dbus_addr_matching_1_gated_we; + reg_we_check[17] = dbus_remap_addr_0_gated_we; + reg_we_check[18] = dbus_remap_addr_1_gated_we; + reg_we_check[19] = nmi_enable_we; + reg_we_check[20] = nmi_state_we; + reg_we_check[21] = err_status_we; + reg_we_check[22] = 1'b0; + reg_we_check[23] = 1'b0; + reg_we_check[24] = 1'b0; + end + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[0] = '0; + reg_rdata_next[1] = '0; + reg_rdata_next[2] = '0; + reg_rdata_next[3] = '0; + end + + addr_hit[1]: begin + reg_rdata_next[3:0] = sw_recov_err_qs; + end + + addr_hit[2]: begin + reg_rdata_next[3:0] = sw_fatal_err_qs; + end + + addr_hit[3]: begin + reg_rdata_next[0] = ibus_regwen_0_qs; + end + + addr_hit[4]: begin + reg_rdata_next[0] = ibus_regwen_1_qs; + end + + addr_hit[5]: begin + reg_rdata_next[0] = ibus_addr_en_0_qs; + end + + addr_hit[6]: begin + reg_rdata_next[0] = ibus_addr_en_1_qs; + end + + addr_hit[7]: begin + reg_rdata_next[31:0] = ibus_addr_matching_0_qs; + end + + addr_hit[8]: begin + reg_rdata_next[31:0] = ibus_addr_matching_1_qs; + end + + addr_hit[9]: begin + reg_rdata_next[31:0] = ibus_remap_addr_0_qs; + end + + addr_hit[10]: begin + reg_rdata_next[31:0] = ibus_remap_addr_1_qs; + end + + addr_hit[11]: begin + reg_rdata_next[0] = dbus_regwen_0_qs; + end + + addr_hit[12]: begin + reg_rdata_next[0] = dbus_regwen_1_qs; + end + + addr_hit[13]: begin + reg_rdata_next[0] = dbus_addr_en_0_qs; + end + + addr_hit[14]: begin + reg_rdata_next[0] = dbus_addr_en_1_qs; + end + + addr_hit[15]: begin + reg_rdata_next[31:0] = dbus_addr_matching_0_qs; + end + + addr_hit[16]: begin + reg_rdata_next[31:0] = dbus_addr_matching_1_qs; + end + + addr_hit[17]: begin + reg_rdata_next[31:0] = dbus_remap_addr_0_qs; + end + + addr_hit[18]: begin + reg_rdata_next[31:0] = dbus_remap_addr_1_qs; + end + + addr_hit[19]: begin + reg_rdata_next[0] = nmi_enable_alert_en_qs; + reg_rdata_next[1] = nmi_enable_wdog_en_qs; + end + + addr_hit[20]: begin + reg_rdata_next[0] = nmi_state_alert_qs; + reg_rdata_next[1] = nmi_state_wdog_qs; + end + + addr_hit[21]: begin + reg_rdata_next[0] = err_status_reg_intg_err_qs; + reg_rdata_next[8] = err_status_fatal_intg_err_qs; + reg_rdata_next[9] = err_status_fatal_core_err_qs; + reg_rdata_next[10] = err_status_recov_core_err_qs; + end + + addr_hit[22]: begin + reg_rdata_next[31:0] = rnd_data_qs; + end + + addr_hit[23]: begin + reg_rdata_next[0] = rnd_status_rnd_data_valid_qs; + reg_rdata_next[1] = rnd_status_rnd_data_fips_qs; + end + + addr_hit[24]: begin + reg_rdata_next[31:0] = fpga_info_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // shadow busy + logic shadow_busy; + assign shadow_busy = 1'b0; + + // register busy + assign reg_busy = shadow_busy; + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni) + `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni) + + `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni) + + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni) + + // this is formulated as an assumption such that the FPV testbenches do disprove this + // property by mistake + //`ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.chk_en == tlul_pkg::CheckDis) + +endmodule
diff --git a/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_peri.sv b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_peri.sv new file mode 100644 index 0000000..7be05c4 --- /dev/null +++ b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_peri.sv
@@ -0,0 +1,130 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// RV core ibex peripheral +// + +`include "prim_assert.sv" + +module rv_core_ibex_peri + import rv_core_ibex_peri_pkg::*; + import rv_core_ibex_peri_reg_pkg::*; +#( + parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}}, + // Number of cycles a differential skew is tolerated on the alert signal + parameter int unsigned AlertSkewCycles = 1 +) ( + input clk_i, + input rst_ni, + + // Bus Interface + input tlul_pkg::tl_h2d_t tl_i, + output tlul_pkg::tl_d2h_t tl_o, + + // alert events from rv_core_ibex + input alert_event_t fatal_intg_event_i, + input alert_event_t fatal_core_event_i, + input alert_event_t recov_core_event_i, + + // region configuration to ibex + output region_cfg_t [NumRegions-1:0] ibus_region_cfg_o, + output region_cfg_t [NumRegions-1:0] dbus_region_cfg_o, + + // interrupts and alerts + input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i, + output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o +); + + // Register module + rv_core_ibex_peri_reg2hw_t reg2hw; + rv_core_ibex_peri_hw2reg_t hw2reg; + + logic intg_err; + rv_core_ibex_peri_reg_top u_reg ( + .clk_i, + .rst_ni, + .tl_i, + .tl_o, + .reg2hw, + .hw2reg, + .intg_err_o (intg_err) + ); + + /////////////////////// + // Region assignments + /////////////////////// + + for(genvar i = 0; i < NumRegions; i++) begin : gen_ibus_region_cfgs + assign ibus_region_cfg_o[i].en = reg2hw.ibus_addr_en[i]; + assign ibus_region_cfg_o[i].matching_region = reg2hw.ibus_addr_matching[i]; + assign ibus_region_cfg_o[i].remap_addr = reg2hw.ibus_remap_addr[i]; + end + + for(genvar i = 0; i < NumRegions; i++) begin : gen_dbus_region_cfgs + assign dbus_region_cfg_o[i].en = reg2hw.dbus_addr_en[i]; + assign dbus_region_cfg_o[i].matching_region = reg2hw.dbus_addr_matching[i]; + assign dbus_region_cfg_o[i].remap_addr = reg2hw.dbus_remap_addr[i]; + end + + /////////////////////// + // Error assignment + /////////////////////// + logic fatal_intg_err, fatal_core_err, recov_core_err; + + assign fatal_intg_err = fatal_intg_event_i != EventOff; + assign fatal_core_err = fatal_core_event_i != EventOff; + assign recov_core_err = recov_core_event_i != EventOff; + + assign hw2reg.err_status.reg_intg_err.d = 1'b1; + assign hw2reg.err_status.reg_intg_err.de = intg_err; + assign hw2reg.err_status.fatal_intg_err.d = 1'b1; + assign hw2reg.err_status.fatal_intg_err.de = fatal_intg_err; + assign hw2reg.err_status.fatal_core_err.d = 1'b1; + assign hw2reg.err_status.fatal_core_err.de = fatal_core_err; + assign hw2reg.err_status.recov_core_err.d = 1'b1; + assign hw2reg.err_status.recov_core_err.de = recov_core_err; + + /////////////////////// + // Alert generation + /////////////////////// + + logic [NumAlerts-1:0] alert_test; + assign alert_test[0] = reg2hw.alert_test.fatal_sw_err.q & + reg2hw.alert_test.fatal_sw_err.qe; + assign alert_test[1] = reg2hw.alert_test.recov_sw_err.q & + reg2hw.alert_test.recov_sw_err.qe; + assign alert_test[2] = reg2hw.alert_test.fatal_hw_err.q & + reg2hw.alert_test.fatal_hw_err.qe; + assign alert_test[3] = reg2hw.alert_test.recov_hw_err.q & + reg2hw.alert_test.recov_hw_err.qe; + + localparam bit [NumAlerts-1:0] AlertFatal = '{1, 0, 1, 0}; + + logic [NumAlerts-1:0] alert_events; + + assign alert_events[0] = reg2hw.sw_alert[0].q != EventOff; + assign alert_events[1] = reg2hw.sw_alert[1].q != EventOff; + assign alert_events[2] = intg_err | fatal_intg_err | fatal_core_err; + assign alert_events[3] = recov_core_err; + + for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_senders + prim_alert_sender #( + .AsyncOn(AlertAsyncOn[0]), + .SkewCycles(AlertSkewCycles), + .IsFatal(AlertFatal[i]) + ) u_alert_sender ( + .clk_i, + .rst_ni, + .alert_test_i(alert_test[i]), + .alert_req_i(alert_events[i]), + .alert_ack_o(), + .alert_state_o(), + .alert_rx_i(alert_rx_i[i]), + .alert_tx_o(alert_tx_o[i]) + ); + end + + // Alert assertions for reg_we onehot check + `ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(RegWeOnehotCheck_A, u_reg, alert_tx_o[2]) +endmodule // rv_core_ibex_peri
diff --git a/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_reg_pkg.sv b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_reg_pkg.sv new file mode 100644 index 0000000..74b9bad --- /dev/null +++ b/fpga/ip/rv_core_ibex/rtl/rv_core_ibex_reg_pkg.sv
@@ -0,0 +1,281 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package rv_core_ibex_reg_pkg; + + // Param list + parameter int NumSwAlerts = 2; + parameter int NumRegions = 2; + parameter int NumScratchWords = 8; + parameter int NumAlerts = 4; + + // Address widths within the block + parameter int CfgAw = 8; + + // Number of registers for every interface + parameter int NumRegsCfg = 25; + + ////////////////////////////////////////////// + // Typedefs for registers for cfg interface // + ////////////////////////////////////////////// + + typedef struct packed { + struct packed { + logic q; + logic qe; + } recov_hw_err; + struct packed { + logic q; + logic qe; + } fatal_hw_err; + struct packed { + logic q; + logic qe; + } recov_sw_err; + struct packed { + logic q; + logic qe; + } fatal_sw_err; + } rv_core_ibex_reg2hw_alert_test_reg_t; + + typedef struct packed { + logic [3:0] q; + } rv_core_ibex_reg2hw_sw_recov_err_reg_t; + + typedef struct packed { + logic [3:0] q; + } rv_core_ibex_reg2hw_sw_fatal_err_reg_t; + + typedef struct packed { + logic q; + } rv_core_ibex_reg2hw_ibus_addr_en_mreg_t; + + typedef struct packed { + logic [31:0] q; + } rv_core_ibex_reg2hw_ibus_addr_matching_mreg_t; + + typedef struct packed { + logic [31:0] q; + } rv_core_ibex_reg2hw_ibus_remap_addr_mreg_t; + + typedef struct packed { + logic q; + } rv_core_ibex_reg2hw_dbus_addr_en_mreg_t; + + typedef struct packed { + logic [31:0] q; + } rv_core_ibex_reg2hw_dbus_addr_matching_mreg_t; + + typedef struct packed { + logic [31:0] q; + } rv_core_ibex_reg2hw_dbus_remap_addr_mreg_t; + + typedef struct packed { + struct packed { + logic q; + } wdog_en; + struct packed { + logic q; + } alert_en; + } rv_core_ibex_reg2hw_nmi_enable_reg_t; + + typedef struct packed { + struct packed { + logic q; + } wdog; + struct packed { + logic q; + } alert; + } rv_core_ibex_reg2hw_nmi_state_reg_t; + + typedef struct packed { + logic [31:0] q; + logic re; + } rv_core_ibex_reg2hw_rnd_data_reg_t; + + typedef struct packed { + logic [3:0] d; + logic de; + } rv_core_ibex_hw2reg_sw_recov_err_reg_t; + + typedef struct packed { + struct packed { + logic d; + logic de; + } wdog; + struct packed { + logic d; + logic de; + } alert; + } rv_core_ibex_hw2reg_nmi_state_reg_t; + + typedef struct packed { + struct packed { + logic d; + logic de; + } recov_core_err; + struct packed { + logic d; + logic de; + } fatal_core_err; + struct packed { + logic d; + logic de; + } fatal_intg_err; + struct packed { + logic d; + logic de; + } reg_intg_err; + } rv_core_ibex_hw2reg_err_status_reg_t; + + typedef struct packed { + logic [31:0] d; + } rv_core_ibex_hw2reg_rnd_data_reg_t; + + typedef struct packed { + struct packed { + logic d; + } rnd_data_fips; + struct packed { + logic d; + } rnd_data_valid; + } rv_core_ibex_hw2reg_rnd_status_reg_t; + + typedef struct packed { + logic [31:0] d; + } rv_core_ibex_hw2reg_fpga_info_reg_t; + + // Register -> HW type for cfg interface + typedef struct packed { + rv_core_ibex_reg2hw_alert_test_reg_t alert_test; // [312:305] + rv_core_ibex_reg2hw_sw_recov_err_reg_t sw_recov_err; // [304:301] + rv_core_ibex_reg2hw_sw_fatal_err_reg_t sw_fatal_err; // [300:297] + rv_core_ibex_reg2hw_ibus_addr_en_mreg_t [1:0] ibus_addr_en; // [296:295] + rv_core_ibex_reg2hw_ibus_addr_matching_mreg_t [1:0] ibus_addr_matching; // [294:231] + rv_core_ibex_reg2hw_ibus_remap_addr_mreg_t [1:0] ibus_remap_addr; // [230:167] + rv_core_ibex_reg2hw_dbus_addr_en_mreg_t [1:0] dbus_addr_en; // [166:165] + rv_core_ibex_reg2hw_dbus_addr_matching_mreg_t [1:0] dbus_addr_matching; // [164:101] + rv_core_ibex_reg2hw_dbus_remap_addr_mreg_t [1:0] dbus_remap_addr; // [100:37] + rv_core_ibex_reg2hw_nmi_enable_reg_t nmi_enable; // [36:35] + rv_core_ibex_reg2hw_nmi_state_reg_t nmi_state; // [34:33] + rv_core_ibex_reg2hw_rnd_data_reg_t rnd_data; // [32:0] + } rv_core_ibex_cfg_reg2hw_t; + + // HW -> register type for cfg interface + typedef struct packed { + rv_core_ibex_hw2reg_sw_recov_err_reg_t sw_recov_err; // [82:78] + rv_core_ibex_hw2reg_nmi_state_reg_t nmi_state; // [77:74] + rv_core_ibex_hw2reg_err_status_reg_t err_status; // [73:66] + rv_core_ibex_hw2reg_rnd_data_reg_t rnd_data; // [65:34] + rv_core_ibex_hw2reg_rnd_status_reg_t rnd_status; // [33:32] + rv_core_ibex_hw2reg_fpga_info_reg_t fpga_info; // [31:0] + } rv_core_ibex_cfg_hw2reg_t; + + // Register offsets for cfg interface + parameter logic [CfgAw-1:0] RV_CORE_IBEX_ALERT_TEST_OFFSET = 8'h 0; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_SW_RECOV_ERR_OFFSET = 8'h 4; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_SW_FATAL_ERR_OFFSET = 8'h 8; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_REGWEN_0_OFFSET = 8'h c; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_REGWEN_1_OFFSET = 8'h 10; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_ADDR_EN_0_OFFSET = 8'h 14; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_ADDR_EN_1_OFFSET = 8'h 18; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_ADDR_MATCHING_0_OFFSET = 8'h 1c; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_ADDR_MATCHING_1_OFFSET = 8'h 20; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_REMAP_ADDR_0_OFFSET = 8'h 24; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_IBUS_REMAP_ADDR_1_OFFSET = 8'h 28; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_REGWEN_0_OFFSET = 8'h 2c; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_REGWEN_1_OFFSET = 8'h 30; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_ADDR_EN_0_OFFSET = 8'h 34; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_ADDR_EN_1_OFFSET = 8'h 38; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_ADDR_MATCHING_0_OFFSET = 8'h 3c; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_ADDR_MATCHING_1_OFFSET = 8'h 40; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_REMAP_ADDR_0_OFFSET = 8'h 44; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DBUS_REMAP_ADDR_1_OFFSET = 8'h 48; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_NMI_ENABLE_OFFSET = 8'h 4c; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_NMI_STATE_OFFSET = 8'h 50; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_ERR_STATUS_OFFSET = 8'h 54; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_RND_DATA_OFFSET = 8'h 58; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_RND_STATUS_OFFSET = 8'h 5c; + parameter logic [CfgAw-1:0] RV_CORE_IBEX_FPGA_INFO_OFFSET = 8'h 60; + + // Reset values for hwext registers and their fields for cfg interface + parameter logic [3:0] RV_CORE_IBEX_ALERT_TEST_RESVAL = 4'h 0; + parameter logic [0:0] RV_CORE_IBEX_ALERT_TEST_FATAL_SW_ERR_RESVAL = 1'h 0; + parameter logic [0:0] RV_CORE_IBEX_ALERT_TEST_RECOV_SW_ERR_RESVAL = 1'h 0; + parameter logic [0:0] RV_CORE_IBEX_ALERT_TEST_FATAL_HW_ERR_RESVAL = 1'h 0; + parameter logic [0:0] RV_CORE_IBEX_ALERT_TEST_RECOV_HW_ERR_RESVAL = 1'h 0; + parameter logic [31:0] RV_CORE_IBEX_RND_DATA_RESVAL = 32'h 0; + parameter logic [31:0] RV_CORE_IBEX_RND_DATA_DATA_RESVAL = 32'h 0; + parameter logic [1:0] RV_CORE_IBEX_RND_STATUS_RESVAL = 2'h 0; + parameter logic [0:0] RV_CORE_IBEX_RND_STATUS_RND_DATA_VALID_RESVAL = 1'h 0; + parameter logic [0:0] RV_CORE_IBEX_RND_STATUS_RND_DATA_FIPS_RESVAL = 1'h 0; + parameter logic [31:0] RV_CORE_IBEX_FPGA_INFO_RESVAL = 32'h 0; + parameter logic [31:0] RV_CORE_IBEX_FPGA_INFO_VAL_RESVAL = 32'h 0; + + // Window parameters for cfg interface + parameter logic [CfgAw-1:0] RV_CORE_IBEX_DV_SIM_WINDOW_OFFSET = 8'h 80; + parameter int unsigned RV_CORE_IBEX_DV_SIM_WINDOW_SIZE = 'h 20; + parameter int unsigned RV_CORE_IBEX_DV_SIM_WINDOW_IDX = 0; + + // Register index for cfg interface + typedef enum int { + RV_CORE_IBEX_ALERT_TEST, + RV_CORE_IBEX_SW_RECOV_ERR, + RV_CORE_IBEX_SW_FATAL_ERR, + RV_CORE_IBEX_IBUS_REGWEN_0, + RV_CORE_IBEX_IBUS_REGWEN_1, + RV_CORE_IBEX_IBUS_ADDR_EN_0, + RV_CORE_IBEX_IBUS_ADDR_EN_1, + RV_CORE_IBEX_IBUS_ADDR_MATCHING_0, + RV_CORE_IBEX_IBUS_ADDR_MATCHING_1, + RV_CORE_IBEX_IBUS_REMAP_ADDR_0, + RV_CORE_IBEX_IBUS_REMAP_ADDR_1, + RV_CORE_IBEX_DBUS_REGWEN_0, + RV_CORE_IBEX_DBUS_REGWEN_1, + RV_CORE_IBEX_DBUS_ADDR_EN_0, + RV_CORE_IBEX_DBUS_ADDR_EN_1, + RV_CORE_IBEX_DBUS_ADDR_MATCHING_0, + RV_CORE_IBEX_DBUS_ADDR_MATCHING_1, + RV_CORE_IBEX_DBUS_REMAP_ADDR_0, + RV_CORE_IBEX_DBUS_REMAP_ADDR_1, + RV_CORE_IBEX_NMI_ENABLE, + RV_CORE_IBEX_NMI_STATE, + RV_CORE_IBEX_ERR_STATUS, + RV_CORE_IBEX_RND_DATA, + RV_CORE_IBEX_RND_STATUS, + RV_CORE_IBEX_FPGA_INFO + } rv_core_ibex_cfg_id_e; + + // Register width information to check illegal writes for cfg interface + parameter logic [3:0] RV_CORE_IBEX_CFG_PERMIT [25] = '{ + 4'b 0001, // index[ 0] RV_CORE_IBEX_ALERT_TEST + 4'b 0001, // index[ 1] RV_CORE_IBEX_SW_RECOV_ERR + 4'b 0001, // index[ 2] RV_CORE_IBEX_SW_FATAL_ERR + 4'b 0001, // index[ 3] RV_CORE_IBEX_IBUS_REGWEN_0 + 4'b 0001, // index[ 4] RV_CORE_IBEX_IBUS_REGWEN_1 + 4'b 0001, // index[ 5] RV_CORE_IBEX_IBUS_ADDR_EN_0 + 4'b 0001, // index[ 6] RV_CORE_IBEX_IBUS_ADDR_EN_1 + 4'b 1111, // index[ 7] RV_CORE_IBEX_IBUS_ADDR_MATCHING_0 + 4'b 1111, // index[ 8] RV_CORE_IBEX_IBUS_ADDR_MATCHING_1 + 4'b 1111, // index[ 9] RV_CORE_IBEX_IBUS_REMAP_ADDR_0 + 4'b 1111, // index[10] RV_CORE_IBEX_IBUS_REMAP_ADDR_1 + 4'b 0001, // index[11] RV_CORE_IBEX_DBUS_REGWEN_0 + 4'b 0001, // index[12] RV_CORE_IBEX_DBUS_REGWEN_1 + 4'b 0001, // index[13] RV_CORE_IBEX_DBUS_ADDR_EN_0 + 4'b 0001, // index[14] RV_CORE_IBEX_DBUS_ADDR_EN_1 + 4'b 1111, // index[15] RV_CORE_IBEX_DBUS_ADDR_MATCHING_0 + 4'b 1111, // index[16] RV_CORE_IBEX_DBUS_ADDR_MATCHING_1 + 4'b 1111, // index[17] RV_CORE_IBEX_DBUS_REMAP_ADDR_0 + 4'b 1111, // index[18] RV_CORE_IBEX_DBUS_REMAP_ADDR_1 + 4'b 0001, // index[19] RV_CORE_IBEX_NMI_ENABLE + 4'b 0001, // index[20] RV_CORE_IBEX_NMI_STATE + 4'b 0011, // index[21] RV_CORE_IBEX_ERR_STATUS + 4'b 1111, // index[22] RV_CORE_IBEX_RND_DATA + 4'b 0001, // index[23] RV_CORE_IBEX_RND_STATUS + 4'b 1111 // index[24] RV_CORE_IBEX_FPGA_INFO + }; + +endpackage
diff --git a/fpga/ip/rv_core_ibex/rv_core_ibex.core b/fpga/ip/rv_core_ibex/rv_core_ibex.core new file mode 100644 index 0000000..766e12a --- /dev/null +++ b/fpga/ip/rv_core_ibex/rv_core_ibex.core
@@ -0,0 +1,88 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: lowrisc:kelvin_ip:rv_core_ibex:0.1 +description: "Wrapper around ibex with TL-UL ports" +filesets: + files_rtl: + depend: + - lowrisc:ibex:ibex_top + - lowrisc:ip:lc_ctrl_pkg + - lowrisc:ip:otp_ctrl_pkg + - lowrisc:ip:tlul + - lowrisc:prim:all + - lowrisc:prim:clock_gating + - lowrisc:prim:edn_req + - lowrisc:prim:esc + - lowrisc:prim:lc_sync + - lowrisc:prim:lc_sender + - lowrisc:prim:mubi + - lowrisc:tlul:adapter_host + - lowrisc:ip:rv_core_ibex_pkg + + files: + - rtl/rv_core_ibex_reg_pkg.sv + - rtl/rv_core_ibex_cfg_reg_top.sv + - rtl/rv_core_ibex_addr_trans.sv + - rtl/rv_core_ibex.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/rv_core_ibex.vlt + file_type: vlt + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/rv_core_ibex.waiver + file_type: waiver + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + files: + - lint/rv_core_ibex.vbl + file_type: waiver + +parameters: + SYNTHESIS: + datatype: bool + paramtype: vlogdefine + + +targets: + default: &default_target + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl + toplevel: rv_core_ibex + + lint: + <<: *default_target + default_tool: verilator + parameters: + - SYNTHESIS=true + tools: + verilator: + mode: lint-only + verilator_options: + - "-Wall" + + syn: + <<: *default_target + # TODO: set default to DC once + # this option is available + # olofk/edalize#89 + default_tool: icarus + parameters: + - SYNTHESIS=true
diff --git a/fpga/ip/rv_core_ibex/syn/constraints.sdc b/fpga/ip/rv_core_ibex/syn/constraints.sdc new file mode 100644 index 0000000..0b119da --- /dev/null +++ b/fpga/ip/rv_core_ibex/syn/constraints.sdc
@@ -0,0 +1,50 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Generic constraints file for simple testsynthesis flow + +# note that we do not fix hold timing in this flow +set SETUP_CLOCK_UNCERTAINTY 0.5 + +##################### +# main clock # +##################### +set MAIN_CLK_PIN clk_i +set MAIN_RST_PIN rst_ni +# set main clock to 125 MHz +set MAIN_TCK 8.0 +set_ideal_network ${MAIN_CLK_PIN} +set_ideal_network ${MAIN_RST_PIN} +set_clock_uncertainty ${SETUP_CLOCK_UNCERTAINTY} ${MAIN_CLK_PIN} + +# other timing constraint in ns +set IN_DEL 1.0 +set OUT_DEL 1.0 +set DELAY ${MAIN_TCK} + +create_clock ${MAIN_CLK_PIN} -period ${MAIN_TCK} + +# in to out +set_max_delay ${DELAY} -from [all_inputs] -to [all_outputs] +# in to reg / reg to out +set_input_delay ${IN_DEL} [remove_from_collection [all_inputs] {${MAIN_CLK_PIN}}] -clock ${MAIN_CLK_PIN} +set_output_delay ${OUT_DEL} [all_outputs] -clock ${MAIN_CLK_PIN} + +##################### +# I/O drive/load # +##################### + +# attach load and drivers to IOs to get a more realistic estimate +set_driving_cell -no_design_rule -lib_cell ${DRIVING_CELL} -pin ${DRIVING_CELL_PIN} [all_inputs] +set_load [load_of ${LOAD_CELL_LIB}/${LOAD_CELL}/${LOAD_CELL_PIN}] [all_outputs] + +# set a nonzero critical range to be able to spot the violating paths better +# in the report +set_critical_range 0.5 ${DUT} + +##################### +# Size Only Cells # +##################### + +set_size_only -all_instances [get_cells -h *u_size_only*] true
diff --git a/fpga/ip/rv_core_ibex/syn/post_elab_gtech.tcl b/fpga/ip/rv_core_ibex/syn/post_elab_gtech.tcl new file mode 100644 index 0000000..abe1a8c --- /dev/null +++ b/fpga/ip/rv_core_ibex/syn/post_elab_gtech.tcl
@@ -0,0 +1,9 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Post elab script, used in GTECH runs to modify the unmapped netlist before +# writing it out. + +# Remove generic views of ram macros +remove_design prim_generic_ram_1p_Width*
diff --git a/fpga/ip/rv_core_ibex/syn/rv_core_ibex_gtech_syn_cfg.hjson b/fpga/ip/rv_core_ibex/syn/rv_core_ibex_gtech_syn_cfg.hjson new file mode 100644 index 0000000..39fedce --- /dev/null +++ b/fpga/ip/rv_core_ibex/syn/rv_core_ibex_gtech_syn_cfg.hjson
@@ -0,0 +1,20 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + // Top level dut name (sv module). + name: rv_core_ibex + + // Fusesoc core file used for building the file list. + fusesoc_core: lowrisc:kelvin_ip:rv_core_ibex:0.1 + + import_cfgs: [// Project wide common GTECH synthesis config file + "{proj_root}/hw/syn/tools/dvsim/common_gtech_syn_cfg.hjson"] + + overrides: [ + { // Deletes black-boxed hierarchies before writing out the unmapped netlist + name: post_elab_script + value: "{proj_root}/hw/ip/{name}/syn/post_elab_gtech.tcl" + } + ] +}
diff --git a/fpga/ip/rv_core_ibex/syn/rv_core_ibex_syn_cfg.hjson b/fpga/ip/rv_core_ibex/syn/rv_core_ibex_syn_cfg.hjson new file mode 100644 index 0000000..70ddca4 --- /dev/null +++ b/fpga/ip/rv_core_ibex/syn/rv_core_ibex_syn_cfg.hjson
@@ -0,0 +1,19 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + // Top level dut name (sv module). + name: rv_core_ibex + + // Fusesoc core file used for building the file list. + fusesoc_core: lowrisc:kelvin_ip:rv_core_ibex:0.1 + + import_cfgs: [// Project wide common synthesis config file + "{proj_root}/hw/syn/tools/dvsim/common_syn_cfg.hjson"] + + // Timing constraints for this module + sdc_file: "{proj_root}/hw/ip/{name}/syn/constraints.sdc" + + // This is not needed for this module + foundry_sdc_file: "" +}