Technical overview of how ps3recomp statically recompiles PS3 (Cell Broadband Engine) executables into native host code.
The PlayStation 3 uses the Cell Broadband Engine, which contains:
-
1x PPU (Power Processing Unit): A dual-threaded 64-bit PowerPC core (PPE) running at 3.2 GHz. This is the main CPU that runs game logic, OS calls, and orchestrates SPU tasks. It uses the Power ISA with VMX/AltiVec (128-bit SIMD) extensions.
-
6x SPUs (Synergistic Processing Units): Six available SPU cores (of 8 total; 1 reserved for the OS, 1 disabled for yield). Each SPU has its own 256 KB Local Store (LS) and communicates with main memory via DMA. SPUs run a custom SIMD-oriented instruction set, not PowerPC.
-
RSX (Reality Synthesizer): An NVIDIA NV47-based GPU with 256 MB dedicated VRAM and access to 256 MB of main RAM. Controlled via a command buffer (FIFO) written by the PPU.
-
256 MB main RAM (XDR): Shared between PPU and SPUs via DMA.
-
256 MB VRAM (GDDR3): Dedicated to the RSX GPU.
The pipeline transforms a PS3 ELF binary into native C/C++ source code that can be compiled for any host platform.
- Decrypt the SELF/ESELF container to obtain the raw ELF (
tools/decrypt_self.py). - Parse ELF headers, program headers, and section headers.
- Extract the
.text(code),.data,.rodata,.bsssegments. - Parse the
.prxrelocation tables and import/export tables (NIDs).
- Disassemble all executable sections using the PowerPC 64-bit instruction set.
- Identify function boundaries via:
- Symbol table entries
blr(branch-to-link-register) return instructions- Call graph analysis from
bl(branch-and-link) instructions - Pattern matching for function prologues (
mflr r0; stw r0, ...)
- Build a complete call graph.
- Identify basic blocks within each function.
- Reconstruct control flow graphs (CFGs).
- Detect and classify branch types:
- Direct branches (
b,bl) -- trivial targets - Conditional branches (
beq,bne,blt, etc.) -- if/else structures - Indirect branches (
bctr,bctrl) -- switch tables, virtual calls
- Direct branches (
- Recover switch/jump tables by analyzing the
r12-load +mtctr+bctrpattern. - Detect loop structures for potential optimization.
- Emit C source for each function:
- Each PPU register maps to a local variable (
uint64_t r0..r31) - CR (Condition Register) fields map to flag variables
- VMX registers map to
u128locals - Memory accesses go through
vm::read<T>()/vm::write<T>()with endian conversion
- Each PPU register maps to a local variable (
- Branch targets become
gotolabels or structuredif/while/switch. - Function calls to known addresses become direct C function calls.
- NID-resolved imports become calls to HLE stub functions.
- Generate a function pointer table mapping guest addresses to host functions.
- The generated C code is compiled by a standard host compiler (Clang/GCC/MSVC).
- Linked against the ps3recomp runtime library (memory manager, thread manager, HLE stubs).
- Produces a native executable.
PS3 uses 32-bit effective addresses (despite the 64-bit PPU, games use 32-bit mode). The runtime maps the entire 4 GB guest address space into host memory:
host_ptr = vm::g_base + guest_addr
vm::g_base is set at initialization to a large mmap/VirtualAlloc region.
PS3 is big-endian; x86/ARM hosts are little-endian. Every memory access in recompiled code passes through endian conversion:
be_t<T>wraps values stored in big-endian formatvm::read<T>(addr)reads from guest memory with byte-swapvm::write<T>(addr, val)writes to guest memory with byte-swap
Register-local computation stays in host-native byte order. Conversion only happens at memory boundaries.
| Guest Address Range | Region |
|---|---|
0x00010000 - 0x0FFFFFFF |
User ELF text + data |
0x10000000 - 0x1FFFFFFF |
PRX module space |
0x20000000 - 0x2FFFFFFF |
Stack / TLS |
0x30000000 - 0x3FFFFFFF |
Heap (user malloc) |
0xC0000000 - 0xCFFFFFFF |
RSX local memory (VRAM, mapped) |
0xD0000000 - 0xDFFFFFFF |
RSX IO-mapped main memory |
SPU emulation is the hardest part of PS3 emulation. ps3recomp supports multiple strategies:
Many games use Sony's SPURS framework or cellSync to dispatch SPU tasks. If we can identify and HLE the task types:
- Audio mixing (MultiStream, ATRAC3+): Replace with host audio decoding.
- Physics (Havok SPU jobs): Intercept and run on host CPU.
- Vertex processing (RSX vertex shaders uploaded to SPU): Skip; handle in the GPU backend.
- Decompression (zlib, LZ-based): Replace with host implementations.
A cycle-inaccurate interpreter that executes SPU instructions directly. Slow but compatible. Each SPU instruction is decoded and executed in a switch-case loop.
The same static recompilation approach applied to SPU programs found in the ELF. SPU code is typically loaded at runtime into Local Store, making static analysis harder. Hybrid approach: statically recompile known SPU ELF segments, fall back to interpreter for dynamically loaded code.
PS3 executables do not link against shared libraries by name. Instead, each exported/imported function has a unique 32-bit NID (Name Identifier) derived by:
NID = SHA-1(function_name)[:4] (first 4 bytes, big-endian u32)
The ELF's import table lists: (module_name, NID) pairs. At load time, the PS3 OS resolves each NID to a function pointer from the loaded PRX modules.
- Parse the ELF's import stubs to extract
(module, NID)pairs. - Look up each NID in a database (
tools/nid_db.json) to get the human-readable function name. - Replace the import stub with a call to our HLE implementation (e.g.,
cellFsOpen). - Unresolved NIDs log a warning and return
CELL_ENOSYS.
The NID database is derived from the RPCS3 project's function tables and Sony SDK headers.
The RSX GPU is handled by a three-layer translation architecture:
cellGcmSys (HLE) → RSX Command Processor → Graphics Backend
│ │
NV47xx FIFO parsing D3D12 / Vulkan / null
GPU state tracking Real rendering
-
cellGcmSys manages the interface between game code and the GPU: command buffer control, display buffers, memory mapping, flip/VBlank, tile/zcull configuration.
-
RSX Command Processor (
rsx_commands.c) parses the NV47xx FIFO command buffer and tracks GPU state: surfaces, viewport, blend, depth/stencil, textures (16 units), vertex attributes (16), shader programs, draw commands. -
Graphics Backend receives state changes and draw calls through the
rsx_backendcallback interface. Current backends:- Null: Win32 window showing clear color (debugging)
- D3D12: Real GPU rendering — device, swap chain, clear, present (Phase 1)
- Vulkan: Planned
See RSX_GRAPHICS.md for the complete graphics architecture, shader translation strategy, and primitive type mapping.
| Aspect | RPCS3 | ps3recomp |
|---|---|---|
| Approach | Dynamic emulation (JIT) | Static recompilation (AOT) |
| PPU | LLVM JIT or interpreter | C source generation, compiled natively |
| SPU | LLVM JIT or ASMJIT | HLE / interpreter / static recomp |
| RSX | Vulkan/OpenGL renderer | Vulkan/D3D12 renderer (shared concepts) |
| Compatibility | Broad (~70% of library) | Per-game (each game is a project) |
| Performance | Good, JIT overhead | Potentially better (fully optimized AOT) |
| Portability | x86-64 primary, ARM64 WIP | Any platform with a C compiler |
| Development | One binary runs many games | Each game needs analysis and customization |
| Memory | Dynamic guest memory | Statically mapped guest address space |
| HLE modules | ~100 modules, varying completion | 95 complete modules, full runtime |
| Use case | General-purpose emulator | Targeted game ports and mods |
The key tradeoff: RPCS3 aims for broad compatibility across the PS3 library. ps3recomp trades that breadth for potentially higher performance and easier game-specific customization (modding, patching, porting to new platforms).
For deeper dives into specific subsystems, see:
- RUNTIME.md — Complete runtime reference (VM, PPU/SPU contexts, type system, endianness, syscall dispatch, DMA)
- SYSCALLS.md — All LV2 kernel syscall implementations documented
- NID_SYSTEM.md — How PS3 function linking works, NID computation, module registration
- MODULES_REFERENCE.md — Detailed per-module documentation for all 93+ HLE modules
- TOOLS.md — Recompiler pipeline tools reference
- PLATFORM_ABSTRACTION.md — How Win32/POSIX differences are handled
- BUILDING.md — Build system reference and troubleshooting
- GAME_PORTING_GUIDE.md — Step-by-step guide to porting a PS3 game