Interrupts
1. Controllers
The SEP integrates a VeeR EL2 core with a built-in
Programmable Interrupt Controller (PIC). All maskable external interrupt
sources feed a single extintsrc_req bus; the memory-mapped meipl, meie,
and meigwctrl registers configure priority, enable, and gateway polarity per
source.
The PIC base address is 0xC008_0000; its register layout is described in the
Register Interfaces section below.
2. Sources and Routing
The vector driven to the core, sep_internal_interrupts, is indexed from 0.
Bit i of that vector is PIC source i + 1. The core’s extintsrc_req port
is numbered from 1, and the core ties source 0 to zero, so the low bit of the
driven vector is the first programmable source. The comment directly above
NUM_INTERNAL_IRQS in sep_pkg.sv numbers sources by that vector index, one
less than the PIC source in Table 1.
2.1. SEP CPU Interrupt Vector Map
The PIC supports 255 external sources. Slots 1–43 are individually assigned to specific peripherals and subsystems connected to the SEP, including both SEP-internal blocks (crypto engines, DMA, entropy) and cross-block sources (SMC mailboxes, SPI). Slots 44–255 are reserved for chip-level external inputs passed in at the SEP block boundary.
Table 1 lists the assigned PIC sources and the range reserved for chip-level inputs.
| PIC source | Source | Description |
|---|---|---|
|
Mailbox interrupt 0 |
SMC-to-SEP mailbox channel 0 interrupt |
|
Mailbox interrupt 1 |
SMC-to-SEP mailbox channel 1 interrupt |
|
Mailbox interrupt 2 |
SMC-to-SEP mailbox channel 2 interrupt |
|
Mailbox interrupt 3 |
SMC-to-SEP mailbox channel 3 interrupt |
|
Mailbox interrupt 4 |
SMC-to-SEP mailbox channel 4 interrupt |
|
Mailbox interrupt 5 |
SMC-to-SEP mailbox channel 5 interrupt |
|
Mailbox interrupt 6 |
SMC-to-SEP mailbox channel 6 interrupt |
|
Mailbox interrupt 7 |
SMC-to-SEP mailbox channel 7 interrupt |
|
DMA transfer done |
Secure DMA full-transfer-complete interrupt |
|
DMA chunk done |
Secure DMA chunk-transfer-complete interrupt |
|
DMA error |
Secure DMA error interrupt |
|
DMA alert |
Secure DMA aggregated alert (fault) |
|
WDT alert |
Watchdog timer aggregated alert. Note: the WDT bark goes to the NMI pin, not here; see Section 2.2. |
|
SPI IRQ |
SPI host controller interrupt |
|
KM mailbox IRQ |
Key Manager-to-SEP mailbox interrupt |
|
Entropy source IRQ |
OpenTitan entropy source interrupt |
|
External TRNG IRQ |
External TRNG interrupt; driven to zero in the current OSS integration |
|
HMAC done |
HMAC operation complete interrupt |
|
HMAC FIFO empty |
HMAC message FIFO empty interrupt |
|
HMAC error |
HMAC error interrupt |
|
KMAC done |
KMAC operation complete interrupt |
|
KMAC FIFO empty |
KMAC message FIFO empty interrupt |
|
KMAC error |
KMAC error interrupt |
|
CSRNG command request done |
CSRNG command request complete interrupt |
|
CSRNG entropy request |
CSRNG entropy request interrupt |
|
CSRNG HW instance exception |
CSRNG hardware instance exception interrupt |
|
CSRNG fatal error |
CSRNG fatal error interrupt |
|
EDN command request done |
Entropy Distribution Network command request complete interrupt |
|
EDN fatal error |
Entropy Distribution Network fatal error interrupt |
|
OTBN done |
OpenTitan Big Number Accelerator operation complete interrupt |
|
KM unrecoverable error |
Key Manager unrecoverable error interrupt; also exported as a SEP output port |
|
KM recoverable error |
Key Manager recoverable error interrupt; also exported as a SEP output port |
|
Crypto alert |
Combined OpenTitan crypto alert. SEP has no |
|
Locked field access |
eFuse locked-field access violation interrupt |
|
Adams Bridge error |
Adams Bridge (post-quantum accelerator) error interrupt |
|
Adams Bridge notification |
Adams Bridge (post-quantum accelerator) operation notification interrupt |
|
Entropy pool low |
Entropy pool FIFO low-water condition (informational: pool draining faster than filling) |
|
Entropy pool fill stall |
Entropy pool FIFO fill-path stall (fault: EDN not making progress) |
|
Entropy pool pointer fault |
Entropy pool FIFO read/write pointer integrity fault (fault). The pool’s
pointer-integrity check is not built in the current configuration, so this
source is tied to zero and never asserts; the slot is assigned anyway so that
enabling the check later does not renumber the map. When live it is
level-sensitive and holds until a |
|
Token match fault |
eFuse token comparator redundancy fault (fault). The OR of the three sticky
|
|
DMA register-path bus error |
A CPU access to a Secure DMA register returned a TL-UL error response
(unmapped or misaligned offset). The faulting access also
received SLVERR synchronously. Latched and held until firmware writes
|
|
DMA host-path integrity/bus fault |
Either the fabric returned a non-OKAY AXI response to a DMA transfer, or a
TL-UL command-integrity check failed on a command issued by the DMA. The
integrity case is a fault-detection event with no other reporting path.
Cleared by the same |
|
Peripheral register-bridge fault |
The OR of the per-block register-bridge error bits for AES, HMAC, KMAC, OTBN,
CSRNG, EDN and the watchdog timer. |
|
Reserved (external band) |
Chip-level external interrupt inputs |
2.2. Non-PIC Interrupt Paths
Three CPU interrupt pins bypass the EL2 PIC entirely. The core also reports its own memory errors through a path that is neither a pin nor a PIC source; see Section 2.2.3.
2.2.1. NMI — Watchdog Timer Bark
The VeeR EL2 nmi_int pin is wired to the watchdog timer bark signal from
sep_wdt_wrap. When the bark fires, the CPU jumps to the NMI vector address
held in the SEP_NMI_VEC register. The SEP_NMI_VEC_LOCK register prevents
runtime modification of the vector once locked.
The NMI is non-maskable: it cannot be suppressed by mstatus.MIE or any PIC
configuration register.
2.2.2. Timer and Software Interrupts
The timer_int and soft_int pins of the VeeR EL2 core are tied to zero at
the SMU integration boundary. There is no external CLINT-style delivery path.
The external pins drive mip.MTIP and mip.MSIP, respectively, so these
pending bits remain inactive in this integration.
The two internal timers instead report mip.MITIP0 (bit 29) and
mip.MITIP1 (bit 28). Enable them through mie.MITIE0 and mie.MITIE1
at the corresponding bit positions, together with mstatus.MIE. Their
interrupt cause codes are 0x1D and 0x1C, respectively (with the interrupt
bit set in mcause). Enabling mie.MTIE or mie.MSIE does not enable the
internal timers.
2.2.3. Memory ECC Errors
The ICCM and DCCM are SECDED-protected. Neither reaches the PIC: the core reports these errors itself, correctable ones as a local interrupt and uncorrectable ones as a synchronous trap. No PIC register affects either, and there is no PIC source to enable or mask.
The SEP core is configured without an I-cache, so the I-cache parity counter
MICECT (0x7F0) never increments. Only the two tightly-coupled-memory
counters below are live.
2.2.3.1. Correctable (single-bit) errors
Hardware corrects the data and the access is retried, so no data is lost and no trap is taken. Each protected memory has a counter CSR (Table 2).
| CSR | Address | Counts |
|---|---|---|
|
|
ICCM single-bit corrections |
|
|
DCCM single-bit corrections |
Bits [26:0] are the running count. Bits [31:27] hold a threshold exponent:
the counter raises a request once the count reaches 2threshold. A written
threshold above 26 is clamped to 26. The requests from both counters are ORed
into mip[30] (MCEIP) and delivered when mie[30] (MCEIE) and
mstatus.MIE are both set, with mcause = 0x8000_001E.
Counters and thresholds reset to zero, so a zero threshold raises the request
on the first corrected error. mie[30] is clear at reset, and until it is set
corrected errors are counted silently. MCEIP follows the threshold comparator
and has no write-one-to-clear: it stays asserted until the count drops below the
threshold. The
memory error handling section
of the Programmer’s Guide gives the enable and service sequence.
2.2.3.2. Uncorrectable (double-bit) errors
These cannot be masked and have no enable bit. The access returned no valid data, so the core traps on the instruction that hit the error (Table 3).
| Access | mcause |
Trap |
|---|---|---|
Instruction fetch from ICCM |
|
Instruction access fault |
Load from DCCM |
|
Load access fault |
Store to DCCM |
|
Store access fault |
DCCM access on the fast-interrupt path |
|
NMI, taken through |
mcause alone does not identify these as memory failures — a bad pointer and a
failing SRAM both raise a load access fault. mscause (0x7FF) is what
separates them: on an access fault, mscause = 1 means uncorrectable ECC.
A handler that does not read mscause cannot distinguish a software bug from
failing hardware.
The faulting access cannot be completed, and retrying it re-reads the same corrupted location.
An uncorrectable error on an externally initiated (DMA) access to either memory is not a CPU trap at all. It is returned as an error response on that transaction, and the initiator is responsible for reporting it.
2.2.3.3. Debug bus mirror
The ICCM and DCCM single- and double-bit error signals are also mirrored onto
ext_debug_bus_o[367:364], most significant first: ICCM single, ICCM double,
DCCM single, DCCM double. These are single-cycle pulses with no latch and no
handshake, provided for external trace and bring-up observability. They are not
a delivery path, so software must not rely on sampling them; use the CSRs above.
3. Software Handling
Interrupt source IDs are 1-based inside the PIC. Source 0 is permanently
tied to zero inside the core. Firmware programs source N through the
per-source arrays, each indexed at an offset of N * 4 from its region base:
meipl at PIC base +0x0000, meie at +0x2000, meigwctrl at +0x4000
and meigwclr at +0x5000. Pending status is the exception — meip at
+0x1000 is a bitmap rather than a per-source array, so source N is bit
N % 32 of meip[N / 32].
Each per-source array carries an entry 0, so that the array index is the source
ID and no off-by-one applies: meipl[7] is source 7. That entry is reserved and
has no hardware behind it — the PIC decodes the address but ties the register
off, so +0x0000, +0x2000, +0x4000 and +0x5000 read as zero and discard
writes. It appears in the RDL, the generated headers and the UVM RAL only to
preserve the indexing. The
PIC section
of the Programmer’s Guide gives the programming and per-source service
rules.
Register tests that walk the whole PIC map must skip index 0 of meipl,
meie, meigwctrl and meigwclr. The register model declares those entries
read-write like every other element, but the hardware treats them as reserved,
so a read-write check on them fails.
|
4. Memory Map and Register Reference
4.1. Memory Map
The EL2 PIC register block (meipl, meie, meigwctrl, meigwclr, and
related registers) is documented in the register reference below.
The per-source arrays in that table are listed from index 0. Index 0 is the reserved entry described in Interrupts: it exists so the array index equals the interrupt source ID, and the first programmable source is index 1.
4.2. Detailed Register Map
EL2_PIC
VeeR EL2 Programmable Interrupt Controller (PIC) memory-mapped registers.
Supports up to PIC_TOTAL_INT external interrupt sources with 15 priority levels.
Register Arrays:
- meipl[256]: 256 registers, base 0x0, stride 0x4
- meip[8]: 8 registers, base 0x1000, stride 0x4
- meie[256]: 256 registers, base 0x2000, stride 0x4
- meigwctrl[256]: 256 registers, base 0x4000, stride 0x4
- meigwclr[256]: 256 registers, base 0x5000, stride 0x4
Register List:
| Address | Name | Access | Description |
|---|---|---|---|
| 0x0 - 0x3FC | meipl[256] | RW | External Interrupt Priority Level Register. Sets the priority level for an interrupt source. |
| 0x1000 - 0x101C | meip[8] | R | External Interrupt Pending Register. Reports pending status of up to 32 interrupt sources. |
| 0x2000 - 0x23FC | meie[256] | RW | External Interrupt Enable Register. Controls interrupt enable for a single source. |
| 0x3000 | mpiccfg | RW | PIC Configuration Register. Used to select the operational parameters of the PIC. |
| 0x4000 - 0x43FC | meigwctrl[256] | RW | External Interrupt Gateway Configuration Register. Controls interrupt type and polarity. |
| 0x5000 - 0x53FC | meigwclr[256] | W | External Interrupt Gateway Clear Register. Writing any value clears the gateway's interrupt pending (IP) bit for edge-triggered interrupts. |
Register Details:
meipl[256]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:4 | Reserved | - | - | Reserved |
| 3:0 | intpriority | RW | 0x0 | External interrupt priority level: RISC-V standard order: 0=Never interrupt, 1..15=Priority (1 lowest, 15 highest) Reverse order: 15=Never interrupt, 14..0=Priority (14 lowest, 0 highest) |
meip[8]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | intpend | R | 0x0 | External interrupt pending bits. Bit Y indicates pending status for source X*32+Y. 0: Interrupt not pending 1: Interrupt pending |
meie[256]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:1 | Reserved | - | - | Reserved |
| 0 | inten | RW | 0x0 | External interrupt enable: 0: Interrupt disabled 1: Interrupt enabled |
mpiccfg
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:1 | Reserved | - | - | Reserved |
| 0 | priord | RW | 0x0 | Priority order: 0: RISC-V standard compliant priority order (0=lowest to 15=highest) 1: Reverse priority order (15=lowest to 0=highest) |
meigwctrl[256]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:2 | Reserved | - | - | Reserved |
| 1 | irq_type | RW | 0x0 | External interrupt type: 0: Level-triggered interrupt 1: Edge-triggered interrupt |
| 0 | polarity | RW | 0x0 | External interrupt polarity: 0: Active-high interrupt 1: Active-low interrupt |
meigwclr[256]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:1 | Reserved | - | - | Reserved |
| 0 | clear | W | 0x0 | Write any value to clear the interrupt pending bit in the gateway. This register is write-only; reads return 0. |