A capture view is compiled at `segment | phys` in whichever segment its
entries ran (docs/SEGMENT_AWARE_CODE.md §5.7), but the recompiler matched
the game config's exact-match code sites as spelled. The config names
overlay code by its bytes, which run in any segment. The runtime keys mod
function-entry hooks by physical address, and the interpreter fires them at
every entry, whatever its segment. So a KUSEG or KSEG1 shard of a hooked
overlay function emitted no psx_mod_function_entry call: the hook fired on a
cold cache (interpreted) and not on a warm one (the new shard).
overlay_codegen_config() (segment_variants.cpp) moves every exact-match
site kind that D's rebase_codegen_config() moves, and whose physical address
lies in the image in a segment that maps RAM, into the view's segment. It
shares the site list with rebase_codegen_config(), which keeps its
link-segment match and its split pre-pass setting. main_psx applies it in
overlay mode. A KSEG0 view with KSEG0-spelled sites, as every pre-§5.7
overlay compile has, is unchanged.
Tests:
- segment_variants_test checks overlay_codegen_config() in each segment's
view: sites spelled in any RAM segment move, and addresses outside the
image, KSEG2 and 0x20000000-0x7FFFFFFF spellings and the physically
matched kinds stay.
- overlay_segment_keys compiles a v3 capture entered at all three segments
with mod_function_entry_funcs spelled at KSEG0 and KSEG1. Every segment's
shard must emit both hooks at its own PCs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A seed that names the image's bytes in another segment than its link
segment (0xA00100F0 for a KUSEG-linked EXE, 0x00012345 for a KSEG0 one)
now compiles a segment variant (docs/SEGMENT_AWARE_CODE.md §5.4): the home
functions the seed reaches through direct edges (calls, tail jumps, split
pieces, fall-throughs, call returns; a seed at a CPS continuation roots its
owner, an alias entry its alias group) are compiled again through a view of
the image in that segment. The variant's names, rows and every PC it bakes
are that segment's, and a KSEG1 variant charges a fetch per instruction
(#429's rule through B's runtime_pc()). A cached variant is the home C with
the segment swapped. Exact-match config sites move into the variant's
segment, so a variant gets every hook the home body gets. A seed that names
no home dispatch entry stops the build, and so does a seed in a segment
that does not map physical memory (0x20000000-0x7FFFFFFF or KSEG2: Beetle's
addr_mask leaves them unmasked, so they address no RAM and are no alias of
the image's bytes).
tools/collect_game_misses.py reports such a segment miss instead of writing
it as a seed.
The dispatch table holds a row per compiled segment of a word, adjacent and
in PC order; when any word has more than one row the lookup (indexed and
binary search) searches the word's rows for the exact PC. Two rows for one
PC remain a build error. A title without variants gets the same dispatch
source as before.
A jump-table case whose value is in another segment than its body is no
longer a local case: the default tail-transfer dispatches it with its full
PC. This applies to every compile. In a variant it is the common case (a
KSEG0 variant of KUSEG-linked code). A home or overlay compile has one only
when its table holds another segment's PCs of its own bytes, for example a
KSEG0-compiled overlay shard of code that runs at KUSEG. Such a case used to
continue in the KSEG0 body with KSEG0 links and fetch tags. Now it
dispatches: a game-text PC with no row in its segment is a recorded segment
miss, and #417's gate sends an overlay PC to the interpreter; both run it
at its own PC (PR E returns overlay code to native per-segment shards). R4's
game C and its 26 overlay shard sources are unchanged.
Ledger: segment-variants and kseg1-fetch-charge close (KNOWN_GAPS is empty)
and become regression guards; resume-pc-segment now requires each row's key
and resume PC to be in its body's segment, and segment-variants checks every
PC a variant body bakes. New segment_variants_test; kuseg_dispatch_lookup
and emitter_runtime_pc_test cover variant rows, closure, equality with the
home C, per-instruction KSEG1 charging, foreign jump-table cases at home and
in variants, data stubs (no row), alias groups declared for every shard and
seeds outside the physical segments.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>