P31 is the first rung where the runtime body is C instead of assembly.
The reset path still lives in runtime/start.S: set the stack pointer, set
mtvec, clear .bss, call main(), and copy the return value into x5 before
halting. The actual probe lives in runtime/main.c.
Commands:
make -C projects/31_rv32i_c_runtime_probe/test
make -C projects/31_rv32i_c_runtime_probe/test act4
Results:
| check | result |
|---|---|
| Compiled C runtime | PASS |
Runtime UART sequence CTE | PASS |
| Runtime timer interrupt visible to C | PASS |
| Runtime external interrupt visible to C | PASS |
ACT4/Sail rv32i/I | PASS=39 FAIL=0 NOT RUN=0 |
| Hardening | NOT RUN |
| Official privileged tests | NOT RUN |
One useful cleanup: the linker script now gives text and data separate program headers, so GNU ld no longer warns about a single RWX load segment. That does not add memory protection to the tiny platform. It just makes the ELF shape less sloppy.
The current generated binary is 540 bytes. Small is good here. We are proving that the core can run compiler output with calls, globals, volatile MMIO, and trap-updated C flags before asking it to run anything that looks like real firmware.