15 Commits
Author SHA1 Message Date
Adrien BeudinandClaude Opus 4.8 49921686b7 fix(jit): update FPSCR[FPRF] after FP arithmetic in the ARM64 JIT
The ARM64 PowerPC JIT computed floating-point arithmetic results correctly
but omitted the set_fprf() side-effect that the interpreter runs after every
FP arithmetic op (updates FPSCR[FPRF] with the result class/sign). Games that
read FPRF back via mffs/mcrfs to classify or clamp their results diverged from
the interpreter: in Daytona USA 2 the opponent AI misbehaved and the rival
cars crashed at the start of the race. With the JIT disabled (interpreter) the
AI matched the standalone.

Add a jit_set_fprf(rD) helper (calls the interpreter's set_fprf on FPR[rD])
and emit a call to it after every op the interpreter runs set_fprf for:
op59 fadds/fmuls/fdivs/fsqrts (via the STORE_SP macro) and op63
fadd/fsub/fmul/fdiv/fsqrt/fmadd/fmsub/fnmadd/fnmsub/frsqrte. Moves (fmr/fneg/
fabs/fnabs), fcmp and fsel are left untouched, matching the interpreter which
does not update FPRF for them. The arithmetic stays native, so the cost is one
short call per FP op rather than falling back to the interpreter.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-15 15:31:04 +02:00
sgiannop 0f6202c6b9 perf: JIT fastmem extended to FP loads, lmw, lwbrx + memset-safe static
Thanks to beudbeud for discovering and sharing these improvements:
- emit_ram_load32 applied to lfsx/lfsux, lfs/lfsu, lwbrx, lmw
- ppc_set_ram_ptr() now stores to s_jit_ram_base so pointer
  survives ppc_base_init() memset calls (correctness fix)

Also:
- Fix duplicate aarch64 GLES source block in Makefile
- R3DShaderTriangles: explicit highp on projMat in fragment shader
  (prevents precision mismatch link error on GLES)
- GLES GPU timer query guards wrapped in #if defined(CORE_GLES)
  so desktop GL builds don't reference EXT function pointers
2026-07-11 11:41:05 +03:00
sgiannop 12cf5712ed perf: JIT inline RAM fast-path for 32-bit loads (lwz/lwzx family)
Add emit_ram_load32() which bypasses jit_read32() C call for word-aligned
RAM reads (addr%4==0, addr<0x800000) via a direct LDR from ram_ptr.
Guards: two TBNZ alignment checks prevent the mismatch that occurs at
addr%4==2, where the interpreter uses XOR-addressed Read16 pairs that
read different host bytes than a plain LDR.

Stores stay on the slow path to preserve smc_write() cache-flush detection.
ram_ptr field added to PPC_REGS and set via ppc_set_ram_ptr() at init.
LDRH/STRH added to Arm64Emitter for future 16-bit fast-path work.
2026-06-21 09:25:34 +03:00
sgiannop a30aec41d3 fix: JIT stwcx. ARM flags + IRQ chaining regression
Three fixes that together unblock RPi5 JIT execution past boot:

1. stwcx. (subop 150): after storing CR0[EQ]=1 via STRB, emit CMP W0,2
   to set ARM Z=1. Without this, the Rc=1 peephole optimizer fuses the
   following 'bf cr0[eq]' with stale ARM flags from andi. two instructions
   earlier (Z=0), causing the CAS retry loop to never exit. The MIDI queue
   producer's kick to midiCtrlPort=0x27 was unreachable, leaving the queue
   permanently full and the game frozen at the disclaimer screen.

2. ppc_set_irq_line(0): clear interrupt_pending bit 0x8 alongside 0x1.
   Bit 0x8 is the JIT chained-epilogue fast-exit signal; leaving it set
   after IRQ deassert caused every JIT block to exit via CBNZ instead of
   chaining, making JIT effectively interpreter-speed.

3. mtmsr (subop 146): fall back to interpreter so ppc_set_msr() runs,
   which calls ppc603_check_interrupts() to deliver any interrupt newly
   enabled by the MSR write (e.g. rfi re-enabling EE).
2026-06-20 18:38:24 +03:00
sgiannop aafe44f087 fix: macOS universal build — replace __aarch64__ JIT guards with HAVE_PPC_JIT
__aarch64__ fires for the arm64 slice of the macOS universal binary, causing
the linker to reference JitArm64 symbols that are not compiled for platform=osx.
Introduce HAVE_PPC_JIT (set by Makefile for android/rpi64/aarch64) and replace
all __aarch64__ guards in ppc.cpp and ppc603.c with it.
2026-06-16 23:17:33 +03:00
sgiannop 49f671b720 perf: eliminate RestoreDepth blit via dedicated trans2 FBO
Add m_frameBufferIDTrans2: pre-wired with att2 color + the copy depth
renderbuffer. After StoreDepth fills the copy buffer with opaque depth,
SetFBO(Layer::trans2) binds m_frameBufferIDTrans2 directly — no second
glBlitFramebuffer(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT) call.
Reduces depth blits per transparent priority layer from 2 to 1.
2026-05-21 09:40:07 +03:00
sgiannop 2a72b97071 fix: op63 FP JIT correctness, SMC detection, remove debug probes
- FCMP_D_ZERO encoding: 0x1E402008 → 0x1E602008 (was single-precision opcode);
  fixed distorted tree geometry in VF4
- frsp (op63 case 12): inline FCVT_S_D+FCVT_D_S causes wrong camera direction;
  fall back to interpreter which also updates FPSCR[FPRF] via set_fprf()
- Add jit_frsp helper at FN table index 13 for future op59 STORE_SP use
- Remove all bisect scaffolding (JIT_DP_BISECT_* defines and guards)
- SMC detection: route interpreter WRITE8/16/32 and jit_write8/16/32 through
  smc_write() page-bitmap check to invalidate stale JIT blocks on code writes
- Add JitArm64::invalidate_containing() and smc_write(); flush() now clears
  m_code_pages bitmap
- Remove debug probes: CAMSTW/CAMST64 in jit_write32/64, CAMW in
  Real3D::WriteHighCullingRAM
- Fold jit_write32_stfs into jit_write32; remove cur_pc plumbing from
  translate_stfs and translate_op31
2026-05-20 18:16:42 +03:00
sgiannop 6292dd06d8 cleanup: minimize footprint in pre-existing supermodel files
- 53C810.cpp: revert entirely — all changes were cosmetic (whitespace,
  removed already-commented lines, one DebugLog that is a release no-op)
- Real3D.cpp: revert entirely — only change was commenting out a DebugLog
  that is already a release no-op via the LibretroWrapper fix
- Model3.cpp: restore two DebugLog("write32") calls removed in debug-probe
  cleanup pass — release no-ops, no reason to diverge from dev
- ppc.cpp: remove spurious blank line added inside ppc_init
2026-05-18 19:48:25 +03:00
sgiannop 2635e7a054 JIT: fix mid-block IRQ delivery, DEC storm, and jit_enable toggle
- ppc_set_irq_line: set interrupt_pending |= 0x1 | 0x8 so the chained
  epilogue's CBNZ exits the block chain immediately on external IRQ
- Guard ppc603_check_interrupts() with s_jit_executing: calling it while
  a JIT block is executing corrupts MSR[EE]/npc before the block returns,
  leaving EE=0 so jit_done skips IRQ delivery permanently
- DEC sentinel: guard dec_trigger_cycle check with != 0x7fffffff to
  prevent a DEC storm that fires on every single block dispatch
- Add ppc_set_jit_enabled(bool) to toggle JIT vs interpreter at runtime
2026-05-18 19:24:09 +03:00
sgiannop c4b4a8794d JIT: cut chained-epilogue fast path from ~20 to ~12 ARM instructions
Three coordinated changes:

1. Mirror fatalError into interrupt_pending bit 3 (0x8) at every fatal-set
   site, so the JIT chained epilogue needs only one load+branch for both
   fatal and interrupt instead of a separate LDRB+CBNZ for fatalError.

2. Use SUBS_W_IMM (flags-setting) for the icount decrement so the
   subsequent B.LE needs no separate CMP_W_IMM(W4, 0).

3. Defer the pc/npc write to the slow-exit path only (icount exhausted /
   interrupt / fatal). On the tail-call fast path pc/npc are never written,
   saving two MOV_W32 + STP per chained block transition. The slow path
   always writes them before returning to the dispatch loop, which is the
   only consumer of ppc.npc. Interrupt handlers see correct pc/npc because
   they are only reachable after a slow-exit which wrote both fields.
2026-05-15 16:00:07 +03:00
sgiannop a3de14b6b7 JIT: xer_ca byte cache — halve emit_load/update_xer_ca cost
Add UINT8 xer_ca to PPC_REGS mirroring XER.CA for direct LDRB/STRB
access instead of LDR+UBFM / CSET+LDR+BFI+STR round-trips through the
full XER word.

emit_load_xer_ca: 2 insns → 1 (LDRB only)
emit_update_xer_ca: 4 insns → 2 (CSET + STRB)
sraw/srawi CA write: 3 insns → 1 (STRB only)

mfspr XER / mtspr XER / mcrxr reconstruct or sync the cache on the
rare paths where the full XER word must be consistent.

ppc.cpp and ppc_ops.c updated so all interpreter CA writes go through
SET_XER_CA_SET/CLR macros that keep xer_ca in sync; ppc_set_spr(XER)
and LoadState also sync on write.
2026-05-15 09:32:52 +03:00
sgiannop 0fa578f1a5 JIT: dispatch optimizations, opcode fixes, and coverage improvements
Dispatch loop:
- Add 4096-entry direct-mapped fast-lookup cache in get_or_compile,
  avoiding the unordered_map hash for hot blocks
- Change block fn signature to fn(PPC_REGS*): saves 1-4 ARM instructions
  per block entry (MOV_X64 → MOV X19,X0)
- Defer ppc_change_pc to just before compilation and after loop exit,
  eliminating the per-block fetch-region sync overhead
- Inline interrupt-pending fast path: skip ppc603_check_interrupts()
  call when interrupt_pending == 0
- Add jit_sync_fetch() bridge so compile() can sync cur_fetch cheaply

New opcodes:
- op31: byte-reverse loads/stores (lwbrx/lhbrx/stwbrx/sthbrx)
- op31: mcrxr(512), eqv(284), dcbt(278), dcbtst(246), tlbia(370)
- op19: mcrf(0), rfi(50) as block terminator
- op17: sc as block terminator (both preserve interpreter-set NPC)
- bclr/bcctr (op19/16,528): fully inlined, no interpreter call per blr

FP/FPSCR:
- op63: frsqrte(26), mffs(583), mcrfs(64)
- op63 NOPs: mtfsf(711), mtfsfi(134), mtfsb0(70), mtfsb1(38)
- op59: fres(24)

Bug fixes:
- crand XO was 256 (dead code never matched); corrected to 257
- Emitter: add REV_W, REV16_W for byte-reverse ops

Buffer: MAX_BLOCK_INSTS 64→128, code buffer 8→16 MB
2026-05-14 03:09:06 +03:00
sgiannop 31bc6a88a5 Add PowerPC→ARM64 JIT dynarec for Android/RPi5
Introduces a block-compiling JIT in Src/CPU/PowerPC/Jit/ that replaces the
interpreter hot loop on aarch64 targets. Goal: reduce PPC thread CPU usage
from ~90-100% on Android phones and RPi5.

Key components:
- Arm64Emitter.h: hand-rolled ARM64 instruction encoder
- JitArm64.h/cpp: block cache, compiler, and opcode translators
- ppc_regs.h: PPC_REGS struct extracted so JIT can include it without
  pulling in all of ppc.cpp
- ppc.cpp: extern "C" bridge functions (memory, SPR, FP estimate helpers)
- ppc603.c: JIT dispatch loop + flush on reset

Opcode coverage: all integer D/X-form arithmetic, all load/store forms
(including byte-reverse and FP indexed), all shift/rotate ops, full FP
op59/op63 (including fres/frsqrte/mffs/mcrfs), all CR logical ops,
branch ops (b/bl/bc fully inline; bclr/bcctr fully inline—no interpreter
call per blr), cache/TLB NOPs, and all common SPR accesses.
2026-05-14 02:38:21 +03:00
sgiannop 4e02291787 Updated supermodel emulator to the current version. 2026-02-09 12:28:00 +02:00
twinaphex 196a16b031 commit remaining files 2019-03-01 02:33:56 +01:00