Skip to content

RISC-V spin-loop recovery

Recover the pure-Rust ADDI/back-branch batch idea from CrispStrobe/labwired-core (5d03bc55a5, with the once-per-batch refinement in 315e6f5cb1). The original persistent promotion cache could outlive code stores and snapshot restoration. It is deliberately not imported.

The implementation recognizes two instructions in the existing, permission-vetted 256-byte fetch window on each batch. It adds no persistent compiled-code cache. Cold windows and blocks spanning a window boundary use the interpreter. Guest stores already invalidate the fetch window; reset and both snapshot restore paths must invalidate it too. This also repairs stale interpreted fetches after restore.

Only ADDI/C.ADDI with identical nonzero source/destination followed by JAL x0/C.J back to the first instruction qualify. Retire whole iterations only. Preserve register wrapping, mtime/mip, odd remaining budgets, scheduler deadlines and the published pre-instruction clock. Disable aggregation with interrupts enabled, external IRQ lines, waiting CPUs, cycle-accurate devices, observers or logic taps. The existing native JIT retains its dispatch priority. Setting decode_cache_enabled=false also opts out of loop aggregation.

Verification: compare against individual interpreter steps; exercise guest code stores, reset, both snapshot formats, compressed negative increments, observable execution, and scheduler deadlines. Measure a warmed loop against repeated steps; report that synthetic measurement separately from real firmware performance.

Deferred fork work: broader Cortex-M caching, Xtensa execution/JIT changes, persistent RISC-V promotion caches, and fork-wide performance baselines. None is implied by this recovery. ARM DSP extensions are separate recovery work requiring instruction-level semantic review. The nRF RF-medium delivery path was already merged in upstream #800, including its path-loss/RSSI regression test.

Local evidence

Rust 1.95.0, repository development profile (opt-level=1, debug assertions and overflow checks enabled): all 37 RISC-V unit tests in the initial recovery run passed. Before the repair, reset and both snapshot-restore regressions each produced 64 instead of 96, proving stale ADDI +1 execution after code became +2.

One synthetic warmed-loop measurement (640,000 guest instructions) took 470 microseconds aggregated versus 92.3 milliseconds using individual interpreter steps with the same configuration and full final CPU-state equality. This is a trivial arithmetic-loop measurement, not an end-to-end firmware throughput or release-build claim; interrupts/observability and nonmatching code retain the interpreter. No physical hardware was recaptured.