Files
WizzardSK 5f2eea7bfb AArch64 (arm64) port: native EE/IOP/VU recompilers
Upstream PCSX2 emulation relies on x86-64 recompilers for the EE (R5900),
IOP (R3000A) and the VUs, none of which exist on ARM. This adds native
AArch64 recompilers plus the supporting infrastructure to run PS2 games
correctly and reasonably fast on 64-bit ARM Linux devices (developed and
tested on a Snapdragon-class device: Adreno 618, 4 KB-page Linux, glibc
RetroArch flatpak + musl test host). Verified booting to real in-game
content (Mega Man X7 gameplay, Gran Turismo 3 intro/FMV and in-race) on
Vulkan/Turnip.

Native components:
- IOP (R3000A) JIT ~98%: ALU incl. trap forms + RFE, aligned/unaligned
  mem, branches + delay slots, block linking, mult/div + HI/LO, COP0
  moves, write-back register cache, RAM fastmem, event-gated tails,
  native J (only the HLE import-stub form stays interpreted, by design),
  cap-chaining, idle-loop fast-forward. Only the J import stub (HLE) and
  SYSCALL still break blocks.
- EE (R5900) JIT ~89%: ALU, loads/stores incl. LQ/SQ + unaligned family
  (fused canonical pairs), branches + likely branches + BC0x/BC1x, block
  linking/chaining, MULT/DIV/MADD + HI/LO (both pipelines), complete
  COP1/FPU (data moves + all S-format arithmetic + CVT + C.cond,
  interpreter-exact clamp/flag semantics), MMI -> NEON (packed integer
  incl. PPAC5, PMFHI/PMFLO/PMTHI/PMTLO, PLZCW, PREVH), CFC1/CTC1,
  MFSA/MTSA, ERET, COP0 moves + EI/DI, kernel idle-loop skip,
  block-revalidation cache, write-back GPR register cache. Only SYSCALL /
  TLB / exceptions still break blocks.
- VU0 macro (COP2) ~78%: runs inline in the EE thread; all SPECIAL1/2 ALU
  ops emit native NEON directly into EE blocks (microVU0 single-op
  emitters) with run-local flag liveness; DIV/SQRT/RSQRT, ITOF/FTOI, VI
  ALU, VI load/store, RNG, MOVE/MR32, MTIR/MFIR, CLIP; COP2 transfers
  native. Only CALLMS(R) falls to the interpreter (as x86).
- VU1 micro (microVU1) ~70%: full microVU recompiler port incl. the
  register allocator; runs on the MTVU worker thread by default.
- VIF 100%: NEON-optimized unpack.

Overall recompiler-suite progress ~88% (weighted by remaining work;
dynamic instruction coverage on the tested titles is much higher).

Supporting infrastructure:
- VIXL vendored as the AArch64 assembler (3rdparty/vixl).
- Build gating: x86 recompiler/emitter sources gated off aarch64; build
  detects and accepts aarch64.
- Fastmem: a 4 GB host mapping where every memory-backed guest page sits
  at its own guest address, so a load/store is one instruction; HW-reg /
  unmapped touches fault into a compile-time backpatch stub.
- Emitted-code quality passes: x19 guest-reg base, displacement folding,
  pinned vmap/fastmem base (x28), pinned &microVU base (x27), out-of-line
  cold code, fused chain epilogues, constant-LUT block chaining,
  adrp+pageoff folds, run-local COP2 flag liveness, lazy MTVU kick.
- Env-gated diagnostics (LRPS2_*) for A/B bisection + an in-tree SIGPROF
  sampling profiler bucketed by JIT code cache.

Verification: every phase is checked bit-identically against a golden
framebuffer (pixel-sum + nonzero count) on a headless Vulkan harness and,
for deep coverage, a Gran Turismo 3 in-race save state:
- GT3 1500f = 106138289 / 860124, GT3 12000f = 29063788 / 855955
- MMX7 1500f = 111415017 / 800725
- GT3 in-race 600f = 49204167 / 858359
Most opcode/emitter changes carry a kill switch and leave these
byte-identical; the microVU work is additionally checked with an
interpreter-vs-microVU shadow differential.

Known limits: SYSCALL/TLB/exceptions and the IOP HLE import stub stay on
the interpreter by design; demanding titles (e.g. GT3) run below full
speed on this hardware class, so audio underruns in heavy scenes (the
emulated audio itself is correct -- a raw-performance ceiling, not a bug).
2026-07-17 21:58:23 +02:00

114 lines
3.4 KiB
C

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
/// Base defines and typedefs that are needed by all code in PCSX2
/// Prefer this over including Pcsx2Defs.h to make sure everyone gets all the defines, as missing defines fail silently
#pragma once
#include "Pcsx2Defs.h"
#if defined(_WIN32)
#include <intrin.h>
#endif
#if defined(_M_X86) || defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__x86_64)
#if defined(__AVX2__)
#define _M_SSE 0x501
#elif defined(__AVX__)
#define _M_SSE 0x500
#elif defined(__SSE4_1__)
#define _M_SSE 0x401
#elif defined(__SSE2__)
#define _M_SSE 0x200
#else
#error PCSX2 requires compiling for at least SSE2, SSE 4.1 recommended
#endif
// Starting with AVX, processors have fast unaligned loads
// Reduce code duplication by not compiling multiple versions
#if _M_SSE >= 0x500
#define FAST_UNALIGNED 1
#else
#define FAST_UNALIGNED 0
#endif
#include <xmmintrin.h>
#include <emmintrin.h>
#include <tmmintrin.h>
#include <smmintrin.h>
#if _M_SSE >= 0x500
#include <immintrin.h>
#endif
#ifndef _MM_MK_INSERTPS_NDX
#define _MM_MK_INSERTPS_NDX(srcField, dstField, zeroMask) (((srcField) << 6) | ((dstField) << 4) | (zeroMask))
#endif
#elif (defined(_M_ARM64) || defined(__aarch64__))
#if defined(_MSC_VER) && !defined(__clang__)
#include <arm64_neon.h>
#else
#include <arm_neon.h>
#endif
#endif
#ifdef __APPLE__
#include <stdlib.h> // alloca
#else
#include <malloc.h> // alloca
#endif
#if !defined(_WIN32)
/* http://svn.reactos.org/svn/reactos/trunk/reactos/include/crt/mingw32/intrin_x86.h?view=markup */
//
// On Windows (MSVC, mingw-gcc, mingw-clang, clang-cl) <intrin.h> already
// provides _BitScanForward / _BitScanReverse, included unconditionally
// at the top of this file. Defining our own here would conflict with
// mingw-w64's declarations (which return 'unsigned char' rather than
// 'int'). This block is therefore only for non-Windows targets: Linux,
// macOS, etc., where <intrin.h> is unavailable and we synthesize the
// functions from gcc / clang builtins.
//
// Note: __MINGW32__ is unreliable -- some MSYS2 mingw64 toolchains do
// not define it -- so prefer the broader _WIN32 gate above.
static inline int _BitScanForward(unsigned long* const Index, const unsigned long Mask)
{
if (Mask == 0)
return 0;
#if __has_builtin(__builtin_ctz)
*Index = __builtin_ctz(Mask);
#else
__asm__("bsfl %k[Mask], %k[Index]" : [Index] "=r" (*Index) : [Mask] "mr" (Mask) : "cc");
#endif
return 1;
}
static inline int _BitScanReverse(unsigned long* const Index, const unsigned long Mask)
{
if (Mask == 0)
return 0;
#if __has_builtin(__builtin_clz)
*Index = 31 - __builtin_clz(Mask);
#else
__asm__("bsrl %k[Mask], %k[Index]" : [Index] "=r" (*Index) : [Mask] "mr" (Mask) : "cc");
#endif
return 1;
}
#endif