pgxp: emit hook macros + dual build targets + flavor-namespaced caches (phase 2)

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>
This commit is contained in:
Matthew Stanley
2026-08-15 19:03:36 -07:00
parent 2ba74f3b4b
commit 38bdeeaade
17 changed files with 941 additions and 587 deletions
+5
View File
@@ -631,6 +631,7 @@ extern "C" void psx_pgxp_muldiv(struct CPUState *cpu, uint32_t instr,
extern "C" void pgxp_gte_push_sxy(int32_t x16, int32_t y16, uint16_t sz3,
uint32_t packed) {
if (!g_pgxp_active) return;
s_stats.produced++;
s_gte[12] = s_gte[13];
s_gte[13] = s_gte[14];
PGXPValue *pv = &s_gte[14];
@@ -735,6 +736,7 @@ extern "C" void pgxp_store_gte_reg(uint32_t addr, uint8_t reg) {
if (!dst) return;
const PGXPValue *src = &s_gte[reg & 31u];
if (src->gen != s_gen) return;
s_stats.swc2_stores++;
*dst = *src;
}
@@ -769,6 +771,9 @@ extern "C" void pgxp_test_get_gte_sxy(uint32_t index, uint32_t *packed,
extern "C" uint32_t pgxp_test_generation(void) { return s_gen; }
extern "C" uint32_t pgxp_test_suppress_depth(void) { return s_suppress; }
extern "C" int pgxp_test_active(void) { return g_pgxp_active; }
extern "C" void pgxp_test_set_generation(uint32_t gen) { s_gen = gen; }
/* Address-keyed depth lookup for the shipped perspective-texturing path