Add dummy interpreter implementations for the basic COP0 instructions

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 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
Henrik RydgårdandClaude Sonnet 5 committed 2026-08-13 11:34:00 +02:00
1 parent defea54cd2
commit 5dbe9bea91
4 files changed
+62 -5

No files matched your search

+44
View File
@@ -685,6 +685,50 @@ namespace MIPSInt {
PC += 4;
}
// Dummy COP0 register file, for kernel-mode code (e.g. flash0:/reboot.bin) that reads/
// writes COP0 state directly - ordinary PSP user-mode code never executes these
// instructions (kernel state is reached via HLE syscalls instead), so this doesn't need
// to model real COP0 semantics (interrupts, exceptions, TLB, ...), just be non-fatal and
// give writes-then-reads-back-same-value behavior. Not part of MIPSState (which is
// layout-sensitive for JIT register allocation) and not save-stated, in keeping with
// "dummy" - revisit if this ever needs to be more than a bail-out.
static u32 g_cop0Regs[32];
void Int_Cop0(MIPSState *mips, MIPSOpcode op) {
int rt = _RT;
int rd = _RD;
switch ((op >> 21) & 0x1f) {
case 0: //mfc0
if (rt != 0)
R(rt) = g_cop0Regs[rd];
break;
case 4: //mtc0
g_cop0Regs[rd] = R(rt);
break;
case 10: //rdpgpr
if (rt != 0)
R(rt) = R(rd);
break;
case 11: //mfmc0 (di/ei)
if (rt != 0)
R(rt) = g_cop0Regs[12]; // Status
break;
case 14: //wrpgpr
R(rd) = R(rt);
break;
default:
_dbg_assert_msg_(false, "Trying to interpret COP0 instruction that can't be interpreted");
break;
}
PC += 4;
}
void Int_RType2(MIPSState *mips, MIPSOpcode op) {
int rs = _RS;
int rd = _RD;
+1
View File
@@ -27,6 +27,7 @@ namespace MIPSInt
void Int_Syscall(MIPSState *mips, MIPSOpcode op);
void Int_mxc1(MIPSState *mips, MIPSOpcode op);
void Int_Cop0(MIPSState *mips, MIPSOpcode op);
void Int_RelBranch(MIPSState *mips, MIPSOpcode op);
void Int_RelBranchRI(MIPSState *mips, MIPSOpcode op);
void Int_IType(MIPSState *mips, MIPSOpcode op);
+8
View File
@@ -144,6 +144,14 @@ int ExecInstruction(MIPSState *mips, MIPSOpcode op) {
case 16:
{
switch ((op.encoding >> 21) & 0x1f) {
// mfc0, mtc0, rdpgpr, mfmc0, wrpgpr
case 0:
case 4:
case 10:
case 11:
case 14:
MIPSInt::Int_Cop0(mips, op);
return 1;
case 16:
case 17:
case 18:
+9 -5
View File
@@ -368,23 +368,27 @@ static const MIPSInstruction tableCop2BC2[4] = // 010010 01000 ...xx ...........
static const MIPSInstruction tableCop0[32] = // 010000 xxxxx ..... ................
{
INSTR("mfc0", JITFUNC(Comp_Generic), Dis_Generic, 0, OUT_RT), // unused
// Dummy interpreter-only implementations (Int_Cop0, Interpreter.cpp) - real hardware
// semantics aren't modeled, just enough to not fault. Ordinary user-mode PSP code never
// executes these; kernel-mode boot code (flash0:/reboot.bin) does. See
// docs/VSHBootInvestigation.md.
INSTR("mfc0", JITFUNC(Comp_Generic), Dis_Generic, Int_Cop0, OUT_RT),
INVALID,
INVALID,
INVALID,
INSTR("mtc0", JITFUNC(Comp_Generic), Dis_Generic, 0, IN_RT), // unused
INSTR("mtc0", JITFUNC(Comp_Generic), Dis_Generic, Int_Cop0, IN_RT),
INVALID,
INVALID,
INVALID,
//8
INVALID,
INVALID,
INSTR("rdpgpr", JITFUNC(Comp_Generic), Dis_Generic, 0, 0),
INSTR("mfmc0", JITFUNC(Comp_Generic), Dis_Generic, 0, 0),
INSTR("rdpgpr", JITFUNC(Comp_Generic), Dis_Generic, Int_Cop0, OUT_RT),
INSTR("mfmc0", JITFUNC(Comp_Generic), Dis_Generic, Int_Cop0, OUT_RT),
INVALID,
INVALID,
INSTR("wrpgpr", JITFUNC(Comp_Generic), Dis_Generic, 0, 0),
INSTR("wrpgpr", JITFUNC(Comp_Generic), Dis_Generic, Int_Cop0, IN_RT),
INVALID,
//16
ENCODING(Cop0CO), ENCODING(Cop0CO), ENCODING(Cop0CO), ENCODING(Cop0CO), ENCODING(Cop0CO), ENCODING(Cop0CO), ENCODING(Cop0CO), ENCODING(Cop0CO),