journal 2026-05-03

P49 - cur_priv goes live

p49riscvprivsmodeautonomous-mode

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:

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