mirror of
https://github.com/libretro/parallel-ps2.git
synced 2026-11-13 16:21:25 -10:00
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 µVU 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).
93 lines
2.0 KiB
C++
93 lines
2.0 KiB
C++
/* SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
|
* SPDX-License-Identifier: LGPL-3.0+ */
|
|
|
|
#include "FastJmp.h"
|
|
|
|
/* Win32 uses Fastjmp.asm, because MSVC doesn't support inline asm. */
|
|
#if !defined(_WIN32) || (defined(_M_ARM64) || defined(__aarch64__))
|
|
|
|
#if defined(__APPLE__)
|
|
#define PREFIX "_"
|
|
#else
|
|
#define PREFIX ""
|
|
#endif
|
|
|
|
#if defined(_M_X86) || defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) || defined(__x86_64)
|
|
|
|
asm(
|
|
"\t.global " PREFIX "fastjmp_set\n"
|
|
"\t.global " PREFIX "fastjmp_jmp\n"
|
|
"\t.text\n"
|
|
"\t" PREFIX "fastjmp_set:" R"(
|
|
movq 0(%rsp), %rax
|
|
movq %rsp, %rdx # fixup stack pointer, so it doesn't include the call to fastjmp_set
|
|
addq $8, %rdx
|
|
movq %rax, 0(%rdi) # actually rip
|
|
movq %rbx, 8(%rdi)
|
|
movq %rdx, 16(%rdi) # actually rsp
|
|
movq %rbp, 24(%rdi)
|
|
movq %r12, 32(%rdi)
|
|
movq %r13, 40(%rdi)
|
|
movq %r14, 48(%rdi)
|
|
movq %r15, 56(%rdi)
|
|
xorl %eax, %eax
|
|
ret
|
|
)"
|
|
"\t" PREFIX "fastjmp_jmp:" R"(
|
|
movl %esi, %eax
|
|
movq 0(%rdi), %rdx # actually rip
|
|
movq 8(%rdi), %rbx
|
|
movq 16(%rdi), %rsp # actually rsp
|
|
movq 24(%rdi), %rbp
|
|
movq 32(%rdi), %r12
|
|
movq 40(%rdi), %r13
|
|
movq 48(%rdi), %r14
|
|
movq 56(%rdi), %r15
|
|
jmp *%rdx
|
|
)");
|
|
|
|
#elif (defined(_M_ARM64) || defined(__aarch64__))
|
|
|
|
asm(
|
|
"\t.global " PREFIX "fastjmp_set\n"
|
|
"\t.global " PREFIX "fastjmp_jmp\n"
|
|
"\t.text\n"
|
|
"\t.align 16\n"
|
|
"\t" PREFIX "fastjmp_set:" R"(
|
|
mov x16, sp
|
|
stp x16, x30, [x0]
|
|
stp x19, x20, [x0, #16]
|
|
stp x21, x22, [x0, #32]
|
|
stp x23, x24, [x0, #48]
|
|
stp x25, x26, [x0, #64]
|
|
stp x27, x28, [x0, #80]
|
|
str x29, [x0, #96]
|
|
stp d8, d9, [x0, #112]
|
|
stp d10, d11, [x0, #128]
|
|
stp d12, d13, [x0, #144]
|
|
stp d14, d15, [x0, #160]
|
|
mov w0, wzr
|
|
br x30
|
|
)"
|
|
".align 16\n"
|
|
"\t" PREFIX "fastjmp_jmp:" R"(
|
|
ldp x16, x30, [x0]
|
|
mov sp, x16
|
|
ldp x19, x20, [x0, #16]
|
|
ldp x21, x22, [x0, #32]
|
|
ldp x23, x24, [x0, #48]
|
|
ldp x25, x26, [x0, #64]
|
|
ldp x27, x28, [x0, #80]
|
|
ldr x29, [x0, #96]
|
|
ldp d8, d9, [x0, #112]
|
|
ldp d10, d11, [x0, #128]
|
|
ldp d12, d13, [x0, #144]
|
|
ldp d14, d15, [x0, #160]
|
|
mov w0, w1
|
|
br x30
|
|
)");
|
|
|
|
#endif
|
|
|
|
#endif /* __WIN32 */
|