Commit Graph

4 Commits

Author SHA1 Message Date
Shokunin fdc354543d tools, tests: the segment probe loads an overlay; ledger guard overlay-segment-shards
docs/SEGMENT_AWARE_CODE.md §5.7, §7. The synthetic probe gains an overlay
phase that loads code the way a game loads an overlay. After the three
probe_run sequences it:
- leaves the critical section the BIOS started it in, because the kernel's
  CD driver waits on CD interrupts;
- reads its own EXE file back from the disc through the BIOS file calls
  (B0:32 open, B0:34 read, B0:36 close; the kernel DMAs the sectors) into
  RAM at 0x000A0000;
- calls the copy of a position-independent ov_run there through KUSEG,
  KSEG0 and KSEG1, timing each run with Timer 2.

It records the T2 deltas and ov_getpc links at R+0x28-R+0x3C, and the file
descriptor and byte count at R+0x40/0x44. In the runtime that code is
CD-DMA'd RAM code. Capture records its entries with their segments, and
compile_overlays.py builds a shard per segment.

The phase replaces the `j .` spin with a `j` of the same size, so every
earlier label keeps its address. The static probe code and every result
word it wrote before are unchanged, and so are its probe_run cycle-watch
hits on Beetle and native. Beetle on both BIOSes: T2 56 / 56 / 82 and links
0x000A0A2C / 0x800A0A2C / 0xA00A0A2C, the same shape as probe_run.

The ledger gains the regression guard overlay-segment-shards (§5.7). It
builds the capture record overlay_capture.c writes for the probe's
disc-loaded ov_run (schema v3), splits it with capture_segment_views(), and
compiles each view as the fragment pass does, with compile_overlays.py's own
helpers and the real recompiler. It requires:
- every PC each shard bakes, and its names, to be in its segment;
- the manifest's S and F records;
- ov_run's straight run to cost Beetle's fetch-model cycles: line leaders
  cached at KUSEG and KSEG0, +4 per fetch at KSEG1.

KNOWN_GAPS stays empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:43:46 -07:00
Shokunin 1c56a8b78c segment_testrom: line-align the probe call sites so the T2 deltas compare
With the delay-slot fix the Beetle deltas were sane but not comparable: the
three unrolled call sequences sat at different I-cache line offsets, and
probe_run shared a line with seeded, so the KUSEG run found its first line
already filled. Beetle read 59/59/89 (KUSEG/KSEG0/KSEG1), where the fetch
model predicts a 23-cycle KSEG1 surcharge.

Pad each call sequence so its first T2 read starts a line, and start
probe_run on its own line. Beetle (disc boot, OpenBIOS and SCPH-1001 alike)
now reads 56/56/82: KUSEG equals KSEG0, and KSEG1 exceeds them by 26 cycles,
exactly the Beetle fetch-model difference for the 15 KSEG1 fetches (60 vs a
cold cached 34).

probe_run moves to 0x000100F0. Ledger ids are unchanged; fetch-tag-segment
counts 30 tags and alias-fetch-coherence reads 22 vs Beetle 11, because leaf
now straddles two lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:20:52 -07:00
Shokunin ba18f992a5 segment_testrom: read T2 after the load delay slot and mask the delta to 16 bits
The Timer 2 subtraction sat in the second lw's load delay slot, so it read
the stale register, and the difference was not masked to T2's 16 bits. The
Beetle disc-boot run of the probe returned 0xFFFFFFF3-style values for
every delta. Add a nop after the load and an andi 0xFFFF.

The layout shifts by six words: probe_run moves from 0x000100C0 to
0x000100D8. The ledger ids are unchanged; fetch-tag-segment now counts 27
tags and alias-fetch-coherence reads 10 vs Beetle 5 for the moved leaf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:20:52 -07:00
Shokunin 9f8ee72f4d docs: design segment-aware code, with a KUSEG-linked acceptance ledger
Compiled code bakes KSEG0 into link values, CPS/IRQ resume PCs and I-cache
tags. KUSEG-linked EXEs run KUSEG PCs through those bodies (and their KUSEG
seeds are dropped), and overlay code executed at KUSEG/KSEG1 stays
interpreted after #417. Until #429, both emitters also charged the uncached
KSEG1 fetch only at cache-line leaders, so compiled BIOS ROM code was 4
cycles short on 5,477 of OpenBIOS's 9,592 KSEG1 instruction sites (Beetle
and the interp charge every fetch).

docs/SEGMENT_AWARE_CODE.md recommends per-segment compiled variants (code
identity = full VA, emitter segment as a per-compile constant, exact-segment
dispatch, per-instruction fetch in uncached bodies, segment-aware capture
and cache keys) over segment-relative emission, which measures +3.2 % /
+27.2 % __TEXT on R4 shards.

tools/segment_testrom/gen_segment_exe.py emits a synthetic KUSEG-linked
PS-X EXE that also works as an oracle probe. The new ctest
segment_aware_codegen runs the real recompilers on it and on OpenBIOS and
checks emitted PCs, the emitted dispatch lookup and fetch cycles (through
runtime/src/psx_icache.c) against a Beetle ReadInstruction transcription.
It passes only while the observed gaps equal its ledger (9 today).

#429 (rollout A) fixed the BIOS undercharge on master before this landed,
so KNOWN_GAPS does not list bios-kseg1-fetch-charge: the OpenBIOS check
finds no uncharged KSEG1 site and stays as a regression guard that reports
the id as a new gap. The last commit of this series brings the doc up to
date with #429.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:20:52 -07:00