Files
psxrecomp/runtime/include
Matthew Stanley a3e8f2818b feat(timing): faithful mult/div completion-stall + ruler #2 native half (validated EXACT)
Stage-2's biggest cost gap closed. MULT/MULTU/DIV/DIVU now set a completion
deadline; MFLO/MFHI stall guest cycles until it — exactly like Beetle's
muldiv_ts_done. Latencies transcribed from cpu.cpp: DIV/DIVU=37; MULT via
MULT_Tab24 (14/10/7) on the first-operand magnitude. Native previously charged
ZERO for this.

- Per-instruction cycle charging is now the DEFAULT on this audit branch
  (PSX_CODEGEN_CYCLE_PER_INSN), required so the stall absorbs correctly (the
  running cycle count must be accurate mid-block). Validated cycle-neutral for the
  identity base model; Tomba 2 still reaches the FMV.
- runtime: CPUState.muldiv_ts_done + psx_muldiv_set/stall + psx_mult_latency_s/u
  in psx_cycles.c. Emitted at the mult/div/mflo/mfhi sites in the GAME emitter
  (gated PSX_ENABLE_BLOCK_CYCLES). Stall fires even for mflo/mfhi to $zero.
- ruler #2 native half: tools/cycle_testrom/CMakeLists.txt builds psx-cyctest
  (links the recompiled test EXE), boots disc/cyctest.cue (serial CYCT-00101 so
  disc-identity matches, no warning dialog). measure.py --port 4600.

VALIDATION (native vs Beetle oracle, per-iteration component cost):
  div +38 vs +38 EXACT | div_spaced +38 vs +38 EXACT (absorb works) |
  mult +15 vs +15 EXACT | baseline/alu match.
Remaining: load native +7 vs Beetle +5 (memory.c flat +6 wait-state needs
calibration to ~4) — a smaller refinement. BIOS emitter still block-mode (ruler
#1 unchanged at 30) — applying per-insn + muldiv there is the next step to close
ruler #1's div-stall gap.

No FMV regression (i_stat 0x8D, screenshot verified).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 00:00:22 -07:00
..
2026-05-17 21:58:55 -07:00