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