Commit Graph

2 Commits

Author SHA1 Message Date
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
Matthew Stanley 47bcfecb21 feat(timing): ruler #2 Beetle half live — synthetic boot disc + oracle component costs
The test ROM now boots on a real BIOS. The license region (required or the BIOS
drops to its shell) is extracted from a disc the developer OWNS via the in-tree
dumpsxiso and embedded by mkpsxiso — LOCAL ONLY, gitignored, never redistributed.
Both backends boot disc/cyctest.cue identically (real BIOS -> SYSTEM.CNF -> EXE),
so CPU/cache state matches.

- disc/cyctest.xml + disc/SYSTEM.CNF: mkpsxiso project (tracked). license_data.dat
  + built .bin/.cue gitignored (copyrighted Sony data, local only).
- measure.py: per-anchor consecutive-hit Δ = per-iteration cycle cost; reports
  per-component cost via baseline subtraction.
- README: boot-disc build + license-extraction recipe + the oracle results.

Beetle ORACLE component costs (the HW targets for the cost model):
  baseline 3 | alu +1 | load +5 | load2 +11 (2nd load +1 = ReadFudge)
  | div +38 (~36 stall) | div_spaced +38 (fillers ABSORBED) | mult +15 (~13 stall)
Native currently charges 0 for div/mult stall — the dominant gaps. div_spaced==div
proves the stall must be a completion-timestamp + stall-on-mflo-read (absorbable),
NOT a flat charge on the divu.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:52:25 -07:00