3.1.7-14M-Mode CSRs II: Vectoring, Delegation, Interrupts & Counters

Part II Linux boot: required Vol. II (Privileged) pp. 41–48 · ~5 min read

  • mtvec
  • trap delegation
  • mip/mie

Where traps go, who handles them, and which interrupts fire — the control plane of the trap unit.

3.1.7 mtvec

mtvec (0x305)

BASE[63:2]632MODE10
WPRI/RO WLRL WARL RW
Click a field for semantics, reset state, and the minimal-implementation note.

Reset and NMI vectors are separate, platform-defined addresses — mtvec governs ordinary traps only.

3.1.8 medeleg / mideleg: pushing traps down

With S-mode present, delegation lets S/U-mode traps bypass M entirely:

Delegation semantics
Rule
What a set bit doesTrap i occurring in S or U-mode → handled by the S-mode handler: scause/sepc/stval/SPP/SPIE/SIE written, SIE cleared — the m* registers stay untouched
Never downwardA trap occurring in M-mode ALWAYS stays in M, delegation notwithstanding
Interrupt maskingA delegated interrupt is MASKED at M: mideleg[5]=1 means STIs cannot be taken while in M-mode
Bit positionsmedeleg bit i = mcause exception code i (64-bit; medelegh on RV32); mideleg matches mip layout
Hardwiring rulesNo medeleg bit may be read-only ONE (delegable must support non-delegation); medeleg[11] (ecall-from-M) and [16] (double trap) are read-only ZERO; discover support by write-ones-readback
Dotted-underlined cells have explanations — click one.

3.1.9 mip / mie: the interrupt front door

Bit i corresponds to cause i; bits 15:0 are standard, ≥16 platform/custom. The take-condition for interrupt i → M-mode :

(mode < M, or mode = M ∧ mstatus.MIE) and mip[i] ∧ mie[i] and ¬mideleg[i]

— evaluated within bounded time of any mip change and immediately after xRET or writes to mip/mie/mstatus/mideleg. Priority among simultaneous M-destined interrupts: MEI > MSI > MTI > SEI > SSI > STI > LCOFI.

The standard interrupt bits (mip layout; sip/sie = delegated-bit views)
Bitmip behavior
MEIP/MEIE — machine external11Read-only; set/cleared by the platform interrupt controller (PLIC/APLIC)
MTIP/MTIE — machine timer7Read-only; pending iff mtime ≥ mtimecmp; cleared by writing mtimecmp
MSIP/MSIE — machine software (IPI)3Read-only; written via the memory-mapped msip register (32-bit, bit 0)
SEIP/SEIE — supervisor external9Software-writable bit B, OR’d with controller signal E: reads return B∨E, RMW sequences act on B only
STIP/STIE — supervisor timer5Writable by M if no stimecmp; read-only reflection of stimecmp when Sstc is active
SSIP/SSIE — supervisor software1Writable; controller-settable too
LCOFIP/LCOFIE — counter overflow13Read-write (Sscofpmf); reflects mhpmevent OF bits
Dotted-underlined cells have explanations — click one.

3.1.10–3.1.14 Counters, gates, scratch, and the return address

  • mcycle / minstret (0xB00/0xB02): 64-bit writable masters of the Part I shadows; arbitrary reset value; a CSR write takes effect after the writing instruction completes (the u06 override rule). mcycle may be shared between harts of one core.
  • mhpmcounter3–31 + mhpmevent3–31: platform-defined events (0 = none); counter+selector read-only zero is a legal implementation.
  • mcounteren (exists iff U-mode): CY/TM/IR/HPMn bits gate the next-lower mode’s access to the shadow CSRs — clear bit = illegal instruction from S/U. TM also gates stimecmp. Pure access control: counters keep counting regardless.
  • mcountinhibit: CY/IR/HPMn stop the counters themselves (power/measurement); accessibility unaffected; mtime is not inhibitable (it’s shared platform state).
  • mscratch: the M-handler’s anchor — typically swapped with an x-register in one csrrw to obtain a save-area pointer without clobbering user state.
  • mepc: WARL, bit 0 always zero, bit 1 masked on reads while IALIGN=32 (yet writable underneath — surviving misa.C toggles); must hold every valid virtual address; written by hardware only when a trap is taken.

Hardware Designer Notes

This page plus mstatus is your interrupt unit’s RTL spec: a priority encoder over (mip ∧ mie) split by mideleg, the mode/MIE geometry, and the mtvec redirect. The classic bugs live in the corners called out above — SEIP’s dual nature, delegated-interrupt masking in M, and the bounded-time re-evaluation after CSR writes (a stale interrupt-pending latch after csrw mideleg is a real-silicon erratum pattern).

Minimal Linux-boot hart MUST

  • Implement the delegated-trap register split exactly: s* written, m* untouched, and the mode check BEFORE mstatus updates
  • Mask delegated interrupts out of the M-mode take-condition
  • Re-evaluate the interrupt condition after xRET and after writes to mip/mie/mstatus/mideleg — not just on mip edges
  • Build the SEIP read=B∨E / RMW-on-B mux
  • Mask mepc[1] on reads (including MRET’s) when IALIGN=32

MAY simplify / trap-and-emulate

  • Support Direct mtvec mode only (MODE bit read-only 0) — Linux copes
  • Hardwire all hpm counters/selectors to zero for v1
  • Share one mcycle across a multithreaded core (document it)

Check yourself — vectoring, delegation & interrupts

1.mtvec.MODE=Vectored. Where does a machine timer interrupt (cause 7) land, and where does an illegal-instruction exception land?

2.medeleg delegates illegal-instruction (bit 2) to S-mode. M-mode firmware itself executes an illegal instruction. Who handles it?

3.With mideleg[5]=1 (STI delegated), can a supervisor timer interrupt be taken while the hart executes in M-mode?

4.csrrs t0, mip, t1 executes where the external controller asserts SEIP and the software SEIP bit is 0. What does t0[9] read, and what does the RMW write?

5.Why does mepc's bit 1 read as zero when IALIGN=32, yet remain writable underneath?

5 questions