# PS1Recomp
**Static recompiler for PlayStation 1 games -- translates MIPS R3000A machine code to native C++ for PC.**
## Overview
PS1Recomp converts PS1 game binaries into native PC executables through static recompilation. Instead of interpreting each MIPS instruction at runtime like a traditional emulator, it translates the entire game binary to C++ at compile time and links it against a hardware simulation runtime. The result is a standalone native executable that runs at full CPU speed.
```
PS1 ISO/BIN
|
v
ps1Analyzer -> game_config.toml (function boundaries, PsyQ signatures)
|
v
ps1Recomp -> recompiled_out.cpp (MIPS -> C++, ~150k lines per game)
|
v
ps1Runtime -> Native PC executable (SDL2 + OpenGL)
```
## Architecture
| Component | Directory | Description |
|-----------|-----------|-------------|
| **ps1Analyzer** | `ps1Analyzer/` | Parses PS1 ELF/BIN, detects function boundaries, identifies PsyQ SDK signatures, generates TOML config |
| **ps1Recomp** | `ps1Recomp/` | Decodes MIPS R3000A instructions and emits literal C++ translation (1:1 per instruction), handles GTE coprocessor and jump tables |
| **ps1Runtime** | `ps1Runtime/` | Simulates PS1 hardware: BIOS HLE, GPU (OpenGL 3.3), SPU (SDL2 audio), CD-ROM, DMA, GTE, MDEC, Timers, Input |
| **ps1Interface** | `ps1Interface/` | GUI studio for loading ELFs, exploring functions, editing configs, and previewing recompiled C++ (ImGui + SDL2) |
| **ps1Test** | `ps1Test/` | 557 unit + integration tests covering all runtime subsystems |
## Project Structure
```
ps1-recomp/
+-- ps1Analyzer/ ELF parser, function finder, PsyQ signature DB, disc reader
+-- ps1Recomp/ MIPS decoder, C++ emitter, GTE emitter, overlay handler
+-- ps1Runtime/ Full PS1 hardware simulation + SDL2/OpenGL host
| +-- src/
| +-- bios/ BIOS HLE (syscall tables A/B/C, heap, events, file I/O)
| +-- cdrom/ CD-ROM emulation (ISO 9660, CUE/BIN, virtual FS)
| +-- gpu/ GPU state machine + OpenGL renderer
| +-- spu/ Sound Processing Unit (24-voice ADPCM)
| +-- mdec/ Motion Picture Decoder (FMV video)
| +-- dma/ DMA controllers (Ch0-Ch6)
| +-- timers/ Hardware timers
| +-- psyq/ PsyQ middleware HLE (VSync, DrawSync, DrawOTag, etc.)
| +-- main_host.cpp SDL2 host: game loop, input, VBlank thread
+-- ps1Interface/ GUI studio (ImGui docking): ELF explorer, function inspector,
| | C++ preview, config editor, Ghidra CSV import
| +-- include/
| | +-- StudioState.hpp Async state management (analysis, config, exports)
| | +-- GUI.hpp 4 dockable panels + menu bar
| | +-- ui/StyleManager.hpp Dark/Light/Custom themes and font scaling
| +-- src/
| +-- main.cpp SDL2 + OpenGL3 entry point with ImGui docking
| +-- StudioState.cpp ps1Analyzer backend integration
| +-- GUI.cpp Panel rendering and keyboard shortcuts
| +-- ui/StyleManager.cpp
+-- ps1Test/ Unit tests (GTest): 557 tests across all subsystems
+-- third_party/ External dependencies: ELFIO, toml11, fmt, googletest
+-- tools/
| +-- extract_psyq_signatures.py Build the PsyQ signature DB from PsyQ SDK .LIB files
| +-- psyq_lib_extract.py Split SN Systems .LIB archives into per-function .OBJ
| +-- ps1_mcp_server.py MCP server for AI-assisted debugging
| +-- run_and_report.py Automated game diagnostics (VRAM, frame rate, logs)
| +-- validate_game.py Pixel-content validation against a frame budget
| +-- demo_build.sh Quick-start demo script
| +-- ghidra/ Ghidra integration scripts
| | +-- ExportPS1Functions.py Export function list from Ghidra to CSV
| | +-- ExportPS1Functions.java Same, Java version (headless mode)
| | +-- start_ghidra_mcp.sh Launch Ghidra with GhidraMCP on port 8080
| +-- pcsx_redux_mcp/ PCSX-Redux emulator integration (MCP server)
+-- .github/workflows/ci.yml CI/CD: build + test on every push
+-- CMakeLists.txt C++20 / CMake 3.20+ build system
+-- LICENSE GPLv3
```
## Building
### Prerequisites
```bash
# Ubuntu / Debian
sudo apt install cmake build-essential libsdl2-dev libgl-dev
# macOS
brew install cmake sdl2
```
### Clone and Build
```bash
git clone --recurse-submodules https://github.com/Dellareti/ps1-recomp.git
cd ps1-recomp
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
```
### Build with GUI Studio (optional)
```bash
cmake -B build -DCMAKE_BUILD_TYPE=Release -DPS1RECOMP_BUILD_INTERFACE=ON
cmake --build build -j$(nproc)
./build/ps1Interface/ps1Interface
```
### Run Tests
```bash
ctest --test-dir build --output-on-failure -j$(nproc)
```
## Running a Game (Rayman example)
> **Note:** Game disc images (ROMs/ISOs) are not included in this repository for legal
> reasons. You need your own legal copy of the game. The disc path is configured per-game
> and can point to **any folder on your system** -- there is no required directory name.
1. Place your disc image anywhere and note the path:
```
# Example paths -- use whatever works for you:
/home/user/games/Rayman (USA).cue
~/roms/Rayman (USA).cue
./my_games/Rayman (USA).cue
```
2. Analyze the binary and generate config:
```bash
./build/ps1Analyzer/ps1Analyzer "/path/to/Rayman (USA) (Track 01).bin.boot.exe" rayman_config.toml
```
3. Edit `rayman_config.toml` to set your disc path:
```toml
[disc]
cue_path = "/path/to/Rayman (USA).cue"
```
4. Recompile MIPS -> C++:
```bash
./build/ps1Recomp/ps1Recomp rayman_config.toml ps1Runtime/src/recompiled_out.cpp
```
5. Build and run:
```bash
cmake --build build -j$(nproc)
./build/ps1Runtime/ps1Runtime --config rayman_config.toml
```
## Controls
The keyboard stands in for a PS1 digital pad. The runtime prints this table on
startup, so it is always visible in the log of a run.
| Keyboard | PS1 pad | Keyboard | PS1 pad |
|---|---|---|---|
| Arrow keys | D-Pad | Q | L1 |
| Z | Cross | W | R1 |
| X | Circle | E | L2 |
| A | Square | R | R2 |
| S | Triangle | C | L3 |
| Enter | Start | V | R3 |
| Right Shift or Backspace | Select | Esc | quit |
Each press is echoed to stderr as `[pad] ->