Exceptions and Interrupts

CV32E40S 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

CV32E40S 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. Execution attempt with address failing PMP check.

0

2

Illegal instruction

0

3

Breakpoint

Environment break.

0

5

Load access fault

Non-naturally aligned load access attempt to an I/O region. Load-Reserved attempt to region without atomic support. Load attempt with address failing PMP check.

0

7

Store/AMO access fault

Non-naturally aligned store access attempt to an I/O region. Store-Conditional or Atomic Memory Operation (AMO) attempt to region without atomic support. Store attempt with address failing PMP check.

0

8

Environment call from U-Mode (ECALL)

0

11

Environment call from M-Mode (ECALL)

0

24

Instruction bus fault

instr_err_i = 1 and instr_rvalid_i = 1 for instruction fetch

0

25

Instruction parity/checksum fault

instr_gntpar_i, instr_rvalidpar, instr_rchk_i related errors

If an instruction raises multiple exceptions, the priority, from high to low, is as follows:

  • instruction access fault (1)

  • instruction parity/checksum fault (25)

  • instruction bus fault (24)

  • illegal instruction (2)

  • environment call from U-Mode (8)

  • environment call from M-Mode (11)

  • environment break (3)

  • store/AMO access fault (7)

  • load access fault (5)

Exceptions in general cannot be disabled and are always active. All exceptions are precise. Whether the PMP and PMA will actually cause exceptions depends on their configuration. CV32E40S 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 CV32E40S 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 or PMP check only leads to an instruction access exception if an actual execution attempt is made for it.

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 CV32E40S 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.

Table 22 CLINT mode interrupt architecture interface signals

Signal

Direction

Description

irq_i[31:16]

input

Active high, level sensistive interrupt inputs. Custom extension.

irq_i[15:12]

input

Reserved. Tie to 0.

irq_i[11]

input

Active high, level sensistive interrupt input. Referred to as Machine External Interrupt (MEI), but integrator can assign a different purpose if desired.

irq_i[10:8]

input

Reserved. Tie to 0.

irq_i[7]

input

Active high, level sensistive interrupt input. Referred to as Machine Timer Interrupt (MTI), but integrator can assign a different purpose if desired.

irq_i[6:4]

input

Reserved. Tie to 0.

irq_i[3]

input

Active high, level sensistive interrupt input. Referred to as Machine Software Interrupt (MSI), but integrator can assign a different purpose if desired.

irq_i[2:0]

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. CV32E40S 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 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 parity/checksum fault NMI (1027)

  • load parity/checksum fault NMI (1026)

  • 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 and load/store parity/checksum fault events. To clear the irq_i[31:0] interrupts at the external source, CV32E40S relies on a software-based mechanism in which the interrupt handler signals completion of the handling routine to the interrupt 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.

CV32E40S can trigger the following interrupts as reported in mcause:

Interrupt

Exception Code

Description

Scenario(s)

1

3

Machine Software Interrupt (MSI)

irq_i[3]

1

7

Machine Timer Interrupt (MTI)

irq_i[7]

1

11

Machine External Interrupt (MEI)

irq_i[11]

1

31-16

Machine Fast Interrupts

irq_i[31]-irq_i[16]

1

1024

Load bus fault NMI (imprecise)

data_err_i = 1 and data_rvalid_i = 1 for load

1

1025

Store bus fault NMI (imprecise)

data_err_i = 1 and data_rvalid_i = 1 for store

1

1026

Load parity/checksum fault NMI (imprecise)

Load parity/checksum fault (imprecise)

1

1027

Store parity/checksum fault NMI (imprecise)

Store parity/checksum fault (imprecise)

Note

Load bus fault, store bus fault, load parity/checksum fault and store parity/checksum 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 CV32E40S 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). CV32E40S 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.

Table 23 CLIC mode interrupt architecture interface signals

Signal

Direction

Description

clic_irq_i

input

Is there any pending-and-enabled interrupt?

clic_irq_id_i[CLIC_ID_WIDTH-1:0]

input

Index of the most urgent pending-and-enabled interrupt.

clic_irq_level_i[7:0]

input

Interrupt level of the most urgent pending-and-enabled interrupt.

clic_irq_priv_i[1:0]

input

Associated privilege mode of the most urgent pending-and-enabled interrupt. Only machine-mode interrupts are supported.

clic_irq_shv_i

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, CV32E40S 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 CV32E40S 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 CV32E40S with the highest priority pending and enabled interrupt. CV32E40S will then prioritize the interrupts including NMI as follows:

  • store parity/checksum fault NMI (1027)

  • load parity/checksum fault NMI (1026)

  • store bus fault NMI (1025)

  • load bus fault NMI (1024)

  • clic_irq_i with index, level and selective hardware vectoring defined by clic_irq_id_i, clic_irq_level_i and clic_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, CV32E40S 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.

CV32E40S can trigger the following interrupts as reported in mcause:

Interrupt

Exception Code

Description

Scenario(s)

1

0-1023

CLIC interrupt

clic_irq_i, clic_irq_id_i

1

1024

Load bus fault NMI (imprecise)

data_err_i = 1 and data_rvalid_i = 1 for load

1

1025

Store bus fault NMI (imprecise)

data_err_i = 1 and data_rvalid_i = 1 for store

Note

Load bus fault and store bus fault are handled as imprecise non-maskable interrupts (as opposed to precise exceptions).

Nested Interrupt Handling

CV32E40S 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.