No. 47 / project of 147 on the ladder

Supervisor-mode CSR scaffolding

introduces — 9 S-mode CSRs (sstatus/sie/stvec/sscratch/sepc/scause/stval/sip/satp) decoded and round-tripping as M-readable storage; staging for Linux's S-mode work

harden statelast run2026-05-03
areaunknownμm²
signoff
  • DRCNOT RUN
  • LVSNOT RUN
  • antennaNOT RUN

P47 stages the S-mode CSR address space the Linux port will need. Nine CSRs - sstatus, sie, stvec, sscratch, sepc, scause, stval, sip, satp - are decoded, writable, and readable; everything is currently M-mode-readable (the chip is still M-mode-only).

Status: RTL pass. Probe (10 sub-checks) all PASS at 5,101,601 clocks. FreeRTOS demo still PASSES afterwards.

What this is and isn’t

The chip does not enter S mode in P47. There is no priv-1 transition, no privilege check on the access, and no behavioral coupling between M and S CSRs. Writing to satp stores the bits but doesn’t translate anything; writing to stvec doesn’t redirect any trap; writing to sip doesn’t pend any interrupt.

This is deliberate. Linux needs the storage to exist before any S-mode trap or page-table work, and putting the address-map work in its own rung means subsequent rungs can each focus on one narrow piece of behavior:

  • M↔S↔U mode tracking with mstatus.MPP returning to the right priv on mret;
  • medeleg/mideleg actually routing traps to S mode;
  • Real S-mode trap entry using stvec/sepc/scause/stval;
  • satp Sv32 paging behind a real MMU.

Each of those is a multi-day rung in its own right.

What changed

One file: src/top.sv. About 40 lines added.

For each of the nine CSRs:

  1. A localparam logic [11:0] CSR_<NAME> for the address.
  2. A logic [31:0] csr_<name> storage register.
  3. An entry in csr_known (so non-S-aware reads don’t trap).
  4. An entry in csr_writable.
  5. A read path in csr_read() returning the storage.
  6. A reset to zero.
  7. A write case in S_EXECUTE storing csr_wdata.

No new FSM states, no new control plane.

Probe

The probe writes 0xC0DE000X (X = 1..9) to each S CSR, reads it back, then re-reads sstatus to verify the eight intervening writes didn’t smear into it. Error codes 80-89.

Files

  • src/top.sv - 9 S-mode CSRs as M-readable storage
  • app/main.c - smode_csr_probe (10 sub-checks)

Harden

NOT RUN. Estimated +340 cells over P46 (9 × 32-bit storage registers ≈ 288 cells, plus ~50 cells of decode/mux). All combinational + simple flops, no new datapath structure.

What just happened?

S-mode CSRs are decoded and round-trip in storage form; the chip still runs only in M-mode but the address-map work for Linux is done. The next rung is P48 - trap delegation CSR storage (medeleg/mideleg), same scaffold-then-behavior pattern.