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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
"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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
ApplyHostRoundingMode fell back to fesetround, which can't set FPSCR.FZ,
so the interpreter and IR interpreter didn't flush with FS set as every
other host does. FPSCR has the mode and FZ at the same bits as ARM64's
FPCR. Found with CPUEquivalence on a Galaxy S8+ running the armeabi-v7a
build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comp_Generic restored the host's default mode around the interpreter call, so
an instruction the JIT doesn't compile rounded and flushed differently than in
the interpreter. Now the guest's mode stays in place, and is reapplied after the
call in case the instruction changed fcr31.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With FS set in fcr31, x86 flushed only denormal results (FTZ) while
ARM64's FZ also flushes denormal inputs, so the hosts disagreed whenever
a denormal reached an FPU or VFPU op. With DAZ too, x86 flushes the way
ARM64 does. That matches the PSP's VFPU, which always flushes inputs and
outputs (cpu/vfpu/fcr31); the PSP's FPU flushes only results
(cpu/fpu/denormal), which neither host does now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It only applied fcr31's rounding mode and flush-to-zero after a ctc1 in
the same block, so add.s, mul.s, cvt and friends rounded to nearest in
every other block. It's now applied once per time slice in RunLoopUntil,
where the native dispatchers do it, and the host's mode is put back
around CoreTiming, compiling, syscalls and replacement functions.
See docs/cpu-equivalence.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The same as GachiTora: without it, GPUs with cull distances draw parts the PSP
range-culls after clipping.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A strip through the near plane leaves a sliver at the screen edge on GPUs with
cull distances, where it isn't software clipped. The PSP range-culls it after
clipping.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>