From 8a2f01d79d46ae68a3d702c16cbcc6bf4d38a6fe Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Sat, 27 Jun 2026 01:08:00 -0700 Subject: [PATCH] timing: land oracle-accurate load wait-state = 4 (KNOWN: wedges Tomba 2 boot) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set memory.c main-RAM load wait-state to 4, the Beetle-oracle-accurate value (ruler #2 load loop == Beetle exactly at 4; the old 6 was DuckStation's). This is the faithful value and we keep it. ⚠ ISSUE THIS COMMIT CAUSES (and why we proceed): load=4 DETERMINISTICALLY wedges Tomba 2's BIOS-shell boot — pc=0/exception at shell pc 0xBFC2CE64 (epc 0x80000048), reproducible at identical total_checks across restarts. The faster-but-accurate load makes the CPU outrun a shell loop's timing assumption, exposing a real downstream bug (incomplete device/loop timing). Per CLAUDE.md Rule -1 (faithful core, no masking with a wrong cost) we LAND the accurate value and root-cause the real wedge, rather than revert to 6 to hide it. Until the wedge is fixed Tomba 2 won't reach the FMV on THIS branch (wt/tomba2-load-accuracy); ruler #2 (its own boot disc, no shell loop) is unaffected and still validates the cost model. Branch wt/tomba2-load-accuracy forks from wt/tomba2-cycle-audit (which keeps the booting value 6). Next: root-cause 0xBFC2CE64. Co-Authored-By: Claude Opus 4.8 --- runtime/src/memory.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/runtime/src/memory.c b/runtime/src/memory.c index 506511c4..8b97bdde 100644 --- a/runtime/src/memory.c +++ b/runtime/src/memory.c @@ -863,16 +863,22 @@ uint8_t psx_read_byte(uint32_t addr) { * effective physical address (all of KUSEG/KSEG0/KSEG1 alias the same DRAM), NOT * the code region, so relocated kernel code is timed correctly. * - * VALUE: the Beetle ORACLE says 4 (the cycle test ROM load-isolation loop measures - * a main-RAM load at +5 over baseline = base 1 + 4; Beetle ReadMemory = fudge(0/2) - * + region wait(0 RAM) + completion(+2), netting 4 in the common fudged case). - * BUT lowering this from 6 to 4 DETERMINISTICALLY WEDGES Tomba 2's BIOS-shell boot - * (reproducible: pc=0/exception at shell pc 0xBFC2CE64, epc 0x80000048, identical - * total_checks across restarts — i.e. a real timing-sensitivity in a shell loop, - * exposed by the faster-but-accurate load cost). Kept at 6 for now to preserve a - * BOOTING validation vehicle (the FMV + ruler #1 need a live boot). The accurate - * value (4) is PARKED behind that wedge — root-cause the shell pc=0 first, then - * land 4. The ruler #2 load loop validates 4 == Beetle when this is enabled. + * VALUE = 4, the Beetle ORACLE-accurate cost (the cycle test ROM load-isolation + * loop measures a main-RAM load at +5 over baseline = base 1 + 4; Beetle ReadMemory + * = fudge(0/2) + region wait(0 RAM) + completion(+2), netting 4 in the common fudged + * case). The old 6 came from DuckStation (RAM_READ_TICKS), which our oracle + * contradicts. Ruler #2 load == Beetle EXACTLY at 4. + * + * ⚠ KNOWN ISSUE this value CAUSES (under active root-cause on branch + * wt/tomba2-load-accuracy): lowering 6→4 DETERMINISTICALLY WEDGES Tomba 2's + * BIOS-shell boot — pc=0/exception at shell pc 0xBFC2CE64 (epc 0x80000048), + * reproducible at identical total_checks across restarts. The faster-but-accurate + * load cost makes the CPU outrun a shell loop's timing assumption, exposing a + * downstream bug (likely incomplete device/loop timing). We deliberately KEEP the + * accurate value and fix the real cause rather than mask it with a wrong cost — + * faithful core (CLAUDE.md Rule -1). Until the wedge is fixed, Tomba 2 will not + * reach the FMV on this branch; ruler #2 (its own boot disc) is unaffected. + * * RESIDUAL beyond the constant (stateful, future): Beetle's per-load ReadFudge * variation (back-to-back loads differ ~1; ruler load2 was 10 vs 11) and LDAbsorb * give-back (a load whose result is read by the next instruction is absorbed). @@ -880,7 +886,7 @@ uint8_t psx_read_byte(uint32_t addr) { * These wrappers are wired to cpu->read_* (see main.cpp), so the penalty applies * to BOTH statically-recompiled and dirty-RAM-interpreted guest loads, but NOT to * debug-server / device reads that call psx_read_* directly. */ -#define PSX_RAM_READ_WAIT_CYCLES 6u /* oracle value is 4 — PARKED: 4 wedges Tomba 2 boot (see above) */ +#define PSX_RAM_READ_WAIT_CYCLES 4u /* oracle-accurate; ⚠ causes Tomba 2 boot wedge @0xBFC2CE64 — root-cause in progress */ extern void psx_advance_cycles(uint32_t cycles); static inline void charge_main_ram_read(uint32_t addr) {