The overlay-region model assumed the boot EXE sits at the bottom of RAM:
[KERNEL_END, text_end) is main-EXE text, [text_end, RAM) is runtime-loaded
overlay code. That holds for a load_address of 0x80010000, where the text
base equals the kernel-window end and the region below the text is empty.
It is false for a boot EXE that loads HIGH and streams its gameplay code
into the RAM beneath itself. Klonoa loads a 46 KB stub at 0x80180000 and
runs its overlays from 0x10000-0x130000, so the floor landed at 0x18B000
and the entire overlay region fell below it:
- dirty_ram_clear_image_baseline() wiped the dirty bits across
[0x10000, 0x18B000) believing it was the clean compiled text image.
- the dirty_ram_dispatch_inner admit heuristic requires phys >= floor,
so a JALR into an overlay page the CD had DMA'd there (never touched
by the CPU write hooks, so never marked dirty) was refused by the
interpreter, fell through to psx_unknown_dispatch and fail-fast
exit(1) — Klonoa, frame 687, target 0x80123D00.
Pin the text BASE (g_text_image_lo) alongside the floor and route the
gates through one predicate: the overlay region is both sides of the text
image, not just above it. Street Fighter Alpha 3 (0x80113B00) and
Bomberman Fantasy Race (0x8003004C) load high too.
No-op for bottom-loading games: g_text_image_lo stays at its 0x10000
default, the below-text clause is empty, and the baseline clear starts at
the same page as before.
Klonoa now runs 6874+ frames at a locked 60 fps with fail-fast on and
zero unknown dispatches; it previously died at frame 687.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keep vsync/pacer XOR and skip the full-period wait while manual fast-forward already paces at the turbo multiplier.
Co-authored-by: Cursor <cursoragent@cursor.com>
Linux compositors wait a full refresh on SwapBuffers even after the pacer has already slept ~16.7 ms, which locked NTSC titles at 30 Hz / 0.50x with the CPU idle. Vsync now owns cadence only on ~60 Hz panels; otherwise the pacer holds 59.94 Hz and swap interval is forced to 0.
Co-authored-by: Cursor <cursoragent@cursor.com>
psx.enhancement.pgxp (game_id \"*\") in the builtin catalog: one Mods-page
toggle that arms sub-pixel vertex precision + perspective-correct
texturing with the user-validated defaults (tolerance clamp 0.5px), plus
a cpu-mode option. Default off = the faithful floor (G1.9). Fully
effective on PGXP-variant binaries; reduced-but-safe coverage elsewhere
(the always-emitted swc2 tier + interpreters, validate-on-read).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Interactive isolation on Ape Escape (in-game, live TCP toggles): OFF =
baseline jiggle; geometry ON unclamped = sparse hairline background-bleed
seams along corrected/uncorrected shared edges (both user-reported
artifacts vanished with the toggle off - the THPS2 line class, not wild
vertices); ON with tolerance 0.5 = seams gone, only sub-half-pixel
misalignment remains. Ship 0.5 as the default; negative still disables.
Also documents the screenshot_hires scale-2 windowed readback defect
(tiled/black PNG - row pitch) found during the session.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Titles that call psxrecomp_add_runtime_target directly (Ape Escape)
never went through the game wrapper, so the variant only existed for
wrapper callers. The clone now replays ARGN recursively at the end of
the target builder itself under PSX_PGXP_VARIANT, which covers every
caller; the wrapper folds an existing clone into its tail config and
the framework CMakeLists drops its now-redundant explicit block.
First real-title census (Ape Escape, worktree build vs this framework,
memory-mode only, boot->title->attract): 79-90% dataflow hits per
10s window vs the 5.2% position-cache ceiling, 0 value mismatches,
0 truncation rejects, every dataflow hit carrying depth; residual
native is 2D HUD/sprite content that must stay native. The G1.9
census gate is passed; visual screenshot_hires A/B requires a windowed
run (headless has no hi-res mirror - scale:1 fallback).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Emitter side of the value-propagation engine (ENHANCEMENTS.md G1.10):
- recompiler/src/pgxp_hook_emitter.{h,cpp} (new, in the codegen-hash
surface): ONE hook grammar shared by BOTH emitters, wrapping loads/
stores/COP2 transfers and precision-carrying ALU ops (moves, add/sub,
or-merge, shifts, LUI, HI/LO, muldiv) with PGXP_*() macros. Clobberable
sources are captured into locals before the statement. Precision-
destroying ops (AND/XOR/SLT/...) are deliberately unhooked - validate-
on-read drops their stale shadows for free.
- code_generator.cpp: central append in translate_instruction; LWC2/SWC2
emissions capture the RAW loaded/stored word (a masked GTE register
write must validate against the word as loaded).
- strict_translator.cpp: translate() wraps translate_impl()'s c_code with
the shared grammar; deferred load-delay variants hook the psx_ldd temp.
- BIOS regenerated, fingerprints verified CHANGED (SCPH1001 + OpenBIOS;
42.6k/12.2k macro sites). Base runtime + 33/33 tests green against it.
- Gating: macros expand only under -DPSX_PGXP=1. runtime.cmake grows a
PGXP option on psxrecomp_add_runtime_target (defines PSX_PGXP=1 +
PSX_OVERLAY_FLAVOR=2, _pgxp exe suffix) and PSX_PGXP_VARIANT to build
the sibling target from the same generated tree (framework runtime +
game wrapper). No ABI version bump needed: the appended PGXPHooks
table is NULL-tolerant and the flavor half of the ABI tag rejects any
host/DLL flavor mix.
- Shard caches: flavor folded into the cache tag (cg<V>_<hash>_gc<hash>
_f<flavor>) in overlay_loader.c + compile_overlays.py so base and pgxp
caches never share a directory; compile_overlays.py passes
-DPSX_PGXP=1 when flavor bit 2 is set; overlay preamble forwards
psx_pgxp_* through the table. PSX_OVERLAY_CODEGEN_VER 9 -> 10.
- Env overrides PSX_GEOMETRY_CORRECTION / PSX_PERSPECTIVE_TEXTURING /
PSX_PGXP_CPU_MODE (validation path: free-running headless boots arm
from the first vertex); census grew produced/swc2_stores and the pgxp
verb reports suppress/active gate state.
Validated: PSXRecomp_pgxp.exe boots the recompiled BIOS with hooks armed
(engine active, per-vertex lookups flowing; the BIOS shell has no RTPS
content so produced=0 there is correct - coverage measurement moves to a
3D title in phase 3).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keep recomp-net at occupied_mask (d65918f); master's pin was an ancestor.
Brings in rewind/save-state controls from master.
Co-authored-by: Cursor <cursoragent@cursor.com>