div.s now maintains fcr31's Cause.Z and (when the trap is masked) sticky
Flag.Z bits, in the standard MIPS bit positions. Only a finite non-zero
dividend counts, so 0/0, inf/0 and NaN operands are excluded per IEEE 754.
When the guest has the trap unmasked, the new Core_FPUException() reports it
with the usual module suffix and MIPS call stack, and fd is left unwritten as
hardware would. That's gated behind a new developer setting, off by default:
PSP threads start with fcr31 = 0x00000e00, i.e. three of the traps already
enabled, and games divide by zero without meaning anything by it. The fcr31
bits are updated either way, so what the game reads back doesn't depend on
the setting.
Interpreter only - the JITs are unchanged, and none of this is reachable
under them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R9fKXvYBrnqtp1QQGaGWVv
ins derived its width as (_SIZE + 1) - pos, which is zero or negative when the
encoded msb is below pos: the following shift is then 32 or more, undefined, and
on x86 produces an all-ones mask that writes bits the JITs don't touch. Build
the mask from msb and shift it down instead, which is what the JITs do and can't
shift out of range. Hardware calls that encoding unpredictable, so consistency
is all that's wanted here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfY7iFJEjmRXf1XGrTs4MF
The alignment checks added in d8edeb7649 return out of the instruction handler
without advancing PC, so with IgnoreBadMemAccess - which is the default, and
which makes Core_MemoryException log and return - the run loop comes straight
back to the same instruction and never gets past it. cpu/crash/crash_read_u32
under -i logged the same SIGSEGV 585096 times in 30 seconds before being killed;
the JIT runs it to completion.
Continue instead, the way Memory::Read_U32 did before those checks existed and
the way the JIT's safe-memory path still does: loads produce zero, stores are
dropped, PC advances. When the exception is set to break rather than ignore,
Core_Break has already stopped the core by the time we get here, so nothing
changes for that case.
lv.q/sv.q are left alone - they already fall through and do the access.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfY7iFJEjmRXf1XGrTs4MF
Every JIT backend puts the host FPU into the mode fcr31 asks for (bits 0-1 and
24) before running emulated code, and takes it back out before calling any host
code. The plain interpreter did none of that, so all its float math rounded to
nearest with denormals intact no matter what the game had set - cpu/fpu/fpu
fails under -i and passes under the JIT on exactly this.
Move the helpers the IR interpreter already had for this out of IRInterpreter
and into MIPS.cpp as ApplyHostRoundingMode/RestoreHostRoundingMode, and use them
around the interpreter's run loop and single step, restoring around syscalls and
replacement functions, which are host code. ctc1 re-applies immediately, since
the interpreter has no block boundary to defer it to.
round.w.s changes with it: it was floorf(x + 0.5f), which is half-away-from-zero
rather than the half-to-even every JIT produces, and the add would now pick up
the guest's rounding mode on top of that. round_ieee_754 is both correct and
mode-independent, and is what cvt.w.s already used for the same rounding.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfY7iFJEjmRXf1XGrTs4MF
Extends LoadAndStartVshKernelModules() to load the 11 real kd/*.prx
kernel drivers for --vsh (dmacman, systimer, memlmd_01g,
loadexec_01g, lowio, idstorage, syscon, rtc, wlan, wlanfirm_01g, utility),
ahead of the existing 4 VSH-specific modules.
Only active when g_runningVSH, no effect on normal game boot.
Improve implementations of sceKernelSm1ReferOperations and sceKernelIsIntrContext.
Add some more MMIO stubs (GPIO, SYSCON).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
(cherry picked from commit 7f3168b7df85e47438900016c9ee7d7ef01a0a28)
Two diagnostic experiments while chasing the divide-by-zero break from the
previous commits (see docs/VSHBootInvestigation.md "Attempt 8"/"Attempt 9"):
- Unregistered MMIO reads now return a distinctive poison value
(0x1337BEEF) instead of 0, so a future trace can tell at a glance when a
value traces back to an unimplemented register instead of looking like an
ordinary zero.
- COP0 register 9 (Count) now returns a live CoreTiming-derived value
instead of a static shadow-array read, matching how real hardware free-
runs it regardless of software writes.
Neither change altered the reboot.bin free-run's outcome at all (identical
break, same PC) - ruling out both as the source of the zero divisor traced
in the previous commit. Kept anyway: both are straightforwardly more
correct/useful than what was there before, independent of this specific
bug.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
(cherry picked from commit ac446449d9031b628d7d9c4dbc101638840f8434)
mfc0/mtc0/rdpgpr/mfmc0/wrpgpr had no interpreter execution function at
all - ordinary PSP user-mode code never executes COP0 instructions directly
so nobody needed one. Real kernel-mode boot code does the opposite:
flash0:/reboot.bin's very first instruction is mfc0.
Int_Cop0 (Interpreter.cpp) backs these with a small file-scope shadow
register array - not real COP0 semantics (no interrupts/exceptions/
TLB), just enough to not fault and give plausible
write-then-read-back-same-value behavior for boot code that pokes
Status and other registers. Might later be added to MIPSState.
Also regenerated Core/MIPS/InterpreterDispatch.cpp (`PPSSPPHeadless
--generate-interpreter-dispatch`).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
All ~82 MIPSInt::Int_* functions (Interpreter.cpp/.h,
InterpreterVFPU.cpp/.h) now take an explicit MIPSState *mips instead
of reaching for the global currentMIPS internally, along with their
file-local helpers (DelayBranchTo, SkipLikely, ApplySwizzleS/T,
ApplyPrefixD/ST, RetainInvalidSwizzleST, EatPrefixes). MIPSInterpretFunc,
Interpret(), ExecInstruction()/InterpreterDispatch.cpp (regenerated),
and RunUntilFast() all thread mips through accordingly.
Deliberately left on currentMIPS for now: MIPSVFPUUtils.cpp's
ReadVector/WriteVector/ReadMatrix/WriteMatrix/VFPURewritePrefix -
these are shared with every JIT backend's compile-time VFPU code, so
parameterizing them would balloon this into a JIT-wide refactor. This
is a partial refactor; that's the next boundary to push on.
Several JIT backends (x86 Jit.cpp, ARM/ArmJit.cpp, ARM64/Arm64Jit.cpp,
x86/X64IRJit.cpp, RiscV/RiscVJit.cpp, LoongArch64/LoongArch64Jit.cpp,
ARM64/Arm64IRJit.cpp) bake the raw interpreter function pointer
directly into JIT-generated machine code as their "fall back to the
interpreter for this one op" mechanism, with only a single argument
register set up for the call. Rather than hand-editing register
allocation across four architectures that can't be build-tested here,
added MIPSInterpretTrampoline(MIPSOpcode op) - a 1-arg wrapper around
MIPSInterpret(currentMIPS, op) - and pointed all 7 such call sites at
it instead, leaving that codegen untouched. Two other call sites
(JitLogMiss, JitBranchLog) were plain C++ calls and just got the
extra argument directly.
Verified (Windows x64): PPSSPPWindows/PPSSPPHeadless/UnitTest all
build clean, 49/49 unit tests pass. `test.py -g --graphics=software`:
interpreter 312/314 (cpu/fpu/fpu is the pre-existing, unrelated
interpreter-vs-JIT denormal difference; gpu/rendertarget/copy passes
standalone, so was cross-test state bleed in the batch run, not a
regression), default JIT 314/314, jit-ir 313/314 (gpu/vertices/morph
is an expected difference from the vertex decoder taking a different
mode with this core change, not a bug).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019SKhm9wKEQzRUsx9mTrrtQ