Interrupts
SMC external interrupts pass through the Platform-Level Interrupt Controller (PLIC). CLINT supplies per-core timer and software interrupts. Each bus error unit (BEU) has both a direct core output and a separately selected PLIC output. This chapter distinguishes raw SMC vector bits from software-visible PLIC IDs.
1. Controllers
1.1. Controller Addresses
These addresses use the SMC-local view. N ranges from 0 through 3 for the per-core watchdog and BEU apertures.
| Block | Base Addr | Size | Interface |
|---|---|---|---|
CPU Control Regs |
0xC003_9000 |
4 KB |
AXI4-Lite |
PLIC |
0xC400_0000 |
64 MB |
TileLink (cluster control bus) |
CLINT |
0xC800_0000 |
64 KB |
TileLink (cluster control bus) |
Watchdog Timers (N) |
0xC000_0000 + (N * 0x400) |
1 KB x4 |
TileLink (cluster peripheral bus) |
Bus Error Units (N) |
0xC801_0000 + (N * 0x1000) |
4 KB x4 |
TileLink (cluster control bus) |
1.2. PLIC Sources and Contexts
The four-core implementation has 336 PLIC inputs with source IDs 1–336. ID 0 means no interrupt. The inputs comprise:
| Input group | PLIC IDs | Origin |
|---|---|---|
Raw SMC vector bits 0–327 |
1–328 |
|
Cluster watchdogs 0–3 |
329–332 |
Added by the cluster interrupt crossbar. |
Core BEU PLIC outputs 0–3 |
333–336 |
Added within the PLIC clock domain. |
Reserved raw-vector positions remain reserved PLIC IDs. The 256 external input meanings come from the enclosing SoC integration; an input count is not a promise that every position is an active source.
There are eight delivery contexts: machine contexts for cores 0–3, then supervisor contexts for cores 0–3. Priorities are shared per source; enable masks, thresholds and claim/complete registers are per context. A priority must exceed the context threshold to raise its external-interrupt output. Priority zero suppresses a source. See the generated map for context offsets and priority range. These settings route interrupts; they do not themselves enforce MMIO access policy.
The gateways are active-high and level-sensitive, with no selectable edge mode.
External SMC pins pass through prim_sync3 before the raw vector. A short pulse
can be missed if it is not sampled; stretch it or hold the request until serviced.
A gateway admits one request and waits for completion before accepting another.
It does not count repeated pulses while one request is in flight.
1.3. CLINT
CLINT provides a shared 64-bit timer, per-core compare registers and per-core software-interrupt state. Timer and software interrupts go directly to the cores rather than through PLIC claim/complete. The timer advances on the cluster’s periodic tick; see the Clocks and Resets chapter for its clock relationship.
1.4. Bus Error Units
A Bus Error Unit (BEU) accumulates error events for one core. The register
named ACCRUED_ENABLE is sticky status, not an enable mask: events set its bits
independently of ENABLE. Ordinary writes replace those bits; write zero to
clear them. ENABLE instead gates capture of the first error’s CAUSE and
PHYS_ADDR while CAUSE is zero. Software can also write PHYS_ADDR.
LOCAL_ENABLE selects accrued errors for direct delivery to the core, bypassing
the PLIC and the ordinary per-source mie bits. This is not an unconditionally
non-maskable interrupt: in machine mode, mstatus.MIE = 0 suppresses delivery.
The machine interrupt is enabled while executing in lower privilege modes.
The BEU also has a separate output selected by PLIC_ENABLE. The
Bus Error Unit service sequence
is in the Programmer’s Guide.
2. Sources and Routing
2.1. Raw Vector and PLIC Numbering
Raw bit N maps to PLIC source ID N+1. For example, DMA completion is raw bit 322 and PLIC ID 323. Watchdog IDs 329–332 and BEU IDs 333–336 are not additional bits on the 328-bit raw SMC vector.
2.2. SMC CPU Interrupt Vector Map
This section documents the raw cpu_interrupts_o vector assembled in
hw/sys/smc/rtl/smc_base.sv. The vector is built from four sources:
-
smc_ext_interrupts_i -
peripheral_interrupts_i[31:0] -
mailbox_interrupts[31:0] -
four internal interrupt signals
Unless otherwise noted, the bit numbers below are raw cpu_interrupts_o
bit indices, not PLIC source IDs. When these signals feed the PLIC, the
PLIC source ID is cpu_interrupts_o bit index + 1.
The vector layout is:
cpu_interrupts_o[NumExtInterrupts-1:0] = ext_interrupts_smc_clk; // smc_ext_interrupts_i after 3-stage sync to clk_smc
cpu_interrupts_o[NumExtInterrupts+:32] = peripheral_interrupts_i;
cpu_interrupts_o[(NumExtInterrupts+32)+:32] = mailbox_interrupts;
cpu_interrupts_o[(NumExtInterrupts+64)] = tdr_dbg_ctrl_clocks_stopped_by_cla_o;
cpu_interrupts_o[(NumExtInterrupts+64)+1] = cla_interrupt;
cpu_interrupts_o[(NumExtInterrupts+64)+2] = dma_intp;
cpu_interrupts_o[(NumExtInterrupts+64)+3] = zeroer_intp;
NumExtInterrupts = 256 and NumCpuInterrupts = 328.
2.2.1. Exact Indexed Map
Table 3 shows the exact raw cpu_interrupts_o indexing. The
Source column is intentionally human-readable; implementation signal
names are called out in the RTL trace column instead.
| Bit(s) | Source | Description | RTL trace |
|---|---|---|---|
|
External interrupts |
Integration-defined external interrupt inputs |
|
|
SEP mailbox interrupt 0 |
SEP-to-SMC mailbox channel 0 interrupt |
|
|
SEP mailbox interrupt 1 |
SEP-to-SMC mailbox channel 1 interrupt |
|
|
SEP mailbox interrupt 2 |
SEP-to-SMC mailbox channel 2 interrupt |
|
|
SEP mailbox interrupt 3 |
SEP-to-SMC mailbox channel 3 interrupt |
|
|
SEP mailbox interrupt 4 |
SEP-to-SMC mailbox channel 4 interrupt |
|
|
SEP mailbox interrupt 5 |
SEP-to-SMC mailbox channel 5 interrupt |
|
|
SEP mailbox interrupt 6 |
SEP-to-SMC mailbox channel 6 interrupt |
|
|
SEP mailbox interrupt 7 |
SEP-to-SMC mailbox channel 7 interrupt |
|
|
Telemetry interrupt 0 |
Telemetry receiver instance 0 interrupt |
|
|
Telemetry interrupt 1 |
Telemetry receiver instance 1 interrupt |
|
|
Telemetry interrupt 2 |
Telemetry receiver instance 2 interrupt |
|
|
NDM Reset Request |
OR-reduced synchronized NDM reset request interrupt |
|
|
I3C interrupt 0 |
I3C controller instance 0 interrupt |
|
|
I3C interrupt 1 |
I3C controller instance 1 interrupt |
|
|
I3C interrupt 2 |
I3C controller instance 2 interrupt |
|
|
I3C interrupt 3 |
I3C controller instance 3 interrupt |
|
|
I3C interrupt 4 |
I3C controller instance 4 interrupt |
|
|
I3C interrupt 5 |
I3C controller instance 5 interrupt |
|
|
UART/Log Engine interrupt 0 |
Combined UART IRQ, UART error, and log-engine interrupt for instance 0 |
|
|
UART/Log Engine interrupt 1 |
Combined UART IRQ, UART error, and log-engine interrupt for instance 1 |
|
|
UART/Log Engine interrupt 2 |
Combined UART IRQ, UART error, and log-engine interrupt for instance 2 |
|
|
UART/Log Engine interrupt 3 |
Combined UART IRQ, UART error, and log-engine interrupt for instance 3 |
|
|
AVSBus interrupt |
Adaptive voltage scaling interrupt |
|
|
I2C interrupt 0 |
I2C controller instance 0 interrupt |
|
|
I2C interrupt 1 |
I2C controller instance 1 interrupt |
|
|
I2C interrupt 2 |
I2C controller instance 2 interrupt |
|
|
SEP watchdog reset |
External watchdog reset indication from SEP path |
|
|
Locked field access |
eFuse locked-field access violation interrupt |
|
|
GPIO interrupt OR, lower half |
OR-reduction across GPIO interrupt sources 0-31 |
|
|
GPIO interrupt OR, upper half |
OR-reduction across GPIO interrupt sources 32-64 |
|
|
AXI hang detector OR |
OR of the three AXI hang detectors (sys_axi, sep_axi, data_accel). Asserts
while any detector’s |
|
|
Reserved |
Unused peripheral interrupt slots; tied to zero |
|
|
SMC mailbox interrupts |
Inbound SMC mailbox interrupt channels 31:0 |
|
|
CLA Clock Stop |
DFD CLA clock-stop status interrupt |
|
|
CLA Interrupt |
DFD CLA interrupt |
|
|
DMA transfer complete |
Falling-edge pulse when DMA busy deasserts |
|
|
Zeroer transfer complete |
Falling-edge pulse when Zeroer busy deasserts |
|
|
Reserved |
Unused tail bits; tied to zero |
|
2.2.2. Routing Notes
smc_base.sv assembles the raw vector; smc_peripherals.sv assembles its
32-bit peripheral slice. The AXI hang-detector OR enters peripheral bit 30
(raw bit 286), while bit 31 is reserved. The table preserves the individual
sources behind combined GPIO, UART/log-engine and hang-detector indications;
software must inspect their local status to identify and service the cause.
The six I3C entries are connected through the peripheral CDC block. The AVSBus and external-watchdog indications are also synchronized into the SMC domain. Do not infer pulse-capture guarantees merely from the presence of a synchronizer. DMA and zeroer completion indications are busy-falling pulses, not counted queues.
3. Software Handling
The PLIC priority, enable and threshold registers are not reset by hardware. A source’s priority is shared by every context that enables it. Completion releases the source’s gateway, so a still-asserted source pends again; claim and complete do not clear a peripheral’s own sticky status. CLINT timer and software interrupts do not use PLIC completion.
The Interrupt Control section of the Programmer’s Guide gives the PLIC initialization and claim/complete sequence, CLINT timer and software interrupt service, and Bus Error Unit service. Watchdog recovery and CPU reset/isolation ordering are described in the Watchdog Timers and CPU chapters. For CPU cluster context, see CPU and Memory System.
4. Memory Map and Register Reference
4.1. Memory Map
Register offsets are relative to the block base in the subsystem memory map. The detailed map below defines each register and its fields.
4.2. Detailed Register Map
PLIC Address Map
Platform-Level Interrupt Controller register interface.
Register Arrays:
- PRIORITY[337]: 337 registers, base 0x0, stride 0x4
- PENDING[11]: 11 registers, base 0x1000, stride 0x4
- CORE0_MEIP_ENABLE[11]: 11 registers, base 0x2000, stride 0x4
- CORE1_MEIP_ENABLE[11]: 11 registers, base 0x2080, stride 0x4
- CORE2_MEIP_ENABLE[11]: 11 registers, base 0x2100, stride 0x4
- CORE3_MEIP_ENABLE[11]: 11 registers, base 0x2180, stride 0x4
- CORE0_SEIP_ENABLE[11]: 11 registers, base 0x2200, stride 0x4
- CORE1_SEIP_ENABLE[11]: 11 registers, base 0x2280, stride 0x4
- CORE2_SEIP_ENABLE[11]: 11 registers, base 0x2300, stride 0x4
- CORE3_SEIP_ENABLE[11]: 11 registers, base 0x2380, stride 0x4
Register List:
| Address | Name | Access | Description |
|---|---|---|---|
| 0x0 - 0x540 | PRIORITY[337] | RW | - |
| 0x1000 - 0x1028 | PENDING[11] | R | - |
| 0x2000 - 0x2028 | CORE0_MEIP_ENABLE[11] | RW | - |
| 0x2080 - 0x20A8 | CORE1_MEIP_ENABLE[11] | RW | - |
| 0x2100 - 0x2128 | CORE2_MEIP_ENABLE[11] | RW | - |
| 0x2180 - 0x21A8 | CORE3_MEIP_ENABLE[11] | RW | - |
| 0x2200 - 0x2228 | CORE0_SEIP_ENABLE[11] | RW | - |
| 0x2280 - 0x22A8 | CORE1_SEIP_ENABLE[11] | RW | - |
| 0x2300 - 0x2328 | CORE2_SEIP_ENABLE[11] | RW | - |
| 0x2380 - 0x23A8 | CORE3_SEIP_ENABLE[11] | RW | - |
| 0x200000 | CORE0_MEIP_THRESHOLD | RW | - |
| 0x200004 | CORE0_MEIP_CLAIM_COMPLETE | RW | - |
| 0x201000 | CORE1_MEIP_THRESHOLD | RW | - |
| 0x201004 | CORE1_MEIP_CLAIM_COMPLETE | RW | - |
| 0x202000 | CORE2_MEIP_THRESHOLD | RW | - |
| 0x202004 | CORE2_MEIP_CLAIM_COMPLETE | RW | - |
| 0x203000 | CORE3_MEIP_THRESHOLD | RW | - |
| 0x203004 | CORE3_MEIP_CLAIM_COMPLETE | RW | - |
| 0x204000 | CORE0_SEIP_THRESHOLD | RW | - |
| 0x204004 | CORE0_SEIP_CLAIM_COMPLETE | RW | - |
| 0x205000 | CORE1_SEIP_THRESHOLD | RW | - |
| 0x205004 | CORE1_SEIP_CLAIM_COMPLETE | RW | - |
| 0x206000 | CORE2_SEIP_THRESHOLD | RW | - |
| 0x206004 | CORE2_SEIP_CLAIM_COMPLETE | RW | - |
| 0x207000 | CORE3_SEIP_THRESHOLD | RW | - |
| 0x207004 | CORE3_SEIP_CLAIM_COMPLETE | RW | - |
Register Details:
PRIORITY[337]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Priority of interrupt. The higher the set value, the higher the priority. For interrupts with the same priority, the tie is broken by interrupt ID; interrupts with the lowest ID has highest effective priority. Interrupts start counting at 1. |
PENDING[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | R | 0x0 | Set to 1 if interrupt source 1 is pending, regardless of its enable or priority setting. Interrupts start counting at 1. |
CORE0_MEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE1_MEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE2_MEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE3_MEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE0_SEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE1_SEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE2_SEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE3_SEIP_ENABLE[11]
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Set bits to 1 if interrupt should be enabled. Interrupts start counting at 1. |
CORE0_MEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE0_MEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |
CORE1_MEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE1_MEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |
CORE2_MEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE2_MEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |
CORE3_MEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE3_MEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |
CORE0_SEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE0_SEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |
CORE1_SEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE1_SEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |
CORE2_SEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE2_SEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |
CORE3_SEIP_THRESHOLD
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:3 | Reserved | - | - | Reserved |
| 2:0 | value | RW | - | Interrupt notification threshold. Maximum value is 7. The context's external interrupt is raised only while the highest-priority pending, enabled source has a priority strictly greater than the threshold. The threshold does not gate claims: a claim read returns the highest-priority pending, enabled source regardless of the threshold. |
CORE3_SEIP_CLAIM_COMPLETE
| Bits | Field | Access | Reset | Description |
|---|---|---|---|---|
| 31:0 | value | RW | - | Claim/Complete register. Reading this register returns the claimed interrupt number and makes it no longer pending. Writing the interrupt number back completes the interrupt. |