Design & Reuse

Industry Expert Blogs

A Chip Designer’s Perspective of RISC-V Traps

- Maven Silicon
January 22, 2026

Author:  P R Sivakumar, Founder and CEO, Maven Silicon

Understanding RISC‑V traps is essential for Chip Designers building RISC‑V CPUs, microcontrollers, and complex SoCs. It’s equally important for Embedded Engineers who develop and debug software stacks — firmware, OS kernels, trap handlers, device drivers. In RISC‑V, traps are at the heart of exception handling, system calls, and interrupt-driven I/O. So, in this article I explain everything, especially from a chip designer’s perspective - from what traps are to how they are set up and used in bare-metal, RTOS and OS-based hardware systems, with RISC-V assembly examples.

What is a Trap in RISC-V?

A trap is any event that causes the CPU to stop normal instruction flow and jump to a trap handler running in a more privileged mode.

Two types:

Type

Synchronous?

Cause Example

Exception

Yes

Illegal opcode, ecall

Interrupt

No

Timer tick, UART receive, GPIO event

When a trap occurs, the CPU:

  1. Saves the PC into mepc or sepc
  2. Records the cause in mcause or scause
  3. Optionally stores fault info in mtval or stval
  4. Updates the fields mpp/spp, mpie/spie and mie/sie of mstatus
  5. Jumps to the address in mtvec or stvec – Executes the trap handler
  6. Executes the mret/sret instruction to resume the interrupted thread : pc=mepc/sepc

To explore more and dive deep into RISC-V traps, refer to my RISC-V Traps YouTube video

Trap Setup Process

Step 1: Trap Vector Setup

The trap vector tells the CPU where to go when a trap happens.

  • Direct mode → all traps go to the same address
  • Vectored mode → traps jump to a base + (cause × 4)

Step 2: Enabling Interrupts

To receive interrupts, you need:

  • Global enable in mstatus
  • Specific enable in mie

Step 3: Delegating to Lower Privilege (Optional)

In OS-based systems, Machine Mode can delegate traps to Supervisor Mode.

Step 4: PLIC Setup for External Interrupts

The Platform-Level Interrupt Controller routes device interrupts.

Real-World Scenarios

[A] Bare-Metal – External Interrupt

 

 

How It Works

  1. Trap Vector Setup
    • mtvec points to our trap_vector in direct mode (all traps jump here).
  2. Enabling Interrupts
    • Set MEIE bit in mie → enables machine external interrupts.
    • Set MIE in mstatus → globally allows interrupts.
  3. PLIC Setup
    • Enables a specific interrupt ID (e.g., UART, GPIO).
    • Sets priority threshold to 0 so all priorities are accepted.
  4. Interrupt Flow
    • wfi halts until an interrupt occurs.
    • When a device triggers, PLIC signals M-mode → CPU jumps to trap_vector.
    • mcause high bit = interrupt (1), low bits = cause code (11 = MEI).
    • Claim the interrupt ID from PLIC, handle the device, then complete the claim.
  5. Returning
    • mret restores mepc and resumes main code.

[B] OS-Based – System Call with ecall

The OS uses traps to switch from user mode to kernel mode.

 

The OS trap handler reads a7 to determine the syscall and services it before sret.

[C] RTOS - M-mode Firmware delegates interrupts to S-mode RTOS

How S-mode RTOS interrupt handling works on RISC-V

  1. M-mode firmware (like OpenSBI or a custom stub) is still required because hardware boots in M-mode.
    • This firmware configures:
      • mideleg → delegates certain interrupts (like external or timer) to S-mode.
      • medeleg → delegates exceptions to S-mode.
      • stvec → points to the S-mode trap handler.
    • Then it switches to S-mode and jumps into the RTOS kernel.
  2. RTOS runs entirely in S-mode.
    • All interrupts you’ve delegated now go directly to the S-mode trap handler without trapping to M-mode first.
    • The S-mode trap handler:
      • Reads scause (cause of trap/interrupt).
      • Reads sepc (return address).
      • Services the interrupt (e.g., from a PLIC).
      • Returns with sret.
  3. PLIC & Timer
    • If using the Platform-Level Interrupt Controller (PLIC), the PLIC is memory-mapped and can be accessed from S-mode (if M-mode firmware allows).
    • For timers, the CLINT (Core Local Interruptor) can also be configured for S-mode interrupts (via mideleg).

Below is a simplified RISC-V assembly sequence that would be part of an S-mode RTOS kernel:

 

How It Works:

  1. M-mode firmware sets mideleg so external interrupts go to S-mode.

Example:

li t0, (1 << 9) # Delegate Supervisor External Interrupt

csrs mideleg, t0

  1. RTOS kernel (in S-mode) sets up stvec, sie, and sstatus.
  2. On interrupt:
    • CPU jumps to supervisor_trap_vector (because of stvec).
    • scause is checked:
      • Bit 31 → interrupt, else exception.
      • Code 9 → Supervisor External Interrupt.
    • Device serviced → PLIC claim/complete done → sret.

Trap Flow Recap

  1. Normal execution
  2. Event occurs (exception or interrupt)
  3. CPU saves state into CSRs (mepc/sepc, mcause/scause, mtval/stval)
  4. PC → trap vector (mtvec/stvec)
  5. Handler runs (bare-metal or OS)
  6. mret / sret restores state and returns to main thread

RISC-V Traps Summary

  • In RISC-V, trap means a transfer of control to trap handler.
  • Three kinds of event which cause the CPU to force a trap: System Call[ecall], Exception[Illegal instruction], and Device Interrupt[Timer/External Interrupt]
  • In bare-metal embedded systems, traps are usually executed in machine mode - using the RISC-V Machine ISA CSRs: mstatus, mie, mcause, mepc, mtval, mtvec
  • In OS-based systems, traps could also be delegated to OS kernel, and executed in supervisor mode – using the RISC-V Supervisor ISA CSRs: sstatus, sie, scause, sepc, stval, stvec

Maven Silicon’s Advanced RISC-V Online Executive Certification Courses - RISC-V IP Design, RISC-V IP Verification, and RISC-V SoC Design empower chip designers to dive deep into the RISC-V ISA and design powerful CPUs, embedded microcontrollers, and complex SoCs.