| # Ibex RISC-V Core Wrapper Technical Specification |
| |
| # 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). |
| |
| # Theory of Operations |
| |
| ## 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`](data/rv_core_ibex.hjson#ibus_addr_matching_0) and [`IBUS_REMAP_ADDR_0`](data/rv_core_ibex.hjson#ibus_remap_addr_0). |
| |
| ### 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)](../edn/README.md) with a register based interface. |
| The [`RND_DATA`](data/rv_core_ibex.hjson#rnd_data) register provides 32-bits directly from the EDN. |
| [`RND_STATUS.RND_DATA_VALID`](data/rv_core_ibex.hjson#rnd_status) indicates if the data in [`RND_DATA`](data/rv_core_ibex.hjson#rnd_data) is valid or not. |
| A polling style interface is used to get new random data. |
| Any read to [`RND_DATA`](data/rv_core_ibex.hjson#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`](data/rv_core_ibex.hjson#rnd_status) until it is valid and then read from [`RND_DATA`](data/rv_core_ibex.hjson#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`](data/rv_core_ibex.hjson#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`](data/rv_core_ibex.hjson#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`](data/rv_core_ibex.hjson#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. |
| |
| ## Hardware Interfaces |
| |
| ### Signals |
| |
| * [Interface Tables](data/rv_core_ibex.hjson#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::pwr_cpu_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. |
| |
| ## Device Interface Functions (DIFs) |
| |
| - [Device Interface Functions](../../../sw/device/lib/dif/dif_rv_core_ibex.h) |
| |
| ## Register Table |
| |
| A number of memory-mapped registers are available to control Ibex-related functionality that's specific to OpenTitan. |
| |
| * [Register Table](data/rv_core_ibex.hjson#registers) |