Files
ppsspp/Core/MIPS/InterpreterDispatch.cpp
T
Henrik RydgårdandClaude Sonnet 5 ffad0acea1 Plumb an explicit MIPSState *mips through the interpreter's Int_* handlers
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
2026-08-12 14:02:19 +02:00

737 lines
17 KiB
C++

// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// AUTO-GENERATED by `PPSSPPHeadless --generate-interpreter-dispatch` from the
// tables in MIPSTables.cpp - do not hand-edit, regenerate instead.
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/Interpreter.h"
#include "Core/MIPS/InterpreterVFPU.h"
// Returns the cycle count consumed, or -1 if op isn't a recognized instruction -
// callers must fall back to MIPSInterpret() themselves in that case.
int ExecInstruction(MIPSState *mips, MIPSOpcode op) {
switch ((op.encoding >> 26) & 0x3f) {
case 0:
{
switch ((op.encoding >> 0) & 0x3f) {
// sll, srl, sra, sllv, srlv, srav
case 0:
case 2:
case 3:
case 4:
case 6:
case 7:
MIPSInt::Int_ShiftType(mips, op);
return 1;
// jr, jalr
case 8:
case 9:
MIPSInt::Int_JumpRegType(mips, op);
return 1;
// movz, movn, add, addu, sub, subu, and, or, xor, nor, slt, sltu, max, min
case 10:
case 11:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 42:
case 43:
case 44:
case 45:
MIPSInt::Int_RType3(mips, op);
return 1;
// syscall
case 12:
MIPSInt::Int_Syscall(mips, op);
return 1;
// break
case 13:
MIPSInt::Int_Break(mips, op);
return 1;
// sync
case 15:
MIPSInt::Int_Sync(mips, op);
return 1;
// mfhi, mthi, mflo, mtlo, mult, multu, div, divu, madd, maddu, msub, msubu
case 16:
case 17:
case 18:
case 19:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 46:
case 47:
MIPSInt::Int_MulDivType(mips, op);
return 1;
// clz, clo
case 22:
case 23:
MIPSInt::Int_RType2(mips, op);
return 1;
default:
return -1;
}
}
case 1:
{
switch ((op.encoding >> 16) & 0x1f) {
// bltz, bgez, bltzl, bgezl, bltzal, bgezal, bltzall, bgezall
case 0:
case 1:
case 2:
case 3:
case 16:
case 17:
case 18:
case 19:
MIPSInt::Int_RelBranchRI(mips, op);
return 1;
default:
return -1;
}
}
// j, jal
case 2:
case 3:
MIPSInt::Int_JumpType(mips, op);
return 1;
// beq, bne, blez, bgtz, beql, bnel, blezl, bgtzl
case 4:
case 5:
case 6:
case 7:
case 20:
case 21:
case 22:
case 23:
MIPSInt::Int_RelBranch(mips, op);
return 1;
// addi, addiu, slti, sltiu, andi, ori, xori, lui
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
MIPSInt::Int_IType(mips, op);
return 1;
case 16:
{
switch ((op.encoding >> 21) & 0x1f) {
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
{
return -1;
}
default:
return -1;
}
}
case 17:
{
switch ((op.encoding >> 21) & 0x1f) {
// mfc1, cfc1, mtc1, ctc1
case 0:
case 2:
case 4:
case 6:
MIPSInt::Int_mxc1(mips, op);
return 1;
case 8:
{
switch ((op.encoding >> 16) & 0x1f) {
// bc1f, bc1t, bc1fl, bc1tl
case 0:
case 1:
case 2:
case 3:
MIPSInt::Int_FPUBranch(mips, op);
return 1;
default:
return -1;
}
}
case 16:
{
switch ((op.encoding >> 0) & 0x3f) {
// add.s, sub.s, mul.s
case 0:
case 1:
case 2:
MIPSInt::Int_FPU3op(mips, op);
return 1;
// div.s
case 3:
MIPSInt::Int_FPU3op(mips, op);
return 29;
// sqrt.s, abs.s, mov.s, neg.s, round.w.s, trunc.w.s, ceil.w.s, floor.w.s, cvt.w.s
case 4:
case 5:
case 6:
case 7:
case 12:
case 13:
case 14:
case 15:
case 36:
MIPSInt::Int_FPU2op(mips, op);
return 1;
// dis.int
case 38:
MIPSInt::Int_Interrupt(mips, op);
return 1;
// c.f.s, c.un.s, c.eq.s, c.ueq.s, c.olt.s, c.ult.s, c.ole.s, c.ule.s, c.sf.s, c.ngle.s, c.seq.s, c.ngl.s, c.lt.s, c.nge.s, c.le.s, c.ngt.s
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
case 56:
case 57:
case 58:
case 59:
case 60:
case 61:
case 62:
case 63:
MIPSInt::Int_FPUComp(mips, op);
return 1;
default:
return -1;
}
}
case 20:
{
switch ((op.encoding >> 0) & 0x3f) {
// cvt.s.w
case 32:
MIPSInt::Int_FPU2op(mips, op);
return 1;
default:
return -1;
}
}
default:
return -1;
}
}
case 18:
{
switch ((op.encoding >> 21) & 0x1f) {
// mfv, mtv
case 3:
case 7:
MIPSInt::Int_Mftv(mips, op);
return 2;
case 8:
{
switch ((op.encoding >> 16) & 0x3) {
// bvf, bvt, bvfl, bvtl
case 0:
case 1:
case 2:
case 3:
MIPSInt::Int_VBranch(mips, op);
return 2;
default:
return -1;
}
}
default:
return -1;
}
}
case 24:
{
switch ((op.encoding >> 23) & 0x7) {
// vadd, vsub, vdiv
case 0:
case 1:
case 7:
MIPSInt::Int_VecDo3(mips, op);
return 2;
// vsbn
case 2:
MIPSInt::Int_Vsbn(mips, op);
return 2;
default:
return -1;
}
}
case 25:
{
switch ((op.encoding >> 23) & 0x7) {
// vmul
case 0:
MIPSInt::Int_VecDo3(mips, op);
return 2;
// vdot
case 1:
MIPSInt::Int_VDot(mips, op);
return 2;
// vscl
case 2:
MIPSInt::Int_VScl(mips, op);
return 2;
// vhdp
case 4:
MIPSInt::Int_VHdp(mips, op);
return 2;
// vcrs
case 5:
MIPSInt::Int_Vcrs(mips, op);
return 2;
// vdet
case 6:
MIPSInt::Int_Vdet(mips, op);
return 2;
default:
return -1;
}
}
case 26:
{
switch ((op.encoding >> 24) & 0x3) {
// RUNBLOCK
case 0:
MIPSInt::Int_Emuhack(mips, op);
return 2;
// RetKrnl, CallRepl
case 1:
case 2:
MIPSInt::Int_Emuhack(mips, op);
return 1;
default:
return -1;
}
}
case 27:
{
switch ((op.encoding >> 23) & 0x7) {
// vcmp
case 0:
MIPSInt::Int_Vcmp(mips, op);
return 2;
// vmin, vmax
case 2:
case 3:
MIPSInt::Int_Vminmax(mips, op);
return 2;
// vscmp
case 5:
MIPSInt::Int_Vscmp(mips, op);
return 2;
// vsge
case 6:
MIPSInt::Int_Vsge(mips, op);
return 2;
// vslt
case 7:
MIPSInt::Int_Vslt(mips, op);
return 2;
default:
return -1;
}
}
case 28:
{
switch ((op.encoding >> 0) & 0x3f) {
// mfic, mtic
case 36:
case 38:
MIPSInt::Int_Special2(mips, op);
return 1;
default:
return -1;
}
}
case 31:
{
switch ((op.encoding >> 0) & 0x3f) {
// ext, ins
case 0:
case 4:
MIPSInt::Int_Special3(mips, op);
return 1;
case 24:
case 32:
{
switch ((op.encoding >> 6) & 0x1f) {
// wsbh, wsbw
case 2:
case 3:
MIPSInt::Int_Allegrex2(mips, op);
return 1;
// seb, bitrev, seh
case 16:
case 20:
case 24:
MIPSInt::Int_Allegrex(mips, op);
return 1;
default:
return -1;
}
}
default:
return -1;
}
}
// lb, lh, lwl, lw, lbu, lhu, lwr, sb, sh, swl, sw, swr
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 40:
case 41:
case 42:
case 43:
case 46:
MIPSInt::Int_ITypeMem(mips, op);
return 1;
// cache
case 47:
MIPSInt::Int_Cache(mips, op);
return 1;
// ll, sc
case 48:
case 56:
MIPSInt::Int_StoreSync(mips, op);
return 1;
// lwc1, swc1
case 49:
case 57:
MIPSInt::Int_FPULS(mips, op);
return 1;
// lv.s, sv.s
case 50:
case 58:
MIPSInt::Int_SV(mips, op);
return 2;
case 52:
{
switch ((op.encoding >> 21) & 0x1f) {
case 0:
{
switch ((op.encoding >> 16) & 0x1f) {
// vmov, vabs, vneg, vsat0, vsat1, vrcp, vrsq, vsin, vcos, vexp2, vlog2, vsqrt, vasin, vnrcp, vnsin, vrexp2
case 0:
case 1:
case 2:
case 4:
case 5:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 26:
case 28:
MIPSInt::Int_VV2Op(mips, op);
return 2;
// vidt
case 3:
MIPSInt::Int_Vidt(mips, op);
return 2;
// vzero, vone
case 6:
case 7:
MIPSInt::Int_VVectorInit(mips, op);
return 2;
default:
return -1;
}
}
case 1:
{
switch ((op.encoding >> 16) & 0x1f) {
// vrnds
case 0:
MIPSInt::Int_Vrnds(mips, op);
return 2;
// vrndi, vrndf1, vrndf2
case 1:
case 2:
case 3:
MIPSInt::Int_VrndX(mips, op);
return 2;
// vf2h
case 18:
MIPSInt::Int_Vf2h(mips, op);
return 2;
// vh2f
case 19:
MIPSInt::Int_Vh2f(mips, op);
return 2;
// vsbz
case 22:
MIPSInt::Int_Vsbz(mips, op);
return 2;
// vlgb
case 23:
MIPSInt::Int_Vlgb(mips, op);
return 2;
// vuc2ifs, vc2i, vus2i, vs2i
case 24:
case 25:
case 26:
case 27:
MIPSInt::Int_Vx2i(mips, op);
return 2;
// vi2uc, vi2c, vi2us, vi2s
case 28:
case 29:
case 30:
case 31:
MIPSInt::Int_Vi2x(mips, op);
return 2;
default:
return -1;
}
}
case 2:
{
switch ((op.encoding >> 16) & 0x1f) {
// vsrt1
case 0:
MIPSInt::Int_Vsrt1(mips, op);
return 2;
// vsrt2
case 1:
MIPSInt::Int_Vsrt2(mips, op);
return 2;
// vbfy1, vbfy2
case 2:
case 3:
MIPSInt::Int_Vbfy(mips, op);
return 2;
// vocp
case 4:
MIPSInt::Int_Vocp(mips, op);
return 2;
// vsocp
case 5:
MIPSInt::Int_Vsocp(mips, op);
return 2;
// vfad
case 6:
MIPSInt::Int_Vfad(mips, op);
return 2;
// vavg
case 7:
MIPSInt::Int_Vavg(mips, op);
return 2;
// vsrt3
case 8:
MIPSInt::Int_Vsrt3(mips, op);
return 2;
// vsrt4
case 9:
MIPSInt::Int_Vsrt4(mips, op);
return 2;
// vsgn
case 10:
MIPSInt::Int_Vsgn(mips, op);
return 2;
// vmfvc
case 16:
MIPSInt::Int_Vmfvc(mips, op);
return 2;
// vmtvc
case 17:
MIPSInt::Int_Vmtvc(mips, op);
return 2;
// vt4444, vt5551, vt5650
case 25:
case 26:
case 27:
MIPSInt::Int_ColorConv(mips, op);
return 2;
default:
return -1;
}
}
// vcst
case 3:
MIPSInt::Int_Vcst(mips, op);
return 2;
// vf2in, vf2iz, vf2iu, vf2id
case 16:
case 17:
case 18:
case 19:
MIPSInt::Int_Vf2i(mips, op);
return 2;
// vi2f
case 20:
MIPSInt::Int_Vi2f(mips, op);
return 2;
// vcmov
case 21:
MIPSInt::Int_Vcmov(mips, op);
return 2;
// vwbn, vwbn, vwbn, vwbn, vwbn, vwbn, vwbn, vwbn
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
MIPSInt::Int_Vwbn(mips, op);
return 2;
default:
return -1;
}
}
// lv, lv.q, sv, sv.q
case 53:
case 54:
case 61:
case 62:
MIPSInt::Int_SVQ(mips, op);
return 2;
case 55:
{
switch ((op.encoding >> 23) & 0x7) {
// vpfxs, vpfxs, vpfxt, vpfxt, vpfxd, vpfxd
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
MIPSInt::Int_VPFX(mips, op);
return 2;
// viim.s, vfim.s
case 6:
case 7:
MIPSInt::Int_Viim(mips, op);
return 2;
default:
return -1;
}
}
case 60:
{
switch ((op.encoding >> 21) & 0x1f) {
// vmmul, vmmul, vmmul, vmmul
case 0:
case 1:
case 2:
case 3:
MIPSInt::Int_Vmmul(mips, op);
return 2;
// v(h)tfm2, v(h)tfm2, v(h)tfm2, v(h)tfm2, v(h)tfm3, v(h)tfm3, v(h)tfm3, v(h)tfm3, v(h)tfm4, v(h)tfm4, v(h)tfm4, v(h)tfm4
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
MIPSInt::Int_Vtfm(mips, op);
return 2;
// vmscl, vmscl, vmscl, vmscl
case 16:
case 17:
case 18:
case 19:
MIPSInt::Int_Vmscl(mips, op);
return 2;
// vcrsp.t/vqmul.q, vcrsp.t/vqmul.q, vcrsp.t/vqmul.q, vcrsp.t/vqmul.q
case 20:
case 21:
case 22:
case 23:
MIPSInt::Int_CrossQuat(mips, op);
return 2;
case 28:
{
switch ((op.encoding >> 16) & 0xf) {
// vmmov
case 0:
MIPSInt::Int_Vmmov(mips, op);
return 2;
// vmidt, vmzero, vmone
case 3:
case 6:
case 7:
MIPSInt::Int_VMatrixInit(mips, op);
return 2;
default:
return -1;
}
}
// vrot
case 29:
MIPSInt::Int_Vrot(mips, op);
return 2;
default:
return -1;
}
}
// vflush
case 63:
MIPSInt::Int_Vflush(mips, op);
return 2;
default:
return -1;
}
}