Runs a recompiled PS2 game against native middleware instead of emulated hardware.
Pure recompilation (PS2Recomp) gets the CPU right and then drowns in HLE: every game drives the GS, the VUs, the DMAC and the IOP differently, so every game needs its own pile of hardware emulation. Pure decompilation is accurate but takes years per title.
The hybrid approach cuts somewhere else. Not at the hardware boundary — at the middleware API boundary.
Silent Hill Origins is built on RenderWare Graphics 3.7 and RenderWare Physics
3.7 (confirmed from strings left in SLES_551.47: //Physics/Rwp37Active/...,
c:/silenthillps2/code/game/libs/RW/Graphics/src/RpPDS/sky2/...). So:
| layer | what happens to it |
|---|---|
| Climax game code | recompiled, runs as-is |
| RenderWare Graphics | reimplemented natively (OpenGL) |
| RenderWare Physics | recompiled — pure math, touches no hardware |
| zlib / JPEG | redirected to host libraries |
| Sony SDK | redirected to host equivalents |
PDS .csl VU1 microcode, GS packets, DMA chains, VIF, IOP |
deleted, not emulated |
This scales in a way a hardware-level seam cannot: RenderWare 3.x ships in hundreds of PS2 titles, so the native RW layer is written once and reused.
.text is 2116 KB / 7713 functions, split as:
| range | class | KB | functions |
|---|---|---|---|
0x100000–0x201400 |
game (Climax) | 987 | 4193 |
0x201400–0x225000 |
zlib / JPEG | 139 | 433 |
0x225000–0x294000 |
RW Graphics 3.7 + libm | 419 | 1264 |
0x294000–0x2a4000 |
Sony SDK / libstdc++ | 60 | 340 |
0x2a4000–0x2d8000 |
RW Physics 3.7 | 202 | 346 |
0x2d8000–0x32a434 |
Sony SDK | 307 | 1137 |
53% of the binary is not the game. And of those 3520 middleware functions,
the game only ever calls 599 of them — the rest are internal. That 599 is
the actual work queue, in data/sho_seam.json.
The binary is stripped and RenderWare release builds strip their assert strings, so none of this came from symbols. It came from two independent signals that agree: link order still holds (~87.5% monotonic between a function's address and the address of the strings it references), and instruction-class density gives the libraries away (RW Physics runs 26–60% FPU at ~1% call density — an unmistakable leaf-math signature).
ps2xCore/ guest execution substrate — memory, ELF loader, the runtime
ps2xSeam/ address→native-implementation binding, plus boot tracing
ps2xRW/ native RenderWare implementation (not yet populated)
ps2xHost/ window / GL device / input / audio (not yet populated)
ps2xApp/ boot harness
tools/ the static-analysis pipeline (Python)
data/ sho_segmentation.json, sho_seam.json
The recompiled sources call exactly nine runtime methods. That is the whole interface, measured across all 7713 functions:
| method | call sites |
|---|---|
dispatchGuestBranch |
40854 |
shouldPreemptGuestExecution |
5702 |
handleBreak |
342 |
Store8/16/32/64/128 |
195 |
handleSyscall |
156 |
Load8/16/32/64/128 |
112 |
SignalException |
50 |
executeVU0Microprogram |
40 |
clearLLBit |
2 |
PS2Recomp's runtime is ~43 kLOC because almost all of it exists to make the
hardware behave. ps2xCore implements the nine methods and links none of it.
ps2x/core/context.h, macros.h and address.h are vendored from PS2Recomp
and must not be "improved". The 174 MB of generated code expands those macros
and reads R5900Context fields directly; changing field order or macro
semantics corrupts everything silently. ps2_runtime.h and
ps2_runtime_macros.h are compatibility shims so the generated sources compile
unmodified.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j8PS2X_RECOMPILED_DIR points at the PS2Recomp output (default ../sho_recompiled).
# boot the game and write a report on where it got to
./build/ps2xHybrid ../original_iso/SLES_551.47
# print the unimplemented seam work queue, hottest first
./build/ps2xHybrid ../original_iso/SLES_551.47 --plan
# stop at the first unmapped branch target, for bisecting a hang
./build/ps2xHybrid ../original_iso/SLES_551.47 --abort-missingThe harness is headless on purpose. Nothing can render until the game reaches its own main loop, and it cannot reach the main loop until the boot path runs honestly from the ELF entry point.
python3 tools/xref.py # string cross-references
python3 tools/profile.py # instruction-class density per function
python3 tools/seam.py # call graph → data/sho_seam.json
python3 tools/mipsdis.py 0x2023d0 0x24cf18 # disassemble by addressThese are game-agnostic: point them at another RenderWare title and they produce the same segmentation.