ps3recomp exists because people who love the PS3 keep showing up. Thank you to everyone who has contributed code, fixes, testing, or a hard-won debugging insight. This file is the canonical record of who did what; the README changelog tells the story version-by-version, but credit lives here.
If you've contributed and aren't listed (or a line is wrong), open a PR against this file — we want every name right.
Ned Heller — @sp00nznet
Project creator and maintainer. Core toolchain (PPU/SPU disassemblers and lifters, ELF/SELF/PRX parsing, NID system, runtime libraries and system-call layer), the recompilation pipeline, and the batch-triage harness.
Caner Saka — @canersaka
Found and fixed a remarkable run of correctness bugs while stress-testing the toolkit against a 22 MB / ~45,000-function Yakuza: Dead Souls port — which turned out to be an excellent fuzzer for everything the pipeline got subtly wrong. Landed in v0.6.1 "Many Hands":
Decode & lift correctness
- NID computation fix — the suffix constant was truncated/corrupted and the digest was read big-endian; corrected to the authoritative 16-byte suffix + little-endian. Took NID resolution on a real game from 0/354 to 343/354.
- VMX/AltiVec decode tables — cross-referenced against the Power ISA manuals; fixed dozens of mnemonics mapped to the wrong opcodes that were decoding silently and lifting to valid C for the wrong operation.
- VMX lifter handlers —
addc/subfcwith carry-out into XER[CA], the unaligned vector loadslvlx/lvrx/lvlxl,ldbrx,vsrw,vsububs,vsum2sws,vupkhsh,vrfim, and a missingvanddispatch entry. sradidecode for shifts ≥ 32 — the 6-bit shift's top bit lives in instruction bit 30, so the XO field reads 827 for shifts of 32+.- Function detection seeded from the
.opdtable — seeds starts from every address-taken function descriptor (located by shape, since section names are often stripped), bounds them at the firstblr, and filters phantom branch targets. A large improvement to coverage of pointer-only/virtual functions.
Lifter throughput
- Parallel lifting (
--jobs N) across a process pool, chunked C output, and record-form CR0 handling — turned a multi-hour single-core lift into minutes.
Runtime & libraries
sys_vmsyscall family (300–313) implemented from scratch.sys_memoryallocations from a committed-on-demand window matching real-hardware addresses, plus thread-safe bump allocation.sys_lwmutex_destroylv2-correct ESRCH/EBUSY semantics + slot locking.- TTY syscall numbers corrected to 402/403.
cellVideoOutbig-endian guest structs + correctedCellGcmContextDatalayout.
Build & tooling
- Excluded runtime test harnesses from the library build (clean MSVC build).
tools/show_func.py— dump a single lifted function's C and/or its original PowerPC disassembly from the chunked output.
Also incorporated (v0.6.4 "Carry the One") — the PPU XER[CA] carry/borrow
bug class (shift-algebraic sraw/srad forms + mtcrf mask, #21;
subfe/subfme/addme, #26), cntlzw(0) = 32 (#35), the PPU lifter
conformance suite (#37), and the vcmpgt* handlers (#39); the SPU
computed-bi $r0 tail-jump classifier (#36), self-referential branch
mislift fix (#30), full SPU ISA coverage (#31), byte-correct quadword helpers
(#32), il double sign-extension (#33), and preferred-slot link register +
rchcnt (#34); plus mftb/mftbu reading a real timebase (#38).
Also incorporated (v0.6.5) — cellFs big-endian out-params + CellFsStat
PS3 packing (#22), cellGame title id read from PARAM.SFO (#24), sys_rwlock
EDEADLK/EPERM lv2 semantics (#25), the crnor/crnand opcode-33/225
disassembler fix (#40), and static firmware LLE (tools/lift_prx.py) —
relocating a decrypted PRX to lift a real firmware module (e.g. the libsre
SPURS kernel) instead of HLE-ing it, under a bring-your-own-firmware model
that ships nothing derived from firmware (#53).
Also incorporated (v0.6.6 "Two Ports, One Toolkit") — fsqrt/fsqrts
source-register decode + vspltis signed-immediate printing (#46), the
addeo/subfeo/mulhwo/mulhwuo overflow forms + vupklsb/vupkhsb/vupklsh
unpacks (#52), sub-millisecond sys_timer usleep (#44), cellNetCtl big-endian
out-params (#45), and cellAudio period-event delivery to notify queues (#54).
Also incorporated (v0.6.7 "Fine Print") — NV40 VP/FP shader-decompiler
hardening (#47), spu_disasm channel-width/hbr/bisl-link/ri7 fixes (#49),
sub-millisecond timeouts for event-flags/semaphores/mutexes (#50), corrected HLE
ABI signatures across cellPamf/Sail/Http/Ssl/Net/sysNet/sceNpTrophy/cellGameData
(#55), and a lifter/HLE audit toolkit + lv2 sync stress test (#56).
Also incorporated (unreleased) — a PPU/SPU correctness batch, several of which were silent-miscompile classes rather than crashes:
- VMX element-wise ops read big-endian lanes — values were byte-reversed on x86, so every float lane op quietly computed on the wrong data (#74).
- D-form loads/stores treat
rA=0as a literal zero base, notGPR[0](#72). - Update forms write back
rA— indexed stores (#71) and FP loads/stores (#73); dropping the write-back leavesrAstale and corrupts every subsequent(rA)-relative access. lmw/stmwload/store multiple word (#68),mulldooverflow form (#70), andstvlx/stvrx/stvlxl/stvrxlCell unaligned vector stores (#61).- Value-verified CAS for
lwarx/stwcxandldarx/stdcx(#62). - FP correctness batch —
fcmpuNaN ordering,fctisaturation, single rounding,vctsxs/vctuxs(#60); plus the objdump decoder audit that found 5 missing VMX float ops. - SPU:
brsltarget parse broken by the disasm link-register fix — every call lifted as a silent no-op (#58);bisl/bisledtarget register is the last operand; single-roundfma/fms/fnms,fesd/frdsfrom the left word slot, andfi/frest/frsqestbase+step interpolation (#51). - lv2:
sys_mutex_trylockrecursive fast path pairs the host critical section (#67);sys_spu_thread_group_createreads r5 as priority and the name from the attr struct (#66).
Also incorporated (unreleased, folded via integrate/fold-2026-08-14) — a
guest-ABI and lv2 batch:
- Guest callbacks receive r3 through r10 — the dispatch hook only plumbed four arguments, so any guest callback taking more than four read stale registers (#86).
- One authoritative lv2 semaphore count — the count lived twice (in
sys_semaphore_info::valueand in the Win32 handle), so timeout/wake races could lose tokens or park a waiter whilevaluewas already positive.valueundervalue_lockis now the only count, the handle is a wake channel, and overflow returns the lv2CELL_EBUSYinstead ofCELL_EINVAL(#88). cellFsReaddirwrites the real 258-byte dirent ABI + a corrected CellOS generic error-code table (#85).cellGamefirmware parameter IDs, error values and buffer bounds matched to the SDK (#84).- SPU
sync/dsync/synccemit real host memory fences, with thesyncC bit decoded instead of folded into plainsync(#87). cellAudioclears each consumed ring-buffer block, so an underrun replays silence rather than the previous block (#83).- Plus the
sync_stresslv2 target wired into the build, so the semaphore behaviour above stays executable outside a generated title (#88).
The live RSX draw engine (v0.10.0 "Three Platforms") — a second, independent
draw engine beside the one @sagemono built, brought
upstream from the Yakuza: Dead Souls EX
port (#113). It executes the guest's NV4097 command stream as it arrives
rather than replaying a recorded frame. rsx_live_draw.c, rsx_dispatch.*,
rsx_vertex_compact.*, rsx_restart_cuts.h and the vertex/fragment-program
decompiler updates are his work; it is opt-in behind RSX_LIVE_DRAW, so the
existing backend path is untouched when it is off. A second title driving the
same engine then needed the FIFO subchannel treated as a binding slot rather
than an engine selector, HDR (F_W16Z16Y16X16) colour surfaces, and
fragment-output NaN guards — all on top of his engine, not in place of it.
The 2026-09 batch (#152-#161), from getting Yakuza: Dead Souls running on a Mac
- Lifted SPU threads — a thread runs its own lifted image in its own architectural context, with lv2 copy semantics for the four thread arguments (games reuse one guest args block across a group and rewrite it between calls, so reading it lazily hands every thread the previous thread's values) (#152).
- lv2 condition signals retained; static guest mutexes registered (#153).
- cellAudio — guest ring indices wrapped, block tags and timestamps provided (#154).
- cellSysutil — dialog completions delivered from the guest callback poll (#155).
- sceNpTrophy first-use slots and registration completion (#156); cellGame content-volume space and guest paths (#157); cellSaveData callback ABI and guest file-request execution (#158).
- RSX: full FIFO driver methods, serialized callbacks and MRT exports (#159).
- macOS native host, Metal rendering and game runner (#160) — the second platform backend, and the reason aarch64 is proven rather than assumed.
- sceNp local score service initialized while offline (#161).
Jonathan Del Corpo — @JonathanDC64
Correctness and robustness fixes distilled from a Demon's Souls port that stress-tested the toolkit against a ~106k-function title. The title-agnostic wins incorporated (v0.6.6):
- SPU cross-function tail calls forced with
musttail— a guest loop whose back-edge crosses a lifted-function boundary was nesting one host C frame per iteration and silently overflowing the stack (a stack-overflow SE runs no unhandled filter, so the process died with no crash log and exit code 0); now an O(1)-stack jump under clang, with a call+return fallback elsewhere. - Mid-function / gap lifting sliced O(n²)→O(span) — turned a ~40-minute no-output hang on 96k+ function titles into bounded work.
sys_event_queue_receivereturns the event in r4–r7 (lv2 ABI) — callers that read the registers instead of thesys_event_t*buffer saw stale values.sys_memory_get_page_attributerenumbered 358→351 (0x15F) and implemented.CellFsStatruntime-side layout corrected to the 52-byte / 4-byte-aligned ABI, fixing theppu_fs.cpp/sys_fs.cstat writers the v0.6.5 libs-side fix didn't cover.
Further title-agnostic fixes incorporated (v0.6.7):
g_active_ctxrestored after guest callbacks — it was left pointing at a stack-local scratch ctx, so after any callback the current-thread ctx pointer dangled and corrupted the crash handler / diagnostics; applied to bothppu_guest_callandppu_guest_call_ct.- SPU
stopsignal code preserved to a newctx->stop_code— SPURS leaf tasks invoke kernel syscalls viastop <code>(EXIT/YIELD/WAIT/POLL/…), which the lifter was discarding. cellGameDataCheckCreate2(NID0xC9645C41) implemented — marshals StatGet/StatSet and fires the guestfuncStatcallback.
(The port's remaining fork-specific work — SPU/PPU jump-table discovery tuned to a different lifter architecture, and cellKb/Mouse/Rtc guest-pointer translation that needs a big-endian rewrite — is tracked for a follow-up with a re-lift/test loop rather than a blind port.)
sagemono — @sagemono
Real-controller correctness surfaced by a DualShock-as-XInput bring-up (v0.6.5):
- cellPad DIGITAL2 packing —
hs->buttonscarries DIGITAL1 in its low byte and DIGITAL2 (the face buttons cross/circle/triangle/square + L1/L2/R1/R2) in the high byte; the whole value was being written into DIGITAL1 with DIGITAL2 forced to 0, so every face button was dead. Split correctly (#42). - analog-Y centering — reflect the inverted Y about 128 (
256 - x) instead of255 - x, which turned a centered stick into 127 (0x7F, aliasing SELECT+START self-exit + TRIANGLE).
The RSX draw engine and the toolchain work behind it, developed across a homebrew TUI (cellmark), vkcube, wave, and a PSL1GHT/Tiny3D bring-up (unreleased):
Rendering
- 2D/dbgfont pipeline + vertex-program capture, then executing the title's real NV4097 vertex program on D3D12 for pixel-perfect text (#43) — grown from there into guest fragment-program pipelines, per-draw textures and VP constants, indexed draws, render-to-texture, MRT, multi-unit textures, FP predication and branches, float RTs, and a VS cache keyed by ucode hash.
- Present correctness — present only on guest flip (partial-frame flicker), present at the clear boundary (ring-wrap blink), flips ordered against the drain, honest flip status, synced non-blocking flips.
- FIFO ring recycle on wrap — the command ring never recycled (the callback OPD was null), wedging ~200 frames in; a real command-buffer-full callback now drains and resets it.
cellGcmSetFlipCommandcontext argument,MapMainMemorynever handing out IO offset 0 (FIFO collision), back-end label byte-swap, and discrete-GPU selection by default.
Lifter & toolchain
blrldispatched as an indirect call — it was lumped withblrand emitted a barereturn;, dropping the call and skipping the frame epilogue, sor1leaked the frame size on every function-descriptor call (#42).- EBOOT (
ET_EXEC) import parsing — the lib-stub table was only reachable via the PRX module_info path, so every retail main executable reported 0 imports; now located viaPT_PROC_PRX_PARAM. Minecraft: 0 → 345 NIDs across 30 modules (#41). lift_functionindexed by address — an O(refs·N) mid-function pass hung the lifter indefinitely after "100% lifted" on large titles (~11.6k refs × 3M instructions); now bisect over a cached sorted index (#41).- Rotate-by-0 undefined behaviour in the rotate helpers —
v >> (64 - n)at n=0 is UB, and clang miscompiled theclrlditruncation idiom that every 32-bit address/index cast lowers to (#41). - Function-registry sizing for >64k-function titles, jump-table switches as in-function computed gotos, multi-TOC jump-table discovery, and callee-save detection that rejects a reused save slot / scratch spill.
- Lifter torture suite — 3793 KATs against an independent PPC model (#64),
plus the fused-fmadd / PPC NaN /
mfspr/mtsprsemantics it surfaced. sys_spu_image_importimplemented (SPU ELF → entry point + segment table) and the SPU image syscall numbers corrected (#57).
A guest-ABI HLE correctness batch, mostly surfaced by LBP and DeferredShading
bring-ups (folded via integrate/fold-2026-07-24):
- Guest-EA / big-endian out-param marshalling across the HLE surface — a run
of handlers were writing host pointers or native-endian values into what are
actually guest VM addresses:
cellUserInfo(overflow), trophy u64s,cellGameGetParamIntDISC type, open PSID,cellRtc, save-data user paths,cellJpgDecDecodeData,cellPngDec(first live use, DeferredShading), and thecellAudioread index as a BE u64. cellFsSdataOpenwith real SDATA/EDAT (NPD) decryption,cellFsMkdir+ the game-data dir created where the VFS actually looks, and a/dev_hdd0overlay onto the installed-update tree (PS3_HDD0_ROOT).- Honest state, not silently-faked CELL_OK — a module name that matches no
file now fails; net reports a real offline state with real SDK NP error codes;
sys_time_get_system_timereturns real microseconds instead of a call counter. - Raw-
sys_fspath parity — strip mount prefixes so rawsys_fsopens hit the same host tree as the cellFs layer;cellHttpCreateClientguest-EA translation (fixed a boot crash); HLSL-safe NaN/Inf fragment-program constants;sys_spu_image_importsegment source EA at the correct offset.
The SPU-lifter "faithful adoption" (branch spu/faithful-adopt-caner, folded
via integrate/faithful-adopt-caner) — a from-scratch re-implementation of the
SPU decode/lift + runtime, consolidating the interpreter and function registry
into spu_channels.c, plus LBP SPU/SPURS bring-up and RSX texture support
(G8B8/DXT, deswizzle). This work re-adopts the original SPU decoder/lifter and
runtime that @sp00nznet and
@canersaka authored — their commit history for
that work stands on its own (the caner/ppu-*, c6*/c7*, and the core SPU
subsystem commits); the faithful-adoption branch is a parallel re-derivation, and
credit for the underlying design belongs to them.
The 2026-09 cellGame batch, from LittleBigPlanet
- cellGame content root — the host directory
/dev_hdd0/gamemaps to has to be the same oneppu_fs.cppresolves that mount to. When the two disagreed, a title wrote its game data into one directory and read it back from another, found nothing, and reported the data as corrupt rather than missing (#163). cellGameContentErrorDialogimplemented (#162), and the per-build LBP SPU sources made optional (#164).
This batch also surfaced a gap nobody could have found alone: with it, Twisted
Metal reaches cellGameCreateGameData for the first time, and that path calls
cellGameSetParamString, which nothing implemented. Exactly the kind of thing a
port owner cannot see from inside their own title.
The 2026-09-10 SPU lifter and EDAT batch
bi $rNclassified by basic block, not by function —compute_link_returnsbounded both backward scans by the enclosing lifted function, but the lifter splits long straight-line runs into several functions that chain by fallthrough, and a split is not a control-flow edge. A scan that stops there stops mid-block, having seen only part of it, which defeats the predecessor refinement the function already does (#169).hbra/hbrrdecoded as the 7-bit opcodes they are — onlyhbris the 11-bit RR form; testing the other two against a 9-bit field can never match, so a stub carrying a branch hint decoded to UNKNOWN and the SPU fell into branch-to-0. Found independently of the identical fix already in the tree, from a different witness (#166).--extra-funcspassthrough inbuild_spu_workloads(#165) andlift_jobmods(#170). An SPU address reached only by an indirect branch is invisible to--auto-functions; an image entered by an interrupt vector has no branch path from its entry point at all. The job modules need it most — they all stream into the same LS 0x4000 buffer with one resident at a time, so a BRANCH-TO-0 names an address with no module attached to it.- EDAT license types 1 and 2, and the 0x08/0x10/0x20 flags —
edat.chandled only self-keyed SDATs and license-type-3 "free" EDATs with one of four public klicensees, refusing everything else up front. Adds the missing HMAC-SHA1 hash modes 0x01 and 0x04 alongside the AES-CMAC mode 0x02 that was there (#167). - List-DMA issue tracing — a list DMA takes its own path through the MFC and
never reaches
mfc_do_transfer, so the always-on per-transfer trace never saw one. Two lines that turn a run where everything downstream depends on a single invisible list command into something you can read: the destination LSA at issue, and what a stall handler leaves behind (#168).
The 2026-09-16 WWS job-manager batch, from LittleBigPlanet
bi $rNthrough a non-r0 link register returns through that register (#174) — Sony's compiler links through r4/r5/r6/r8/r78 as well as r0, andSPU_RETalways took r0, so every such return unwound the host stack and the job manager restarted on every job.lift_jobmodsseeds the entries modules reach only through data (#175) — the post-header stub and the hand-built return addresses that 46 of 47 job modules use.- SPU drain resumes at a lifted entry and unwinds an
iretto the frame that took the interrupt (#176). - The taskset syscall HLE'd for a standalone task on a planted context (#177) — LBP's audio tasks died on their first syscall and the loader waited forever on their event flag.
_sys_spu_image_importwrites the segment source at +0x10 (#178) — the FMOD mixer DMA'd its DSP overlay from EA 0 and jumped into zeroed local store.
Paulo Adriano Alves — @pauloadrianoalves
Initial PPU boot path and supporting tooling (PR #3, partially incorporated in v0.6.2 — the SPU portions were superseded by the v0.6.0 SPU subsystem and not taken):
- PPU boot scaffold —
runtime/ppu/(loader, HLE dispatch, sysprx, fs) +runtime/host/host_main.c: the per-game path that loads a lifted PPU image, links it with the HLE runtime, and boots it. Compiled per-game against the lifter-generatedppu_recomp.h, so it lives outside the game-agnostic runtime library build. - RSX shader decompilers —
libs/video/rsx_fp_decompiler.*andrsx_vp_decompiler.*: NV40 fragment/vertex program → host shader translation, with a validation-test corpus. - Tooling —
tools/ppu_loader.py(image manifest / OPD table / TOC / imports extraction) andtools/gen_hle_nids.py. - Docs —
docs/PPU_RECOMP.md,docs/RSX_FRAGMENT_PROGRAM.md.
gnome41 — @gnome41
While porting DBZ Budokai HD, gnome41's fork surfaced and fixed real bugs in the shared SDK that have been incorporated upstream:
- the AltiVec VX-form 11-bit XO extraction fix (~3,800 instructions were mis-decoded);
- 19 additional VMX integer lifter handlers +
crorc/crandc; - SPU decoder corrections (RI16 branch forms, channel opcodes per the IBM Cell BE manual);
- a
find_functions.pywalrus-syntax fix.
Lucas Picoli — @LucasPicoli
- Linux/GCC build fixes — glibc's
st_atime/st_mtime/st_ctimemacros were shadowing identically namedCellFsStat/CellSaveDatamembers; five translation units now compile clean so downstream game projects get a Linux runtime to link against. (v0.6.1)
slushiimusic — @slushiimusic
Gave the project its first CI and its second platform, in v0.9.0.
- macOS is not actually supported, and said so with receipts (#94) — the docs advertised Apple Clang 14+ under "full support" while the runtime failed to compile on arm64 with 77 errors. Filed with the errors and a fix.
- arm64 macOS build + the first CI this repository has ever had (#95).
Its value was immediate and slightly embarrassing: it failed 17 seconds after
landing on a
getenvwithout<stdlib.h>that MSVC had been quietly accepting, and again on Win32 timing APIs used unguarded. - RSX → Metal backend, POSIX host, and the draw path (#96) — a second
graphics backend beside D3D12: clear, flip, guest vertex fetch, a
pipeline-state cache and blend translation, windowed or headless.
runtime/host/host_posix.cdrives cellGcm → RSX → backend with no lifted game, hand-building a big-endian NV4097 command buffer — which is what makes non-Windows graphics work startable at all. - The CI those PRs brought asserts the presented pixel rather than an exit code, and running the existing lifter suites under it immediately exposed fifteen silent VMX miscompiles that had been in the tree unnoticed.
lilbeefaroni — @lilbeefaroni
- Caught the porting guide documenting flags that do not exist (#93) —
elf_parser.py --output/--decrypt. Both were wrong, and auditing every documented command against its tool's real argument parser turned up four more in the guide and two in the README. Fixed.
tomspilman — @tomspilman
- Found
spu_lifter.py --header-namesilently ignored (#181) — the flag set the output filename but the emitted#includestayed hardcoded tospu_recomp.h, so any image lifted under a custom header name produced a source file that could not compile. Every in-tree caller happens to pass the default, which is exactly why it survived: a flag that only breaks for the second person to use it.
Filedownloader-tech — @Filedownloader-tech
- Build failure report with a full log (#89) — the kind of report that can actually be acted on.
gabryboy12-ai — @gabryboy12-ai
- Put Linux and macOS back on the build (#191) — three recent commits had
reached for Win32 API that GCC/Clang builds do not have (a bare
__declspec(thread),LONG/InterlockedExchange/Sleepoutside_WIN32, andGetFileAttributesAin two diagnostic gates), so master stopped building off Windows. Fixed each the way the file already did it, and gave the compat layer a POSIXGetFileAttributesAwith a test. - A Vulkan RSX backend (#182, #192) — Linux had no renderer. Opt-in,
libvulkanloaded at run time, Vulkan 1.0 core only: clears, the fixed-function fallback path, depth, textures and an SDL2 window first, then the guest's own vertex/fragment programs through an HLSL → SPIR-V translator on the shared register-file draw engine. Everyps3recomp_hostscene passes on it under the Khronos validation layer — on lavapipe in CI, and on a Nintendo Switch's Tegra X1. - Vulkan stencil (#231): the depth format now carries stencil
(
D32_SFLOAT_S8_UINTfirst), so the engine's stencil state takes effect. Verified with a two-pass stencil scene on lavapipe and on the Switch.
André Brum — @andrebrumdev
Lifter and RSX correctness found bringing up God of War II HD and Ben 10 Omniverse — every fix arrives with a test that fails on master.
- Jump-table base register arbitrated by validated targets (#179, fixing his
own report #115) — with
lwzx rD,rA,rBeither operand can be the table base; the lifter took the first one it could resolve, so an absolute table whose index also came off r2 lost its dispatcher silently. - Callee-save slots snapshotted only for a real epilogue restore (#207) — a
reload of a frame local written by
stvxor through a pointer read the stale value from fragment entry; a Ben 10 dialog band drew half a tile off-centre. Same PR:vcmpequb./vcmpequh.set CR6, closing the last gap in the family. SET_TRANSFORM_CONSTANTis a 32-dword window, not 64 (#208) — three registers above it were landing in the vertex constant file, inside God of War's skinning palette: 46% of samples had a non-rigid bone, now 0.1%.-msse4.1probed instead of assumed (#206) — Apple clang 21 and aarch64 GCC reject it outright.
Kurtisone — @Kurtisone
Draw-engine, Vulkan and SPURS fixes found bringing up Twisted Metal on Linux/Vulkan. Each one comes with a measurement or a test, and most of v0.14.0 came from this work.
- Surfaces read through guest memory in another format (#236): a depth
buffer read as colour, a Z16 shadow map, a float packed into RGBA8. Write
serials let the engine pick the newer of the two surfaces at one address.
Plus
RSX_ENGINE_PASS_DUMPto find which pass of a frame first goes wrong (#237). - NV3089 surface coherence (#224), display buffers and flips handed to the engine (#223), texel-addressed coordinates (#221), B8 (#220), Z16 far-plane clears (#235).
- Vulkan: RGBA16F targets (#222), cube maps (#229), images sized by the device limit (#227), cached readbacks (#245), and dumping every nth frame (#219).
- An SPU-signalled SPURS task wakes at once (#242). It used to wait out a 1 s timeout, which made one frame of post-FX take 4.1 s.
- SPURS taskset fields kept out of guest memory (#240), barrier and
GetTasksetInfo(#241), IO-table-first offsets (#238), a POSIXps3_ms_now(#244), real POSIX lwmutex/lwcond (#225), safe stack scans (#217), SPU disassemblerorbi/xorhi/xorbi(#239),--chunk-lines(#216),PS3_NULL_READ_STACK(#226) andg_ppu_main_ctx(#228). - Depth bounds test in the draw engine and Vulkan (#319), measured on Twisted Metal's deferred lighting.
- v0.16.0, 12 PRs. In-stream flips that complete when the RSX reaches them (#343), get across a JUMP (#347), FP16 transfers (#367) and pixel-wise row conversion (#348); a cache of HLSL to SPIR-V translations (#346); Vulkan feedback snapshots (#352) and a split present (#351); atomic task signal bits (#340), job frames below cache buffers (#366), AVX2/SSE2 SPU float (#369, #370), and AIO reads that keep the fd's position (#376).
- v0.18.0, 5 PRs.
SPU_PCSAMPLEis read once at init instead of on every DMA, with the regression test the competing fix lacked (#243). AVX2 estimate, interpolation and float/int conversion helpers, four lanes at a time (#500). In Vulkan, each draw gets its own vertices, indices, constants and descriptor set rather than sharing one set across the frame (#536). A cellPad port with no controller attached reports centred sticks instead of zero, which several titles read as a stick held hard left (#496). The twistedmetal regression run clears its FIOS file cache before starting, so a stale cache cannot make a run look green (#498).
undecuple — @undecuple
- Real video decode in cellVdec (#215): H.264 and MPEG-2 through FFmpeg, loaded at run time and never linked. Pictures come out in display order, with pic items, PICOUT and EndSeq flush, in YUV420/UYVY/ARGB/RGBA. The loader is reusable for cellAdec and cellDmux.
- A detailed set of about 60 general fixes from a Killzone 3 port (#214), each with a focused test against v0.13.0.
- v0.15.0, 33 PRs from the Killzone 2/3 ports. In the lifter: VMX lane
order (#269),
lwaxjump tables (#285),scfall-through (#297), carry-form callee-save reloads (#320), and--chunks(#254). In the loader: TLS sizing (#253), a per-coroutine call-depth guard (#270), and MinGW thread-locals (#271). In cellGcm: IO table and leak (#255),GET_REPORTDMA context (#256), user commands (#273), and in-FIFO flip (#275). Depth export, depth-as-texture, Z16 clears, MSAA, predicated selects and sampler keys (#278-#282, #321). cellFs (#257, #258), PSF saves (#322), UserAutoSave (#276), cellHttp (#260, #261), NP (#259, #323), EDAT klicensee (#274), lwcond layout (#277), cellFont (#324), SPURS argument ABI (#309, #310), SMClqa/stqa(#268), and the MFC table (#272). - v0.18.0, 11 PRs. The published error-code bases move: GCM to
0x80210000and SPURS task codes onto their own0x80410900(#414) — the one change in the batch a downstream port can see in a literal value. A thread that has exited is gone and its id is not handed straight back out (#415). The licence area answers as system parameter0x0122(#429). cellVdec never returns handle 0 (#495). XInput is loaded at run time instead of being imported, which also takesxinputoff the Windows link line (#494). stdout and stderr are buffered with a timed flush, and nothing is lost at exit, onabort()or through the unhandled-exception filter (#524). Five docs PRs:SPU_LIFTER.md(#425), the SPU workflow inGETTING_STARTEDand the porting guide (#426), prerequisites reconciled across five documents (#427), template paths matched to the CMake (#428), andCITATION.cff(#535).
robbe1912 — @robbe1912
- D3D12 fragment-program source capacity (#230): a 256-instruction program produced 57 KB of HLSL against a 32 KB buffer and was dropped as a decompile failure. Comes with a synthetic regression fixture.
tekulvw — @tekulvw
- SPU interpreter
ILH(#234): it had sharedIL's case and repeated a 32-bit immediate instead of a halfword. The test runs the real interpreter. - v0.15.0, 34 PRs: a correctness sweep of the runtime and the Metal
backend, each with a fixture that fails before the fix.
- SPURS policy scheduling with per-instance workers and contention limits (#291), private per-context DMA and reservation state (#290), interpreter hand-off (#266), and SPU ELF discovery in the build (#288). Also SDCRZ (#295), FNMS (#318), the interrupt-enable bit (#289), and the SPURS task/taskset fixes (#283, #284, #298, #306).
- argv/envp (#263) and HLE registration regeneration (#262).
- RSX: depth compare (#302), sRGB output (#304), texture gamma (#305), colour-input clamp (#303), depth24 (#299), depth-export cache keys (#301), and immediate vertices (#292). Metal: depth readback (#300), colour snapshots (#307), clears (#293), window close (#308), and FPS diagnostics (#294).
- cellFs directory entries and disc roots (#247, #249), GCM strict IO mapping (#248), network (#250, #265), timezone (#264), sysmodules (#267), dialogs (#251), and Sail (#252).
- Guest spinlocks with a 32-bit atomic on LP64 hosts, an arm64 fault (#326, v0.16.0).
- v0.18.0, 45 PRs — the largest set in the release. Three threads run
through it.
- SPU dispatch and residency. Streamed code regions are verified once
per load and then dispatched by residency (#420); resident-code ownership
is honoured when the interpreter rejoins lifted code (#419); a per-thread
cache sits in front of
spu_lifted_lookup, on by default (#481). Indirect-dispatch registry lookups (#436) and the per-thread MFC engine lookup (#421) are memoized, and an image's fingerprint is reused while its bytes are unchanged (#433). Lifter coverage verifies job-module regions and embedded SPU programs, reports dispatch misses loudly rather than silently, and handles spilled PPU jump tables (#444). - Exact float and coherency. NEON float ops without scalar fix-up lanes
(#445), and opt-in
SPU_FLOAT_RZrunning single precision natively under a round-toward-zero FPCR (#479).GETLLARwithout the lock-line lock for registered holders (#441), only the reserved lines of a PUT copied under it (#484), a brief spin before parking on the POSIX lock-line lock (#443), DMA event producers serialized against reservation-lost notifications (#418), and the parked-task scan bounded on every committed lock line (#450). - Draw engine and Metal. A larger surface is reused only on the same
sample grid (#422), each texture key remembers where it was last found
(#438), the per-draw pipeline key is cheaper (#459), index runs append in
one pass (#465), and a draw's vertices are fetched attribute by attribute
(#458).
rsx_stateis handed only the methods with outside effects when the draw engine is on (#466). The Metal staging arena records into a pooledMTLBuffer(#440) with one reused depth-readback buffer (#461). - Plus the diagnostics gates the release is named for: the GCM FIFO walker
stops calling
getenvper packet (#437), the guest load/store watch hooks go behind one inlined load (#483), the PUT poison scan runs only when it can be reported (#454), andPS3_TPROF(#480) andRSX_WALKER_PROF(#467) arrive as opt-in samplers.
- SPU dispatch and residency. Streamed code regions are verified once
per load and then dispatched by residency (#420); resident-code ownership
is honoured when the interpreter rejoins lifted code (#419); a per-thread
cache sits in front of
Noah Peterson — @NoahBPeterson
Runs the inFAMOUS port.
- Hardware-exact SPU float semantics (#287): extended range, truncation,
denormal flush,
frest's table, and an exact-arithmetic referee. NEON paths are bit-identical and 1.6-4x faster. Replaces the old GPL-derived float code. - Exact VMX and branch decode in the PPU lifter (#286): about 45 VMX ops that were no-ops, VSCR/CR6, BO/BI decoding, and 64-bit CTR.
- Both are pieces of the LLE firmware and conformance work in #213.
erikomis — @erikomis
Fixes found bringing up inFAMOUS 2 on the inFamous branch, sent to master as well:
- jump tables behind a tail-call epilogue (#311);
- a parked FIFO given time to be patched (#312);
- the
SPU_RdDec231 s wrap (#313); - NV40 pack/unpack opcodes (#314);
- cellGem/cellCamera imports (#315);
- Metal command-buffer errors reported (#316).
- v0.16.0, 21 PRs. 3D textures (#335); FACING/TC8/TC9 (#328),
perspective-correct texcoords (#329),
_bx2and biased-remap fetches (#331), Y16_X16/HILO8 crossbars (#332); flips that complete in order (#354), a bounded semaphore acquire (#327), GCM callbacks at timer sleeps (#353), unscaled NV3089 rows (#334); Metal MRT masks (#330), anisotropy (#373), FXAA and sharpening (#374), gamma (#355) andprecise::math (#356); sparse texture re-hashing (#375) and per-draw vertex spans (#357);PS3_FTRACE(#339), FP debug knobs (#336),PS3_LANG(#333),PS3_GAMEDATA_ROOT(#338) and full-strength rumble (#372). - v0.18.0, 41 PRs, and the macOS and Linux bring-up work is the spine of
it.
- Raw SPUs run on POSIX (#473) — each with its own program,
SPU_RunCntl = 0stopping a running one (#505), and raw-SPU images carrying a parameter area the loader fills in (#538). - One window across an
exitspawnon macOS, viatools/host_windowand a Metal host-surface mode over shared IOSurfaces (#509), with the guest moved off the main thread (#477) and the whole 32-bit guest space backed on POSIX as it already was on Windows (#475). One host clock backsmftb, system time and timers, throughmach_absolute_time(#540). - SSE4.1 and AVX2 forms of the per-lane integer and quadword helpers
(#512) — about 72 helpers, including a rewrite of
cbd/chd/cwd/cddthat drops their 16-byte control loops on every host, arm64 included. - Metal: HLSL→MSL translations cached in memory and on disk (#511),
SET_TEXTURE_BORDER_COLORhonoured in the sampler (#476), and a vertex program's position invariant compiling (#563). - The depth-snapshot chain: a stale snapshot is released (#502) and a snapshot is the region the texture names (#507) — the pair the eviction work in #499 had to land behind.
- New HLE surface:
cellSysconfOpen/cellSysconfAbort(#564),cellSysutilNpEulaanswering through its callback (#542), sceNp tickets, account region and network time as OFFLINE (#543), the cellNetCtl net-start dialog (#503),cellPadInfoSensorMode/SetSensorMode(#565), andps3_host_quitso the close button and Cmd+Q reach the guest (#544). - Plus
SPU_DIRECTtail calls (#510), atomicevent_status(#492),SPU_IRQWAIT_DIAG(#491), per-thread HLE→guest callback stacks (#489),lift_jobmodsat the link base each header names (#488), andppu_lifter --insn-patches(#539).
- Raw SPUs run on POSIX (#473) — each with its own program,
deucebucket — @deucebucket
- Reported that
fw_spu/was tracking decrypted firmware PRXs and lifted C, against our own firmware policy (#210). It came out in #212.
bojogon7 — @bojogon7
- Added AnyPS5 to the README's list of sibling recompilation projects (#209).
n0madic — @n0madic
Fixes from a SoulCalibur II HD port (n0madic/Soulcalibur2HD-recomp):
- An SPU thread runs the image its own bytes identify (#362), not whichever registered image has code at its entry point. SPU user events find the port the PPU binds (#363).
- NV3089's 12.4 source origin (#358): copies were 256 times too short.
- The D3D12 vertex program cache keyed on the program (#361), which took most D3DCompile calls off the FIFO thread.
cellGameBootCheckgame type from PARAM.SFO (#359), and the msg-dialog NONE/INVALID button codes (#360).- v0.18.0, 9 PRs. Shadow compare is
depth FUNC reference, not the reverse (#424) — it had been backwards, so every shadow test was inverted. A depth surface read as a texture converts on the GPU, with eviction from full surface and zeta tables (#499). 3D texel coordinates divide by depth (#482), the vertex program branches on the transform branch bits with leaders up to slot 544 (#485), WPOS counts pixels on antialiased targets (#446), and the depth formats present their one channel on every crossbar source (#501). A flip in the FIFO restoresZSTENCIL_CLEAR_VALUE, and a 0 clear value is the near plane (#526). Frequency 1 under a modulo divider bit is one element for the whole draw (#547). A thread created above its creator's priority runs until it blocks, underPS3_PRIO_START=1(#416).
kalpakprod — @kalpakprod
CELL_FS_O_*flag values corrected soO_CREATcreates (#349)./dev_hdd1maps to a writable host root with its cache directory (#350).- Syscall 14 classifies lock-line addresses by guest segment (#341).
rigaz29 — @rigaz29
The D3D12 backend's guest-shader pipeline, and the GCM FIFO walker. 33 PRs in v0.18.0, their first release here, and the largest single body of new capability in it.
- D3D12 guest pipelines: guest depth/stencil state and samplers are folded
into the guest-FP pipelines (#558), with depth surfaces per zeta offset that
are readable as textures and FP depth export (#559). Indexed triangle lists
are drawn with their own indices rather than being expanded (#530). Guest
textures stage through a shared upload ring with least-recently-used slots
(#579), vertices are converted once per draw (#518), and a small batch can be
held back across two flips (#583). The texture-slot SRVs that were
overwriting the SRV heap are gone (#557). New
D3D12_VSYNC=0(#575) and on-demand RenderDoc capture with resources named in guest terms (#561). - GCM FIFO walker: NOP runs are passed over and 3D method runs decoded a
command at a time (#554); vertex-program methods are taken first, with one
diagnostic gate per FIFO word instead of one per method (#548); the drain's
own ring recycle counts as the JUMP to begin (#553);
GCM_PARK_GRACE_MSbounds how long a park may stand (#531). GCM handlers run from blocked semaphore waits on Windows (#576). - PPU loader and lifter: guest stores inline, to match the inline loads (#573), on a cheaper access sequence — memory-model copy, one compare, a branch hint (#574). The SPU reserved-line bitmap is tested inline on guest stores (#534), and the reservation is re-checked once the lock-line lock is held (#522).
- Diagnostics:
SPU_INTERP_STATSnow says where the interpreter was entered (#523),PS3_SAMPLE_DRAIN=1samples only the RSX drain thread (#520) with exact attribution underPS3_SAMPLE_RVASand a one-thread fast path (#568), an ftrace span is recorded per HLE import call with its own report section (#580), and the remaining hot debug switches are read once rather than per event (#519, #521, #527). - Also:
sysPrxForUserlwmutex on an atomic lock word with a fast path for leaf HLE imports (#577), named runtime host threads (#567), the interpreter rejoining inside resident regions (#525), per-hop hook fast paths (#533), CMP (11-11-10) attribute decode (#529), swizzled decode that steps the offset instead of re-interleaving each texel (#578), an empty XInput slot polled once a second instead of every frame (#581), and--merge-chunksin the SPU program build (#549).
MaChInEgUn3 — @MaChInEgUn3
First release here, 5 PRs in v0.18.0.
VK_DRAW_BATCH=1records engine draws, snapshots, uploads and clears into a single Vulkan submission instead of one per operation (#532), with readback staging reused and changed textures refreshed in place (#552).- WPOS follows the RSX's own window convention —
SET_SHADER_WINDOWorigin and pixel centres (#589). - Straight quadword load/store sequences run in the SMC microstep on a tight
loop (#571), and halt and
iretlongjmp without unwinding on 64-bit Windows (#572).
xuxinsss — @xuxinsss
First release here, 2 PRs in v0.18.0.
- The runtime builds with plain MSVC (
cl), not only clang-cl (#588) — five files across the SPU and PPU, mostly SIMD intrinsics and statement expressions that only the Clang front end accepted. - lv2 syscall 22 is registered as
_sys_process_exit(#587).
feanor-noldorin — @feanor-noldorin
First release here, 1 PR in v0.18.0.
- cellFs repositions the stream when a fd switches between reading and writing (#456), which the C library requires and the previous code did not do — a read after a write returned bytes from the wrong offset. Comes with two new tests.
Tzeentchnet — @Tzeentchnet
First release here, 1 PR in v0.18.0.
- Duplicate clear-presented flips are skipped in D3D12, and only those (#486) — the narrow form matters: a title that legitimately presents the same cleared frame twice still gets both.
- ATRAC3 / ATRAC3plus decoders (
third_party/at3_standalone, used bycellAtrac) — from FFmpeg, as extracted to a standalone library by the PPSSPP project (ext/at3_standalone). LGPL-2.1-or-later, kept as a separable component; see itsREADME.txtandCOPYING.LGPLv2.1.
Parts of this project — and some contributions to it — were developed with the help of AI coding tools. That's welcome here: what matters is that every change is understood, reviewed, and verified by a human before it lands. If you used an assistant, just say so in your PR (several contributors have) and make sure you can stand behind the result.