Add a conservative source-checkout setup helper based on the Linux quick-start intent from PR #54.
The script builds the CLI/recompiler tools, refreshes BIOS C when a BIOS is present, and builds the BIOS-only runtime only when BIOS/generated sources are available. It deliberately leaves game project creation to the existing CLI generator.
Co-authored-by: Keeganator <keegan.pan@gmail.com>
Remove the in-tree launcher implementation and its submodules now that game projects use recomp-ui for launcher support.
Keep Vulkan hidden from the launcher unless a game explicitly sets [video] offer_vulkan = true, and clamp stale Vulkan settings back to OpenGL when it is not offered.
Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Two independent failures made every live reshard fail SILENTLY (runs
counted, shard_ok stayed 0, the game just never got shards):
- autocompile.c: the child line is executed via 'cmd.exe /C <line>'.
When the line BEGINS with a quoted path and contains further quotes,
cmd.exe strips the first and last quote characters and mangles the
command ('The filename, directory name, or volume label syntax is
incorrect'). Wrap the whole line in one extra pair of quotes -- cmd
then strips exactly those and executes the inner command verbatim.
- launch_tomba2_interp_perf.ps1: the autocompile command used an
unqualified 'python'; with an MSYS python first on the inherited
PATH, it cannot open the Windows-style script path ('can't open
file'). Use the canonical Windows Python312 explicitly and fail the
launch loudly if it is absent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three-layer faithful-core fix for the exception-return contract, root-caused
live over TCP on a deterministic dbg-build repro (vblank authority vetoed
forever while the guest spun in the kernel idle loop, in_exception stuck 1):
1. Interpreter RFE backend parity: dirty-RAM RFE now calls
psx_rfe_mark_escape() exactly like the recompiled opcode and every
overlay shard (ABI v12), and dirty_ram_dispatch_inner takes a pending
escape at the committed transfer before local dirty flow can keep
interpreting the resumed code inside psx_check_interrupts' window.
2. Legacy-sentinel deliveries arm the escape too: the old blanket decline
assumed a sentinel delivery always resumes AT the sentinel, but guest
TCBs never hold the sentinel (Fix B anti-leak), so a kernel
ReturnFromException restore resumes at an approximate real PC with no
exit path armed. The take site preserves the legacy contract: a resume
landing ON the sentinel still exits through the sentinel detector.
3. Same-thread completion of a sentinel delivery via explicit RFE /
ReturnFromException converts to the legacy exit (restore interrupted
GPRs, pc=0, continue the live host chain) keyed on the structural
entry_tcb == exit_tcb test - otherwise the approximate TCB PC surfaces
up the trampoline, severs the live chain, and the run dies one hop
later on an un-re-enterable mid-function PC ("execution completed").
Validated: production build passes the previously-fatal splash transition
(frames 4717+ at 60fps, was deterministic death at 1385 x3 runs); dbg build
advances past the wedge (was frozen at exactly 1385); all runtime tests +
structural guards pass (guards extended to pin the interp RFE contract).
Known follow-up: the PSX_DEBUG_TOOLS build still loses one kernel CD event
through a third timing path at the same site - tracked as an open
foundation item; production config unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two changes to finish the interpreter-perf / AOT-investigation split:
1. Build dir switches from runtime/build-tomba2-perf-rel (configured
against the SHARED Tomba2Recomp checkout, CMAKE_HOME_DIRECTORY=
F:/Projects/psxrecomp/Tomba2Recomp) to the new isolated
runtime/build-tomba2-interp-iso-rel, configured against
_wt-tomba2-interp-perf (branch interp/game-isolated, forked from
Tomba2Recomp's master). That build passes
-DPSXRECOMP_GAME_EXE_NAME_OVERRIDE=Tomba2InterpPerf, so it emits
Tomba2InterpPerf.exe natively. The old build-tomba2-perf-rel is left
untouched on disk as evidence of the original measurement; only this
script's target moves.
2. Drops the Copy-Item alias hack: since the isolated build already
produces the isolated exe name directly, there is nothing left to
alias.
3. GameRoot now defaults to the isolated game worktree instead of the
shared Tomba2Recomp checkout, so this script no longer reads
game.toml from a tree whose HEAD (feat/aot-overlay-spike) belongs to
a different investigation and has already drifted from master
(overlay_capture_history).
4. The pre-launch guard now refuses to start if EITHER Tomba2InterpPerf
OR Tomba2Recomp is already running (previously only checked its own
process name) — the two builds can no longer collide on disk, but
still share the BIOS file, debug-port range, and taskkill-by-name
cleanup surface.
State paths (memcards/captures/logs/overlay cache) were already scoped
under _wt-interpreter-perf and are unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
extract_generic: supplement prologue seeds with the overlay's OWN export/dispatch
table (the header pointers) as dispatch entries — the game's authoritative
entry-point manifest, on the disc, play-free. compile_overlays classifies mid-fn
targets DISPATCH_INTERIOR aliases. Honest note: no-op for Tomba 2 (skipped=23) —
the recompiler's control-flow walk already reaches those entries; kept because it
helps engines where the walk cannot.
coverage_report.py (new): measures play-free static-extraction RECALL against a
played vault (most complete needed-set) and/or a live-session captures json, and
persists a durable gap manifest (misses grouped by region). Tomba 2: 60.0%
entry-level recall vs vault (1113/1856), 743 misses dominated by MAIN.EXE
frameless/indirect functions + the kernel region.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The old delta-sweep matched export-table pointers against 0x27BD prologues,
but those pointers point at mid-function DISPATCH entries, not prologues
(measured: 0/29 hit a prologue at the true base). It scattered bases by
2-16KB and decoded data as code.
Fix: j/jal targets are BASE-INDEPENDENT (0x80000000 | (imm26<<2), since all
game code lives in 0x800xxxxx). At the true base, the maximum number of
intra-overlay jal targets land on a real prologue. recover_base() votes every
(jal-target, prologue-offset) pair for base t-o within the pointer-containment
window; the peak is unique and sharp (~2x margin). Records are emitted
page-aligned with a FILL prefix, because the runtime keys shards by a
page-aligned region_start and compile_overlays takes load_addr verbatim.
Weak-signal files are skipped (score<4 or <1.5x runner-up) -- safe coverage
loss under the per-function code_crc dispatch guard. Also dedup overlays by
content CRC (position-fixed BINs are reused across AREA folders).
Validation: generic output is byte-identical (base, region envelope, seed set)
to the live-proven tomba1_extract.py hand tool for ALL 22 Tomba 1 overlays,
with no hardcoded constants. Tomba 2's 21 A*.BIN overlays converge on a single
consistent base 0x80108F9C (region 0x80108000 +3996).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>