RISC-V
A Chip Designer’s Perspective of RISC-V Traps
![]()
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:
- Saves the PC into mepc or sepc
- Records the cause in mcause or scause
- Optionally stores fault info in mtval or stval
- Updates the fields mpp/spp, mpie/spie and mie/sie of mstatus
- Jumps to the address in mtvec or stvec – Executes the trap handler
- 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
- Trap Vector Setup
- mtvec points to our trap_vector in direct mode (all traps jump here).
- Enabling Interrupts
- Set MEIE bit in mie → enables machine external interrupts.
- Set MIE in mstatus → globally allows interrupts.
- PLIC Setup
- Enables a specific interrupt ID (e.g., UART, GPIO).
- Sets priority threshold to 0 so all priorities are accepted.
- 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.
- 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
- 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.
- This firmware configures:
- 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.
- 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
2. RTOS kernel (in S-mode) sets up stvec, sie, and sstatus.
3. On interrupt:
o CPU jumps to supervisor_trap_vector (because of stvec).
o scause is checked:
- Bit 31 → interrupt, else exception.
- Code 9 → Supervisor External Interrupt.
o Device serviced → PLIC claim/complete done → sret.
Trap Flow Recap
- Normal execution
- Event occurs (exception or interrupt)
- CPU saves state into CSRs (mepc/sepc, mcause/scause, mtval/stval)
- PC → trap vector (mtvec/stvec)
- Handler runs (bare-metal or OS)
- 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.
75,221
SUBSCRIBERS
Subscribe to our Blog
Get the latest VLSI news, updates, technical and interview resources



