Exceptions and Interrupts
CV32E40X supports one of two interrupt architectures.
If the CLIC
parameter is set to 0, then the CLINT mode interrupt architecture is supported (see CLINT Mode Interrupt Architecture).
If the CLIC
parameter is set to 1, then the CLIC mode interrupt architecture is supported (see CLIC Mode Interrupt Architecture).
CLINT and CLIC offer different trade offs with respect to cost, interrupt latency and interrupt flexibility. If more than 19 interrupts are required, if programmable interrupt levels are required or if hardware support for preemption is important, then CLIC should be chosen.
Exceptions
CV32E40X can trigger the following exceptions as reported in mcause
:
Interrupt |
Exception Code |
Description |
Scenario(s) |
0 |
1 |
Instruction access fault |
Execution attempt from I/O region. |
0 |
2 |
Illegal instruction |
|
0 |
3 |
Breakpoint |
Environment break. |
0 |
4 |
Load address misaligned |
Non-naturally aligned Load-Reserved address. |
0 |
5 |
Load access fault |
Non-naturally aligned load access attempt to an I/O region. Modified load access attempt to an I/O region. Load-Reserved attempt to region without atomic support. |
0 |
6 |
Store/AMO address misaligned |
Non-naturally aligned Store-Conditional / AMO address. |
0 |
7 |
Store/AMO access fault |
Non-naturally aligned store access attempt to an I/O region. Modified store access attempt to an I/O region. Store-Conditional or Atomic Memory Operation (AMO) attempt to region without atomic support. |
0 |
11 |
Environment call from M-Mode (ECALL) |
|
0 |
24 |
Instruction bus fault |
|
If an instruction raises multiple exceptions, the priority, from high to low, is as follows:
instruction access fault (1)
instruction bus fault (24)
illegal instruction (2)
environment call from M-Mode (11)
environment break (3)
store/AMO access fault (7)
load access fault (5)
store/AMO address misaligned (6)
load address misaligned (4)
Exceptions in general cannot be disabled and are always active. All exceptions are precise. Whether the PMA will actually cause exceptions depends on its configuration. CV32E40X raises an illegal instruction exception for any instruction in the RISC-V privileged and unprivileged specifications that is explicitly defined as being illegal according to the ISA implemented by the core, as well as for any instruction that is left undefined in these specifications unless the instruction encoding is configured as a custom CV32E40X instruction for specific parameter settings as defined in (see CORE-V Instruction Set Extensions). An instruction bus error leads to a precise instruction interface bus fault if an attempt is made to execute the instruction that has an associated bus error. Similarly an instruction fetch with a failing PMA check only leads to an instruction access exception if an actual execution attempt is made for it.
Note
The address misaligned exceptions (exception codes 4 and 6) are only triggered when Load-Reserved, Store-Conditional or AMO instructions use non-naturally aligned addresses for their data access(es) and the access is not blocked by a higher priority access fault from the PMA (exception codes 5 or 7). Misaligned accesses by non-Atomic instructions are either handled by hardware (no exception) or lead to access faults from the PMA (exception code 5 or 7) as explained in :ref:` misaligned-accesses`.
Non Maskable Interrupts
Non Maskable Interrupts (NMIs) update mepc
, mcause
and mstatus
similar to regular interrupts.
However, as the faults that result in NMIs are imprecise, the contents of mepc
is not guaranteed to point to the instruction after the faulted load or store.
The mintstatus
CSR (which exists only if CLIC
== 1) is not impacted by NMIs.
Note
(Unrecoverable) NMIs and regular interrupts have identical effects on the mstatus
CSR. Specifically mstatus.mie
will get cleared
to 0 when an (unrecoverable) NMI is taken. [RISC-V-PRIV] does not specify the behavior of
mstatus
in response to NMIs, see https://github.com/riscv/riscv-isa-manual/issues/756. If this behavior is
specified at a future date, then we will reconsider our implementation.
NMIs have higher priority than other interrupts for both the CLINT mode interrupt architecture and the CLIC mode interrupt architecture.
If CLIC
== 0, then the NMI vector location is as follows:
Upon an NMI in non-vectored CLINT mode the core jumps to mtvec[31:7], 5’h0, 2’b00} (i.e. index 0).
Upon an NMI in vectored CLINT mode the core jumps to mtvec[31:7], 5’hF, 2’b00} (i.e. index 15).
If CLIC
== 1, then the NMI vector location is as follows:
Upon an NMI in CLIC mode the core jumps to mtvec[31:7], 5’h0, 2’b00} (i.e. index 0).
Note
For NMIs the exception codes in the mcause
CSR do not match the table index as for regular interrupts.
An NMI will occur when a load or store instruction experiences a bus fault. The fault resulting in an NMI is handled in an imprecise manner, meaning that the instruction that causes the fault is allowed to retire and the associated NMI is taken afterwards.
NMIs are never masked by the MIE
bit. NMIs are masked however while in debug mode or while single stepping with STEPIE
= 0 in the dcsr
CSR.
This means that many instructions may retire before the NMI is visible to the core if debugging is taking place. Once the NMI is visible to the core, at most two instructions will retire before the NMI is taken.
If an NMI becomes pending while in debug mode as described above, the NMI will be taken immediately after debug mode has been exited.
In case of bufferable stores, the NMI is allowed to become visible an arbitrary time after the instruction retirement. As for the case with debugging, this can cause several instructions to retire before the NMI becomes visible to the core.
When a data bus fault occurs, the first detected fault will be latched and used for mcause
when the NMI is taken. Any new data bus faults occuring while an NMI is pending will be discarded.
When the NMI handler is entered, new data bus faults may be latched.
While an NMI is pending, DCSR.nmip
will be 1. Note that this CSR is only accessible from debug mode, and is thus not visible for machine mode code.
CLINT Mode Interrupt Architecture
If CLIC
== 0, then CV32E40X supports the CLINT mode interrupt architecture as defined in [RISC-V-PRIV]. In this configuration only the
CLINT mode interrupt handling modes (non-vectored CLINT mode and vectored CLINT mode) can be used. The irq_i[31:16]
interrupts are a custom extension
that can be used with the CLINT mode interrupt architecture.
When entering an interrupt/exception handler, the core sets the mepc
CSR to the current program counter and saves mstatus
.MIE to mstatus
.MPIE.
All exceptions cause the core to jump to the base address of the vector table in the mtvec
CSR.
Interrupts are handled in either non-vectored CLINT mode or vectored CLINT mode depending on the value of mtvec
.MODE. In non-vectored CLINT mode the core
jumps to the base address of the vector table in the mtvec
CSR. In vectored CLINT mode the core jumps to the base address
plus four times the interrupt ID. Upon executing an mret
instruction, the core jumps to the program counter previously saved in the
mepc
CSR and restores mstatus
.MPIE to mstatus
.MIE.
The base address of the vector table must be aligned to 128 bytes and can be programmed
by writing to the mtvec
CSR (see Machine Trap-Vector Base Address (mtvec) - CLIC == 0).
Interrupt Interface
Table 22 describes the interrupt interface used for the CLINT mode interrupt architecture.
Signal |
Direction |
Description |
---|---|---|
|
input |
Active high, level sensistive interrupt inputs. Custom extension. |
|
input |
Reserved. Tie to 0. |
|
input |
Active high, level sensistive interrupt input. Referred to as Machine External Interrupt (MEI), but integrator can assign a different purpose if desired. |
|
input |
Reserved. Tie to 0. |
|
input |
Active high, level sensistive interrupt input. Referred to as Machine Timer Interrupt (MTI), but integrator can assign a different purpose if desired. |
|
input |
Reserved. Tie to 0. |
|
input |
Active high, level sensistive interrupt input. Referred to as Machine Software Interrupt (MSI), but integrator can assign a different purpose if desired. |
|
input |
Reserved. Tie to 0. |
Note
The clic_*_i
pins are ignored in CLINT mode and should be tied to 0.
Interrupts
The irq_i[31:0]
interrupts are controlled via the mstatus
, mie
and mip
CSRs. CV32E40X uses the upper 16 bits of mie
and mip
for custom interrupts (irq_i[31:16]
),
which reflects an intended custom extension in the RISC-V CLINT mode interrupt architecture.
After reset, all interrupts, except for NMIs, are disabled.
To enable any of the irq_i[31:0]
interrupts, both the global interrupt enable (MIE
) bit in the mstatus
CSR and the corresponding individual interrupt enable bit in the mie
CSR need to be set. For more information, see the Control and Status Registers (CSRs) documentation.
If multiple interrupts are pending, they are handled in the fixed priority order defined by [RISC-V-PRIV]. The highest priority is given to the interrupt with the highest ID, except for the Machine Timer Interrupt, which has the lowest priority. So from high to low priority the interrupts are ordered as follows:
store bus fault NMI (1025)
load bus fault NMI (1024)
irq_i[31]
irq_i[30]
…
irq_i[16]
irq_i[11]
irq_i[3]
irq_i[7]
The irq_i[31:0]
interrupt lines are level-sensitive. The NMIs are triggered by load/store bus fault events.
To clear the irq_i[31:0]
interrupts at the external source, CV32E40X relies on a software-based mechanism in which the interrupt handler clears the interrupt at the source, e.g., through a memory-mapped register, which then deasserts the corresponding interrupt line.
In Debug Mode, all interrupts are ignored independent of mstatus.MIE
and the content of the mie
CSR.
CV32E40X can trigger the following interrupts as reported in mcause
:
Interrupt |
Exception Code |
Description |
Scenario(s) |
1 |
3 |
Machine Software Interrupt (MSI) |
|
1 |
7 |
Machine Timer Interrupt (MTI) |
|
1 |
11 |
Machine External Interrupt (MEI) |
|
1 |
31-16 |
Machine Fast Interrupts |
|
1 |
1024 |
Load bus fault NMI (imprecise) |
|
1 |
1025 |
Store bus fault NMI (imprecise) |
|
Note
Load bus fault and store bus fault are handled as imprecise non-maskable interrupts (as opposed to precise exceptions).
Note
The NMI vector location is at index 15 of the machine trap vector table for vectored CLINT mode (i.e. at {mtvec[31:7], 5’hF, 2’b00}). The NMI vector location therefore does not match its exception code as is otherwise the case for vectored CLINT mode.
Nested Interrupt Handling
Within the CLINT mode interrupt architecture there is no hardware support for nested interrupt handling. Nested interrupt handling can however still be supported via software.
The hardware automatically disables interrupts upon entering an interrupt/exception handler.
Otherwise, interrupts during the critical part of the handler, i.e. before software has saved the mepc
and mstatus
CSRs, would cause those CSRs to be overwritten.
If desired, software can explicitly enable interrupts by setting mstatus
.MIE to 1 from within the handler.
However, software should only do this after saving mepc
and mstatus
.
There is no limit on the maximum number of nested interrupts.
Note that, after enabling interrupts by setting mstatus
.MIE to 1, the current handler will be interrupted also by lower priority interrupts.
To allow higher priority interrupts only, the handler must configure mie
accordingly.
CLIC Mode Interrupt Architecture
If CLIC
== 1, then CV32E40X supports the Smclic, Smclicshv and Smclicconfig extensions defined in [RISC-V-CLIC]. The Ssclic and Suclic extensions are not supported.
In this configuration (i.e. CLIC
== 1) only the CLIC interrupt handling mode can be used (i.e. mtvec[1:0]
= 0x3).
The CLIC implementation is however split into a part internal to the core (containing CSRs and related logic) and a part external to the core (containing memory mapped registers and arbitration logic). CV32E40X only provides the core internal part of CLIC. The external part can be added on the interface described in Interrupt Interface. CLIC provides low-latency, vectored, pre-emptive interrupts.
Interrupt Interface
Table 23 describes the interrupt interface used for the CLIC interrupt architecture.
Signal |
Direction |
Description |
---|---|---|
|
input |
Is there any pending-and-enabled interrupt? |
|
input |
Index of the most urgent pending-and-enabled interrupt. |
|
input |
Interrupt level of the most urgent pending-and-enabled interrupt. |
|
input |
Associated privilege mode of the most urgent pending-and-enabled interrupt. Only machine-mode interrupts are supported. |
|
input |
Selective hardware vectoring enabled for the most urgent pending-and-enabled interrupt? |
The term pending-and-enabled interrupt in above table refers to pending-and-locally-enabled, i.e. based on the CLICINTIP
and
CLICINTIE
memory mapped registers from [RISC-V-CLIC].
Note
Edge triggered interrupts are not supported.
Note
clic_irq_shv_i
shall be 0 if cliccfg.nvbits
of the externl CLIC module is 0.
Note
clic_irq_priv_i[1:0]
shall be tied to 2’b11 (machine).
Note
The irq_i[31:0]
pins are ignored in CLIC mode and should be tied to 0.
Interrupts
Although the [RISC-V-CLIC] specification supports up to 4096 interrupts, CV32E40X itself supports at most 1024 interrupts. The
maximum number of supported CLIC interrupts is equal to 2^CLIC_ID_WIDTH
, which can range from 2 to 1024. The CLIC_ID_WIDTH
parameter
also impacts the alignment requirement for the trap vector table, see Machine Trap Vector Table Base Address (mtvt).
Interrupt prioritization is mostly performed in the part of CLIC that is external to the core, with the exception that CV32E40X prioritizes all NMIs above interrupts received via clic_irq_i
.
The clic_irq_i
, clic_irq_id_i
, clic_irq_level_i
, clic_irq_priv_i
and clic_irq_shv_i
signals are controlled via an externally memory mapped CLIC module.
After reset, all interrupts, except for NMIs, are (at least globally) disabled.
To enable any of the CLIC interrupts, both the global interrupt enable (MIE
) bit in the mstatus
CSR and the corresponding individual interrupt enables and levels in the external CLIC module must be configured.
The external CLIC module prioritizes all interrupts and presents CV32E40X with the highest priority pending and enabled interrupt. CV32E40X will then prioritize the interrupts including NMI as follows:
store bus fault NMI (1025)
load bus fault NMI (1024)
clic_irq_i
with index, level and selective hardware vectoring defined byclic_irq_id_i
,clic_irq_level_i
andclic_irq_shv_i
respectively.
The clic_irq_i
interrupt line is level-sensitive. The NMIs are triggered by load/store bus fault events.
To clear the clic_irq_i
interrupt at the external source, CV32E40X relies on a software-based mechanism in which the interrupt handler clears the interupt at the source, e.g., through a memory-mapped register.
In Debug Mode, all interrupts are ignored independent of mstatus.MIE
and the configuration of an external CLIC module.
CV32E40X can trigger the following interrupts as reported in mcause
:
Interrupt |
Exception Code |
Description |
Scenario(s) |
1 |
0-1023 |
CLIC interrupt |
|
1 |
1024 |
Load bus fault NMI (imprecise) |
|
1 |
1025 |
Store bus fault NMI (imprecise) |
|
Note
Load bus fault and store bus fault are handled as imprecise non-maskable interrupts (as opposed to precise exceptions).
Nested Interrupt Handling
CV32E40X offers hardware support for nested interrupt handling when CLIC
== 1.
CLIC extends interrupt preemption to support up to 256 interrupt levels for each privilege mode, where higher-numbered interrupt levels can preempt lower-numbered interrupt levels. See [RISC-V-CLIC] for details.