Brian Degenhardt aeabe3e0e5 EE cache: fix the DXSTG tag lookup's 29-bit fold, and the tests around it (#568)
* EE: the D-cache store-tag lookup dropped the top three bits of the tag

DXSTG takes a guest physical page from TagLo and has to turn it into the
host pointer our tags carry. It did that by routing the page through its
KSEG0 alias, which meant masking the tag to 29 bits first -- and KSEG0 is
only 512 MB wide, so the mask was not a formality. Every physical page at
or above 0x20000000 folded into the low half of the map and resolved to
whatever happened to live at the folded address.

The consequence that matters is that a page past the end of the physical
map folded onto real memory: 0x60129000 resolved to 0x00129000, and the
eviction wrote 64 bytes of cache line into guest RAM the tag never named.

Use vtlb_GetPhyPtr instead, which is what the debugger and PSM already use
to ask this question. It covers the whole 1 GB physical map and answers
null both for a handler page and for an address off the end of the map, so
the unbacked case is now decided by the same lookup that produces the
pointer rather than by a truncation.

Where a tag naming one of our main-RAM mirrors resolves changes as a side
effect of that, and is deliberately left unpinned. Those mirrors are our
physical map's, not a console's: an SCPH-30001 has no RAM at those physical
addresses, and an eviction steered at one reached nothing at all. There is
no hardware answer to hold us to, so nothing asserts one.

* Tests: point the DXSTG unresolvable-page check at a page that is unresolvable

The check named 0x1FFFF000, described as "BIOS/unmapped territory at the
top of the physical map". That page is the last one of the 4 MB BIOS ROM
mapped at 0x1FC00000, so it is real backing memory: the test took the
backed branch every time, wrote 64 bytes into the loaded BIOS image, and
asserted only that nothing faulted. The branch it was named for -- the one
carrying the safety property -- had no coverage at all.

Name 0x60129000 instead. It is past the end of the physical map, and it is
the page with teeth, because the old 29-bit fold sent it to 0x00129000 in
main RAM. A witness there turns "we did not fault" into "we did not write
somewhere the guest never named", which is the property worth holding.

An SCPH-30001 agrees with that much: an eviction steered above the end of
RAM puts nothing into RAM. Nothing beyond it is asserted -- where a tag
naming one of our main-RAM mirrors resolves is emulator-specific, so it
stays unpinned, with a comment saying so and why.

* Tests: stop the DXSTG write-back check skipping on 16K-page hosts

MapAt's candidate addresses are 4K-aligned and none is 16K-aligned, so on
a 16K-page kernel -- Asahi, Apple Silicon, some Android, and one of our own
CI jobs -- the kernel rejects every one of them and the mapping fails. The
write-back check treated that as a precondition and skipped outright, which
took its guest-side assertions with it: the ones that actually pin where a
DXSTG-steered eviction lands, none of which need anything from the host.

The mapping is only the negative control, there to show the write-back did
not ALSO reach the host page carrying the same number. Make it optional.
The guest-side half now runs everywhere and only the control drops out.

DxstgDirtyStaysInsideGuestMemory still skips, and should: it is entirely
about the host page. That leaves one skip here on a 16K-page host instead
of two, and none at all on a 4K one.
2026-08-14 21:50:24 -07:00
2022-11-29 09:46:18 +00:00
2026-07-27 19:48:36 +02:00
2024-01-14 14:18:03 -05:00
2026-04-03 12:41:47 -04:00
2026-07-18 12:04:18 -04:00

ARMSX2 — Native ARM64 JIT Fork of PCSX2

All Platforms

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

Project Demo

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

S
Description
No description provided
Readme
512 MiB
Languages
C++ 68.2%
Kotlin 9.8%
Swift 7.7%
C 5.6%
Objective-C++ 2.2%
Other 6.4%