A probe was built with the ps2dev toolchain, run on a PS2, and streamed its results back over ps2link's `host:` channel. Its two records are the oracle behind autocases_sa.h. SA is four bits wide. `mtsa 0x10` leaves SA at 0, `mtsa 0xFFFFFFFF` at 0xF, and MFSA reads the masked value back, so the mask belongs at the write. PCSX2 stored the raw 32 bits, which was the root cause of three different QFSRV behaviors for sa >= 16: UB in the interpreter, a guest-controlled out-of-bounds host read in the x86 recompiler, and a defensive mask in the arm64 one - and upstream recMTSA masks on its const path but not its runtime path, so x86 disagrees with itself too. Masking at MTSA makes all of it unreachable at once. Leaving it would mean permanently suppressing a JIT-vs-interp diff. EeRecTraps.MtsaCopiesFullRegister and MtsaConstFoldsAtCompile asserted the old behavior and were updated to the console's value. Two defects found and recorded 1, link branches with rs == $31 judge the condition on the pre-link value on console: `bltzal $ra` with $ra = -1 is taken. Their no-link twins agree on all six probe values, so the link write does not feed the comparison. PCSX2 links first in six functions (EE BGEZAL / BLTZAL / BGEZALL / BLTZALL, IOP psxBGEZAL/psxBLTZAL); 12 rows x 2 engines diverge. This settles the question IopLsuBranchConsoleConformance.LinkBranchesWithRaAsSourceArePinned left open. The assembler refuses to encode these at all, which is why no capture had them - they went in as raw .words, each verified by disassembling it back. `jalr $31,$31` rode along as a positive control and passed: the console jumps to the OLD $ra, corroborating the psxJALR ordering fix on a second CPU. 2, PCCR's writable mask is 0x800FFBFE - exactly the layout R5900.h documents, with pad0, pad1 and the eleven Reserved bits reading back as zero. PCSX2 stores it verbatim; 14 rows x 2 engines diverge. PCR0/PCR1 are fully 32-bit writable, so PCSX2 is already right there. DISABLED_AllSaPerfMatchesConsole is the graduation tripwire for both.
ARMSX2 — Native ARM64 JIT Fork of PCSX2
ARMSX2 is a free and open-source PlayStation 2 (PS2) emulator based on PCSX2. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your phone, PC, or gaming handheld, with many additional features and benefits.
Thank You
The ARMSX2 team is eternally indebted to the PCSX2 project it is based on. We are so fortunate to build on their 20 years of hardcore development.
About This Fork
The upstream PCSX2 project ships an ARM64 interpreter build for ARM, but its high-performance JIT recompilers (EE, IOP, VU0, VU1, and vtlb fast memory) are x86-64 only.
This fork exists to close that gap. The goal is to preserve the correctness features of 20 years of PCSX2 development, while generating the fastest native ARM performance possible.
Current status:
- ✅ EE (Emotion Engine) recompiler — integer, float, MMI, COP0/COP1/COP2, branches, load/store
- ✅ IOP (I/O Processor / R3000A) recompiler — full integer, load/store, branches, coprocessors
- ✅ VU (Vector Unit) recompiler — microVU skeleton + Upper FMAC vector ISA complete; Lower ISA and runtime complete
- ✅ vtlb fast memory
- ✅ Native ARM64 binary builds and boots the PS2 BIOS
- ✅ 2D games are already playable
- ✅ 3D games run
Why LLMs / AI Were Used
A word on methodology:
The x86-64 JIT code in upstream ARMSX2 is already proven correct — it has run thousands of PS2 titles for years. The challenge in this port is not emulator design or JIT theory; it is mechanical translation of a large, well-understood x86-64 assembly codebase into equivalent ARM64 assembly (via VIXL) while preserving the exact same register-allocation contracts, block lifecycle, and recompiler semantics.
Large language models (LLMs) were used as an accelerant for this translation work — pattern-matching x86 JIT boilerplate to ARM64 equivalents, scaffolding emit routines, and keeping the porting velocity high. The JIT logic (block compiler, dispatcher, analysis passes, flag pipelines, clamping rules, Tri-Ace hacks, etc.) is taken directly from the upstream x86 implementation and validated against it. Nothing was hallucinated from scratch.
In other words: the hard engineering was done by the PCSX2 team over two decades. The hard typing — translating ~50k lines of x86 emitter code into ARM64 — is what AI helped compress.
System Requirements
ARMSX2 targets ARM64 across desktop (macOS, Windows, Linux) and mobile (Android, iOS/iPadOS), all from the single shared core. Our setup documentation page contains additional details on software and hardware requirements.
Please note that a BIOS dump from a legitimately-owned PS2 console is required to use the emulator. For more information, visit this page.
Building
Check out our github actions for the latest build recipe
