Commit Graph
48936 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 6d105ae35d ARM32: Start an IR-based JIT
The backend follows the ARM64 one: a dispatcher, a register cache on top of the IR one, and
native exits, syscalls, breakpoints and transfers. Everything else goes to the IR interpreter
for now. Floats are mapped one lane per S register (no SIMD mapping yet), and addresses are
masked, as on every 32-bit build.

The JIT core now uses it on ARM32 in place of the old ArmJit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 17:32:53 +02:00
Henrik RydgårdandClaude Opus 5.5 2e3b844cff Add a headless armhf cross build, for testing ARM32 under qemu
./b.sh --armhf builds headless and the unit tests for 32-bit ARM, which run under qemu-arm the
way the loongarch64 and riscv64 builds do. setup-cross.sh learns the target (it also needs an
EGL stub), and the docs cover setting it up without root.

hash/hash dies with a bus error under qemu-arm on every CPU core, so it goes in a known-failures
list for the target.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 17:32:53 +02:00
Henrik Rydgård c015a881a3 Merge pull request #22562 from hrydgard/ir-jit-fixes
IR jit fixes, extracted from a different PR
2026-10-14 17:32:39 +02:00
Henrik RydgårdandClaude Opus 5.5 a56e5f2f6a ARM64 IR JIT: Keep the address out of SCRATCH1 across flushes
A flush stores pending imms through SCRATCH1, so in a non-constant MemoryCheck, and in
ValidateAddress's bad-address path, the address computed into SCRATCH1 could be replaced by an imm
before IRRunMemCheck or ReportBadAddress saw it. It now waits in SCRATCH2, which flushes don't use.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 17:10:35 +02:00
Henrik RydgårdandClaude Opus 5.5 985440a0c6 IR regcache: Load a dest that's a later lane of a source
When floats are mapped one lane at a time (RISC-V and LoongArch), a NOINIT dest was only upgraded
to a loaded one when a source had the same first reg. In Vec2Pack32To16 vf3, vf2,vf3 the dest is
the source's second lane, so it could be mapped without a load and the op read garbage. Found
with an IR-based ARM32 JIT, which failed vi2s.q C002, C000 in cpu/vfpu/overlap because of it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 17:10:35 +02:00
Henrik RydgårdandClaude Opus 5.5 f27b86c687 VFPU: Don't assert on mfv/mtv past the control registers
The encodings are reachable from guest code, and the CPUEquivalence fuzzer generates them, which
stopped a debug-build "UnitTest all" at the interpreter's assert. Every core already leaves rt
alone for mfv and writes nothing for mtv there (the IR interprets them), so only the asserts go.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 17:10:35 +02:00
Henrik Rydgård 400a97f0ad Merge pull request #22563 from hrydgard/remove-legacy-arm64-x64-jits
Remove the legacy (non-IR) x86-64 and ARM64 JITs
2026-10-14 17:08:38 +02:00
Henrik RydgårdandClaude Opus 5.5 66d7975e7f Remove the legacy (non-IR) x86-64 and ARM64 JITs
Their IR-based replacements stay. The JIT core now creates the IR JIT on both, so "JIT using
IR" is the same as "JIT" on every architecture (ARM32 still uses its legacy JIT for both). The
settings no longer offer it, a saved JIT_IR loads as JIT, and the JIT harness and CPUEquivalence
fuzzer drop the duplicate run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 14:39:45 +02:00
Henrik Rydgård 61e60ee6ff Merge pull request #22560 from eraycep/add-fading-chat-button
UI: Fade chat button with touch controls
2026-10-14 14:13:48 +02:00
Henrik Rydgård 836004e684 Merge pull request #22558 from hrydgard/cpu-equiv-6
CPU equivalence 6/6: ARM32 JIT fixes, and the docs
2026-10-14 14:06:49 +02:00
Henrik Rydgård 4e442b22b2 Merge pull request #22559 from hrydgard/game-browser-xmb-list
Game browser: Add a more XMB-like list format, make default
2026-10-14 14:04:34 +02:00
Henrik Rydgård bac8668204 Merge branch 'master' into add-fading-chat-button 2026-10-14 13:28:20 +02:00
Eray Cepni d970cf74f2 UI: Fade chat button with touch controls
Apply touch-control opacity to the chat button so it fades after
inactivity and reappears on touch. Keep it visible when touch controls
are disabled.
2026-10-14 14:20:33 +03:00
Henrik RydgårdandClaude Opus 5.5 66dc8972e8 GitLab CI: Only run libretro pipelines for master, tags and manual runs
Every mirrored branch was triggering the full libretro build matrix and
tying up their shared runners. Requested by the libretro team.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 12:49:35 +02:00
Henrik RydgårdandClaude Opus 5.5 d0e6e0a7c7 Docs: CPU equivalence state, including ARM32
Where the cores now agree, what the hardware tests answered, what's still
open (the NaN handling waits on the cpu-equiv-4 branch), and the ARM32 cores
as measured on a Galaxy S8+ and A21.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:29:57 +02:00
Henrik RydgårdandClaude Opus 5.5 48f9752235 ARM JIT: Leave matrix inits with a prefix to the interpreter, like the others
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:29:49 +02:00
Henrik RydgårdandClaude Opus 5.5 ad6f0ceea2 ARM JIT: Fix mtvc masking and vsgn of denormals, and interpret vh2f
mtvc masks the written control register like the other JITs, vsgn tests the
exponent (so a denormal gives 0, as in the interpreter), and the hardware
half-to-float conversion quiets NaNs, so vh2f goes to the interpreter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:29:49 +02:00
Henrik RydgårdandClaude Opus 5.5 0e908f466c ARM JIT: Gate VFPU ops on prefixes like the other JITs, and drop its vasin
The ARM32 JIT only checked for unknown prefixes, so a swizzle naming a lane
past the op's size, or a T prefix on vscl, read the wrong register or
asserted in VMOV. It now uses the ARM64 JIT's gates, and sends what they
refuse to the interpreter.

Its vasin was a polynomial approximation, not the bit-exact function the
other cores use (cpu/vfpu/exact failed 364 lines), so it goes to the
interpreter too, like vsin and vcos already did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:29:49 +02:00
Henrik RydgårdandClaude Opus 5.5 d7e449ab75 ARM JIT: Fix ins with msb below pos, ext past bit 31, and constant max/min
ins with msb below pos encoded an invalid BFI instead of doing nothing,
as the interpreter and the other JITs do, and ext with pos + size past 32
an invalid UBFX. max and min of two constants compared them unsigned.
Found by CPUEquivalence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:29:49 +02:00
Henrik Rydgård 21da437b79 Merge pull request #22557 from hrydgard/cpu-equiv-5
CPU equivalence 5/6: vmin/vmax ordering, vmfvc and vcmov fixes
2026-10-14 12:29:36 +02:00
Henrik RydgårdandClaude Opus 5.5 b025e9f819 VFPU: vcmov with imm3 = 7 tests a CC bit that is always clear
So vcmovt never moves and vcmovf always moves (cpu/vfpu/undefined). The
interpreter did nothing for either, and the JITs took it as imm3 = 6,
one CC bit per lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:59:35 +02:00
Henrik RydgårdandClaude Opus 5.5 1a9e06e2d6 ARM JITs: Write vmfvc's 0 for a control register past the defined ones
The register was mapped without MAP_DIRTY, so the 0 never reached it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:59:35 +02:00
Henrik RydgårdandClaude Opus 5.5 1f5e7e275b test.py: minmax_zero and minmax_tie pass now
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:59:35 +02:00
Henrik RydgårdandClaude Opus 5.5 9a08ff39be VFPU: vmin and vmax order zeros and denormals as equal, on every core
On the PSP, zeros and denormals all compare equal, a tie returns the
second operand, and the result keeps its bits (cpu/vfpu/minmax_zero,
minmax_tie, fcr31). The interpreter got the ties and NaNs right but
compared denormals as numbers, and each JIT had its own fast path with
host min/max, which returned the first operand on a tie and flushed or
not depending on the host's mode.

All cores now compare by vfpu_minmax_key(), an integer key that is 0
for a zero exponent and orders the rest by sign and magnitude, and
select the operand by it, without branching on NaN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:59:35 +02:00
Henrik Rydgård c6bec7e12c Merge pull request #22555 from hrydgard/cpu-equiv-3
CPU equivalence 3/6: Decode shift and Allegrex bit op encodings as the PSP does
2026-10-14 11:47:10 +02:00
Henrik RydgårdandClaude Opus 5.5 753e869ca1 Search: Drop the focus from a view the filter hides
When a search stopped matching the focused game, it stayed focused while
hidden, so its background and music kept going.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 11:17:44 +02:00
Henrik RydgårdandClaude Opus 5.5 754e49c6d6 Game browser: Switch existing installs to the large list on Games and Homebrew
Their old grid setting is no longer migrated, so everyone gets the new
view there. Recent and Remote still keep theirs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 11:12:00 +02:00
Henrik RydgårdandClaude Opus 5.5 9fe0ab593b MIPSTables: Include <algorithm> and <string_view> for the dispatch generator
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:05:42 +02:00
Henrik RydgårdandClaude Opus 5.5 ce8f48980a Game browser: Default to the large list for Games and Homebrew, bigger folders
The old GridView keys are now read as ints, so a missing key can be told
apart from false. Configs without them get the new defaults, while
existing ones still migrate their choice.

Folders get taller lines in the large list too, though not as tall as
the games.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 11:00:00 +02:00
Henrik RydgårdandClaude Opus 5.5 ef72f27fea Game browser: Keep the search and focus when returning from a game
FocusGame cleared the path to focus right after setting it, so since
the refresh became deferred nothing got refocused. The refresh also
showed every game again while the search bar still showed the filter.

Now an existing button is focused directly, without a refresh, and a
refresh reapplies an active search filter.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 11:00:00 +02:00
Henrik RydgårdandClaude Opus 5.5 51ce3fbde9 test.py: shift_encodings and allegrex_encodings pass now
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:56:48 +02:00
Henrik RydgårdandClaude Opus 5.5 4849ef020e Decode the unused bits of shifts and Allegrex bit ops as the PSP does
srl/srlv rotate when the low bit of their unused field (rs or sa) is
set and shift when it's clear, whatever the other bits hold
(cpu/cpu_alu/shift_encodings). The interpreter treated values above 1 as
invalid and the other cores shifted.

The Allegrex bit ops decode only some bits of sa, so all 32 values are
one of wsbh, wsbw, seb, seh and bitrev (cpu/cpu_alu/allegrex_encodings).
AllegrexBitOp() gives the canonical one for every core. Special3
function 0x18 does nothing on the PSP, where it was decoded as an alias
of 0x20.

The interpreter dispatch is regenerated, and its generator now lists
each instruction name once. CPUEquivalence no longer skips the srl/srlv
encodings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:56:48 +02:00
Henrik Rydgård 5ca12f0050 Merge pull request #22554 from hrydgard/cpu-equiv-2
CPU equivalence 2/6: Run every core in the guest's rounding mode and flush-to-zero
2026-10-14 10:56:15 +02:00
Henrik RydgårdandClaude Opus 5.5 524e8b5254 Translations: Game browser view modes, "Icon size"
"Grid icon size" is renamed to "Icon size", keeping the translations with
"grid" dropped from them. New keys for the view mode choices.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 10:46:40 +02:00
Henrik RydgårdandClaude Opus 5.5 43704b215c Game browser: Keyboard focus for the info button, more left padding
In the large list, right and left move between a game and its info
button, so up and down still step from game to game.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 10:45:12 +02:00
Henrik RydgårdandClaude Opus 5.5 7d273e178f Game browser: Info button in the large list, long press with buttons
Each line in the large list gets an info button, doing the same as a long
press or right click.

Holding the accept button now works as a long press in all view modes,
so it can be done from a gamepad.

Rename "Grid icon size" to "Icon size", since it now also applies to the
large list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 10:33:04 +02:00
Henrik RydgårdandClaude Opus 5.5 0066599f9a Game browser: Add an XMB-style large list mode
- Fixes #22202

A third view mode next to grid and list: a list with full size icons,
scaled by the grid icon size setting. Like the XMB, the selected (or
hovered) game plays its ICON1.PMF in place of the icon.

The per-tab grid bools become GameBrowserView1-4 ints. The old GridView
keys are still read, to pick the default, but no longer saved.

The PMF decoding moved out of GameScreen's PMFView into a shared
PMFVideoTexture.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 10:24:32 +02:00
Henrik RydgårdandClaude Opus 5.5 e93c1c389c Unit tests: Run the IR JIT on macOS too
It was left out of the JIT harness tests in 2024 for a crash nobody tracked
down, and runs fine on both arm64 and x86-64 Macs now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:01:44 +02:00
Henrik RydgårdandClaude Opus 5.5 90510d9e88 ARM JIT: Keep the guest's flush-to-zero in round, ceil and floor
They swap only the rounding mode bits in FPSCR now instead of resetting it,
which kept FZ off, so a denormal input is flushed like on the other hosts
(cpu/fpu/denormal).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:38:29 +02:00
Henrik RydgårdandClaude Opus 5.5 8d8948ee37 ARM JIT: round.w.s of NaN, and the guest's rounding mode after conversions
round.w.s gave 0 for a NaN instead of 0x7FFFFFFF like the other
conversions. round.w.s, ceil.w.s and floor.w.s reset FPSCR to
round-to-nearest and left it there, so cvt.w.s and the float ops after
them ignored the guest's mode (cpu/fpu/roundmode).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:38:29 +02:00
Henrik RydgårdandClaude Opus 5.5 b1b4f26b89 Docs: The JITs' rounding mode gaps are fixed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:48 +02:00
Henrik RydgårdandClaude Opus 5.5 b623183764 Unit tests: Add CPURoundingMode
Runs FPU math after a ctc1, and after a mode set from outside on blocks
compiled before it, on every core with and without ops left to the
interpreter, and checks the result against the interpreter. A fake syscall
checks that HLE always runs in the host's own mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:29 +02:00
Henrik RydgårdandClaude Opus 5.5 4f47475a69 Headless: Support --appendconfig
Merges the settings in an ini file over headless's own defaults, for runs that
need something like JitDisableFlags. Unlike in the app, the result is never
saved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:29 +02:00
Henrik RydgårdandClaude Opus 5.5 b44f61cba4 IR interpreter: Force the host's mode back in RestoreRoundingMode
A native backend can run this op through its generic fallback after its own
asm applied the guest's mode, which RestoreHostRoundingMode() doesn't know
about, so it has to clear the bits even when it didn't save them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:29 +02:00
Henrik RydgårdandClaude Opus 5.5 39813ffaf1 JITs: Notice a rounding mode that didn't come from a compiled ctc1
A JIT only switched modes around syscalls, and only took the mode into account
in conversions, once it had compiled a ctc1 (hasSetRounding). A mode from an
interpreted ctc1, a savestate made on another core, a core switch or a thread
switch went unnoticed, and HLE then ran in the guest's mode. UpdateFCR31()
now sets the flag when fcr31 isn't the default, and clears the block cache at
the next safe point, since blocks compiled before don't switch either. A new
JIT gets an UpdateFCR31() too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:28 +02:00
Henrik RydgårdandClaude Opus 5.5 241e781810 JIT: Switch rounding modes around interpreted ctc1 and syscalls only
Interpreted ops run in the guest's mode. A syscall left to the interpreter
(with JitDisable flags, say) is host code and now gets the host's mode, like a
compiled one, and an interpreted ctc1 to fcr31 now takes effect right away:
nothing set hasSetRounding for it, so the mode only reached the host at the
next time slice. Every other interpreted op skips the two calls it used to
make after it. The IR frontend's Comp_Generic, which the IR interpreter and the
IR native backends share, gets the same treatment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:28 +02:00
Henrik RydgårdandClaude Opus 5.5 4631c7b2f3 Save the host's FPU mode on apply, so restoring it is just a write
RestoreHostRoundingMode read the control register back to clear our bits, even
when nothing had been applied. Now ApplyHostRoundingMode saves the host's mode
the first time it changes it, and restore writes that back only if it did. With
the guest in the default mode, both are now just a flag check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:28 +02:00
Henrik RydgårdandClaude Opus 5.5 4b7baaf629 ARM32: Flush denormal inputs to float-to-int conversions under FS
ARM32's libm ceilf/floorf don't honor flush-to-zero, so the interpreters flush
the input themselves there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:28 +02:00
Henrik RydgårdandClaude Opus 5.5 f0c40e521d IR interpreter: Use the NEON Vec4 paths only on ARM64
ARMv7 NEON always flushes denormals and rounds to nearest, whatever FPSCR
says, so on ARM32 the scalar paths are used, which follow the guest's mode
like everything else.

The Vec4 ops only come from VFPU code, and the VFPU itself always rounds to
nearest and flushes denormals (cpu/vfpu/fcr31, see docs/cpu-equivalence.md),
so the NEON paths were arguably closer to the PSP there. But they disagreed
with every other host and core, and agreement between those comes first.
Running VFPU ops in the VFPU's own mode on every core would get both, and is
still to do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:26:28 +02:00
Henrik Rydgård 88f4c12437 Merge pull request #22553 from hrydgard/gpu-fallback-fixes
GLES and fallback rendering fixes from running the framedumps on Android
2026-10-14 09:20:38 +02:00