Skip to content

Reference Projects PSXRecomp

Italo Dell Areti edited this page May 18, 2026 · 1 revision

Reference Projects: psxrecomp

Repo mstan/psxrecomp
Author Matthew Stan
License PolyForm Noncommercial 1.0.0
Console PlayStation 1
Reference game Tomba! (SCUS-94236) — playable end-to-end (gameplay + menu + FMV + audio)
Local clone PS1Recomp-workspace/psxrecomp/

The closest project to ours architecturally — another PS1 static recompiler, with a fully functional game shipping on top of it (TombaRecomp). Different threading model and stub strategy, but a goldmine of practical patterns.

Architecture sketch

psxrecomp/
  recompiler/         MIPS → C (exe → serial_full.c + serial_dispatch.c)
  runner/             Native runtime (linked by the game project)
    src/
      runtime.c           Memory map, BIOS stubs, fiber scheduler
      gpu_interpreter.cpp GP0/GP1 parser
      opengl_renderer.cpp OpenGL 3.3 backend
      gte.cpp             GTE coprocessor
      spu.cpp             24-voice ADPCM
      xa_audio.cpp        XA-ADPCM streaming
      fmv_player.cpp      STR v2 FMV decoder (via FFmpeg)
      cdrom_stub.cpp      Just opens the ISO and reads sectors
      overlay_manager.cpp Overlay management
      main_runner.cpp     GLFW loop, frame throttling
  tools/
    pcsx_redux_mcp/   MCP server for PCSX-Redux

Each game is its own repository that uses psxrecomp as a submodule and exposes a game_extras.h interface (display thread entry, EXE filename, expected CRC, per-frame hook).

Differences vs ps1-recomp

Aspect psxrecomp ps1-recomp
Target Windows (Win32 Fibers, MinGW) Linux (pthreads)
Threading Cooperative fibers (4 native fibers) Multithreading + drainPendingCallbacks
BIOS Inline stubs in runtime.c Separate bios.cpp module
Overlays Embedded MIPS interpreter for non-compiled addresses OverlayManager with separate dispatch
Recompiler rabbitizer + ELFIO Custom MIPS decoder (rabbitizer lacks GTE)
GPU backend OpenGL 3.3 OpenGL 3.3
MIPS decoder rabbitizer Custom

Lessons we already applied

TestEvent (B:0x0B) → return 1

PSX TestEvent returns "fired" immediately. On real hardware it would wait; psxrecomp returns 1, which breaks the CdInit retry loop. We do the same — see Architecture-BIOS.

GPUSTAT = 0x1C080000

The GPU always reports ready (bits 28/27/26 = GP0 ready, DMA ready, ready). A non-ready response would loop the game polling.

Scratchpad is its own buffer

Scratchpad (0x1F800000-0x1F8003FF) must be a separate 1 KB buffer, not g_ram[addr & 0x1FFFFF] — that would alias the low end of RAM and corrupt both. See Architecture-Runtime.

VBlank = fiber yield (their model)

In psxrecomp, every time the display fiber yields to main = 1 VBlank. That's more reliable than time-based counting. We use a dedicated VBlank thread that increments psyq_state().vsyncCounter at 60 Hz; same result, different mechanism. See Architecture-Integration.

Annotations CSV

psxrecomp lets each game ship a CSV mapping addresses to comments that appear in the generated C as /* [NOTE] */. We do not have this — TODO worth considering once we have more games.

What we want to crib later

SPU ADPCM

psxrecomp's spu.cpp has a working 24-voice ADPCM decoder with proper loop / end-of-sample handling. When we tackle the SPU accuracy gap (envelope, reverb, pitch modulation) this is a primary reference. See Architecture-SPU.

XA streaming

xa_audio.cpp handles streaming compressed audio off the disc. We do not have this yet; relevant for any title that uses CD-DA-style BGM (Tomba, Crash level music).

Memory card

runtime.c saves to C:\temp\memcard\ — basic but functional. We have no memcard UI yet (the save-state machinery exists in save_state.cpp but is not surfaced).

Snapshot system

F6 saves RAM + VRAM; F7 restores. Enables test automation — capture a known-good state, run, diff. Worth adopting.

Licensing

PolyForm Noncommercial 1.0.0 — free for non-commercial use with attribution. We can study and learn from it; we cannot copy code directly. All borrowed patterns are re-implemented from scratch (clean-room) here.

Clone this wiki locally