Autonomous-mode rung, 5th past P45. After the user said “go on” following the original 4-rung stop point.
What landed
A real 2-bit cur_priv register in src/top.sv. Resets to M.
Trap entry captures cur_priv into mstatus.MPP and switches to
M; mret restores cur_priv from MPP and sets MPP back to M; ECALL
cause routes through M/S/U based on cur_priv at the call.
WARL coerce on writes to MPP: U (00) and reserved 2’b10 both
coerce to S (01). M and S pass through. Keeps a software typo
from putting the chip into an unsupported priv mode silently.
PASS at 5,102,225 clocks. Two probes:
priv_tracking_probeexercises MPP storage + WARL coerce.priv_transition_probedoes the full M→S→trap→M round trip with a probe-local trap handler installed in mtvec. Verifies ECALL-from-S yields cause 9, captured MPP is S, the handler can mret back to M, and a follow-up ECALL yields cause 11.
While building the round-trip probe, hit a chip-side limit:
csr_mtvec_hi was 10 bits wide ([11:2]) — capping mtvec at
4 KiB. The FreeRTOS handler is always at 0x100 so nothing had
ever noticed; our probe handler at 0x51f8 was getting truncated
to 0x1f8 and the chip jumped to garbage on the first ECALL.
Widened csr_mtvec_hi to [31:2] (the full spec-required base
width). One small RTL fix as a side effect of having a real test
that exercises mtvec.
What still goes to M
Every trap. medeleg/mideleg storage exists (P48) but isn’t
consulted for routing yet. That’s the next big rung — when
cur_priv != M and medeleg[cause] is set, route to stvec
instead of mtvec, capture into sstatus.SPP instead of MPP,
and add sret for the dual return path.
Stop point reasoning
Originally stopped at P48 (4 rungs past P45). User said “go on” and then “finish mret-to-s transition”, so P49 is the 5th rung and it now covers the full M↔S round trip via M-mode trap routing.
Wart count
Zero new ones. The old gcc-zbb-auto-emit-sext.b hang is still
outstanding and still the reason march is held at
rv32ima_zba_zicsr_zifencei (no _zbb suffix).