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):
+![](https://dashboards.lowrisc.org/badges/dv/ibex/opentitan/test.svg)
+![](https://dashboards.lowrisc.org/badges/dv/ibex/opentitan/passing.svg)
+![](https://dashboards.lowrisc.org/badges/dv/ibex/opentitan/functional.svg)
+![](https://dashboards.lowrisc.org/badges/dv/ibex/opentitan/code.svg)
+
+# 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] = ~&region_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: ""
+}