mirror of
https://github.com/libretro/ppsspp.git
synced 2024-12-13 20:22:38 +00:00
df12802a5a
Implement Vsocp
1168 lines
37 KiB
C++
1168 lines
37 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/.
|
|
|
|
#include "MIPSTables.h"
|
|
|
|
#include "MIPS.h"
|
|
#include "MIPSDis.h"
|
|
#include "MIPSDisVFPU.h"
|
|
#include "MIPSInt.h"
|
|
#include "MIPSIntVFPU.h"
|
|
#include "MIPSCodeUtils.h"
|
|
#include "../../Core/CoreTiming.h"
|
|
#include "../Debugger/Breakpoints.h"
|
|
|
|
#include "JitCommon/JitCommon.h"
|
|
|
|
enum MipsEncoding
|
|
{
|
|
Imme,
|
|
Spec,
|
|
Spe2,
|
|
Spe3,
|
|
RegI,
|
|
Cop0,
|
|
Cop0CO,
|
|
Cop1,
|
|
Cop1BC,
|
|
Cop2,
|
|
Cop2BC2,
|
|
Cop2Rese,
|
|
VFPU0,
|
|
VFPU1,
|
|
VFPU3,
|
|
VFPU4Jump,
|
|
VFPU7,
|
|
VFPU4,
|
|
VFPU5,
|
|
VFPU6,
|
|
VFPUMatrix1,
|
|
VFPU9,
|
|
ALLEGREX0,
|
|
Emu,
|
|
Rese,
|
|
NumEncodings
|
|
};
|
|
|
|
struct MIPSInstruction
|
|
{
|
|
int altEncoding;
|
|
const char *name;
|
|
MIPSComp::MIPSCompileFunc compile;
|
|
#ifndef FINAL
|
|
MIPSDisFunc disasm;
|
|
#endif
|
|
MIPSInterpretFunc interpret;
|
|
//MIPSInstructionInfo information;
|
|
u32 flags;
|
|
};
|
|
|
|
#define INVALID {-2}
|
|
#define N(a) a
|
|
|
|
#ifndef FINAL
|
|
#define ENCODING(a) {a}
|
|
#define INSTR(name, comp, dis, inter, flags) {-1, N(name), comp, dis, inter, flags}
|
|
#else
|
|
#define ENCODING(a) {a}
|
|
#define INSTR(name, comp, dis, inter, flags) {-1, comp, inter, flags}
|
|
#endif
|
|
|
|
|
|
using namespace MIPSDis;
|
|
using namespace MIPSInt;
|
|
using namespace MIPSComp;
|
|
//regregreg instructions
|
|
const MIPSInstruction tableImmediate[64] = //xxxxxx .....
|
|
{
|
|
//0
|
|
ENCODING(Spec),
|
|
ENCODING(RegI),
|
|
INSTR("j", &Jit::Comp_Jump, Dis_JumpType, Int_JumpType, IS_JUMP|IN_IMM26|DELAYSLOT),
|
|
INSTR("jal", &Jit::Comp_Jump, Dis_JumpType, Int_JumpType, IS_JUMP|IN_IMM26|OUT_RA|DELAYSLOT),
|
|
INSTR("beq", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT),
|
|
INSTR("bne", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT),
|
|
INSTR("blez", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT),
|
|
INSTR("bgtz", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT),
|
|
//8
|
|
INSTR("addi", &Jit::Comp_IType, Dis_addi, Int_IType, IN_RS|IN_IMM16|OUT_RT),
|
|
INSTR("addiu", &Jit::Comp_IType, Dis_addi, Int_IType, IN_RS|IN_IMM16|OUT_RT),
|
|
INSTR("slti", &Jit::Comp_IType, Dis_IType, Int_IType, IN_RS|IN_IMM16|OUT_RT),
|
|
INSTR("sltiu", &Jit::Comp_IType, Dis_IType, Int_IType, IN_RS|IN_IMM16|OUT_RT),
|
|
INSTR("andi", &Jit::Comp_IType, Dis_IType, Int_IType, IN_RS|IN_IMM16|OUT_RT),
|
|
INSTR("ori", &Jit::Comp_IType, Dis_ori, Int_IType, IN_RS|IN_IMM16|OUT_RT),
|
|
INSTR("xori", &Jit::Comp_IType, Dis_IType, Int_IType, IN_RS|IN_IMM16|OUT_RT),
|
|
INSTR("lui", &Jit::Comp_IType, Dis_IType1, Int_IType, IN_IMM16|OUT_RT),
|
|
//16
|
|
ENCODING(Cop0), //cop0
|
|
ENCODING(Cop1), //cop1
|
|
ENCODING(Cop2), //cop2
|
|
INVALID, //copU
|
|
|
|
INSTR("beql", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT), //L = likely
|
|
INSTR("bnel", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT),
|
|
INSTR("blezl", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT),
|
|
INSTR("bgtzl", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT),
|
|
//24
|
|
{VFPU0},
|
|
{VFPU1},
|
|
{Emu},
|
|
{VFPU3},
|
|
{Spe2},//special2
|
|
{-2}, //, "jalx", 0, Dis_JumpType, Int_JumpType},
|
|
{-2},
|
|
{Spe3},//special3
|
|
//32
|
|
INSTR("lb", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_MEM|IN_IMM16|IN_RS_ADDR|OUT_RT),
|
|
INSTR("lh", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_MEM|IN_IMM16|IN_RS_ADDR|OUT_RT),
|
|
INSTR("lwl", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_MEM|IN_IMM16|IN_RS_ADDR|OUT_RT),
|
|
INSTR("lw", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_MEM|IN_IMM16|IN_RS_ADDR|OUT_RT),
|
|
INSTR("lbu", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_MEM|IN_IMM16|IN_RS_ADDR|OUT_RT),
|
|
INSTR("lhu", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_MEM|IN_IMM16|IN_RS_ADDR|OUT_RT),
|
|
INSTR("lwr", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_MEM|IN_IMM16|IN_RS_ADDR|OUT_RT),
|
|
{-2},
|
|
//40
|
|
INSTR("sb", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_IMM16|IN_RS_ADDR|IN_RT|OUT_MEM),
|
|
INSTR("sh", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_IMM16|IN_RS_ADDR|IN_RT|OUT_MEM),
|
|
INSTR("swl", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_IMM16|IN_RS_ADDR|IN_RT|OUT_MEM),
|
|
INSTR("sw", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_IMM16|IN_RS_ADDR|IN_RT|OUT_MEM),
|
|
{-2},
|
|
{-2},
|
|
INSTR("swr", &Jit::Comp_ITypeMem, Dis_ITypeMem, Int_ITypeMem, IN_IMM16|IN_RS_ADDR|IN_RT|OUT_MEM),
|
|
INSTR("cache", &Jit::Comp_Generic, Dis_Generic, Int_Cache, 0),
|
|
//48
|
|
INSTR("ll", &Jit::Comp_Generic, Dis_Generic, Int_StoreSync, 0),
|
|
INSTR("lwc1", &Jit::Comp_FPULS, Dis_FPULS, Int_FPULS, IN_RT|IN_RS_ADDR),
|
|
INSTR("lv.s", &Jit::Comp_Generic, Dis_SV, Int_SV, IS_VFPU),
|
|
{-2}, // HIT THIS IN WIPEOUT
|
|
{VFPU4Jump},
|
|
INSTR("lv", &Jit::Comp_Generic, Dis_SVLRQ, Int_SVQ, IS_VFPU),
|
|
INSTR("lv.q", &Jit::Comp_Generic, Dis_SVQ, Int_SVQ, IS_VFPU), //copU
|
|
{VFPU5},
|
|
//56
|
|
INSTR("sc", &Jit::Comp_Generic, Dis_Generic, Int_StoreSync, 0),
|
|
INSTR("swc1", &Jit::Comp_FPULS, Dis_FPULS, Int_FPULS, 0), //copU
|
|
INSTR("sv.s", &Jit::Comp_Generic, Dis_SV, Int_SV,IS_VFPU),
|
|
{-2},
|
|
//60
|
|
{VFPU6},
|
|
INSTR("sv", &Jit::Comp_Generic, Dis_SVLRQ, Int_SVQ, IS_VFPU), //copU
|
|
INSTR("sv.q", &Jit::Comp_Generic, Dis_SVQ, Int_SVQ, IS_VFPU),
|
|
INSTR("vflush", &Jit::Comp_Generic, Dis_Vflush, Int_Vflush, IS_VFPU),
|
|
};
|
|
|
|
const MIPSInstruction tableSpecial[64] = /// 000000 ...... ...... .......... xxxxxx
|
|
{
|
|
INSTR("sll", &Jit::Comp_ShiftType, Dis_ShiftType, Int_ShiftType, OUT_RD|IN_RT|IN_SA),
|
|
{-2}, // copu
|
|
|
|
INSTR("srl", &Jit::Comp_ShiftType, Dis_ShiftType, Int_ShiftType, OUT_RD|IN_RT|IN_SA),
|
|
INSTR("sra", &Jit::Comp_ShiftType, Dis_ShiftType, Int_ShiftType, OUT_RD|IN_RT|IN_SA),
|
|
INSTR("sllv", &Jit::Comp_ShiftType, Dis_VarShiftType, Int_ShiftType, OUT_RD|IN_RT|IN_RS_SHIFT),
|
|
{-2},
|
|
INSTR("srlv", &Jit::Comp_ShiftType, Dis_VarShiftType, Int_ShiftType, OUT_RD|IN_RT|IN_RS_SHIFT),
|
|
INSTR("srav", &Jit::Comp_ShiftType, Dis_VarShiftType, Int_ShiftType, OUT_RD|IN_RT|IN_RS_SHIFT),
|
|
|
|
//8
|
|
INSTR("jr", &Jit::Comp_JumpReg, Dis_JumpRegType, Int_JumpRegType,0),
|
|
INSTR("jalr", &Jit::Comp_JumpReg, Dis_JumpRegType, Int_JumpRegType,0),
|
|
INSTR("movz", &Jit::Comp_RType3, Dis_RType3, Int_RType3, OUT_RD|IN_RS|IN_RT),
|
|
INSTR("movn", &Jit::Comp_RType3, Dis_RType3, Int_RType3, OUT_RD|IN_RS|IN_RT),
|
|
INSTR("syscall", &Jit::Comp_Syscall, Dis_Syscall, Int_Syscall,0),
|
|
INSTR("break", &Jit::Comp_Generic, Dis_Generic, Int_Break, 0),
|
|
{-2},
|
|
INSTR("sync", &Jit::Comp_Generic, Dis_Generic, Int_Sync, 0),
|
|
|
|
//16
|
|
INSTR("mfhi", &Jit::Comp_Generic, Dis_FromHiloTransfer, Int_MulDivType, OUT_RD|IN_OTHER),
|
|
INSTR("mthi", &Jit::Comp_Generic, Dis_ToHiloTransfer, Int_MulDivType, IN_RS|OUT_OTHER),
|
|
INSTR("mflo", &Jit::Comp_Generic, Dis_FromHiloTransfer, Int_MulDivType, OUT_RD|IN_OTHER),
|
|
INSTR("mtlo", &Jit::Comp_Generic, Dis_ToHiloTransfer, Int_MulDivType, IN_RS|OUT_OTHER),
|
|
{-2},
|
|
{-2},
|
|
INSTR("clz", &Jit::Comp_Generic, Dis_RType2, Int_RType2, OUT_RD|IN_RS|IN_RT),
|
|
INSTR("clo", &Jit::Comp_Generic, Dis_RType2, Int_RType2, OUT_RD|IN_RS|IN_RT),
|
|
|
|
//24
|
|
INSTR("mult", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
INSTR("multu", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
INSTR("div", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
INSTR("divu", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
INSTR("madd", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
INSTR("maddu", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
{-2},
|
|
{-2},
|
|
|
|
//32
|
|
INSTR("add", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("addu", &Jit::Comp_RType3, Dis_addu, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("sub", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("subu", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("and", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("or", &Jit::Comp_RType3, Dis_addu, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("xor", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("nor", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
|
|
//40
|
|
{-2},
|
|
{-2},
|
|
INSTR("slt", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("sltu", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("max", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("min", &Jit::Comp_RType3, Dis_RType3, Int_RType3,IN_RS|IN_RT|OUT_RD),
|
|
INSTR("msub", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
INSTR("msubu", &Jit::Comp_Generic, Dis_MulDivType, Int_MulDivType, IN_RS|IN_RT|OUT_OTHER),
|
|
|
|
//48
|
|
INSTR("tge", &Jit::Comp_Generic, Dis_RType3, 0, 0),
|
|
INSTR("tgeu", &Jit::Comp_Generic, Dis_RType3, 0, 0),
|
|
INSTR("tlt", &Jit::Comp_Generic, Dis_RType3, 0, 0),
|
|
INSTR("tltu", &Jit::Comp_Generic, Dis_RType3, 0, 0),
|
|
INSTR("teq", &Jit::Comp_Generic, Dis_RType3, 0, 0),
|
|
{-2},
|
|
INSTR("tne", &Jit::Comp_Generic, Dis_RType3, 0, 0),
|
|
{-2},
|
|
|
|
//56
|
|
{-2}, {-2}, {-2}, {-2}, {-2},
|
|
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
};
|
|
|
|
const MIPSInstruction tableSpecial2[64] =
|
|
{
|
|
INSTR("add.s", &Jit::Comp_FPU3op, Dis_FPU3op, Int_FPU3op, 0),
|
|
INSTR("sub.s", &Jit::Comp_FPU3op, Dis_FPU3op, Int_FPU3op, 0),
|
|
INSTR("mul.s", &Jit::Comp_FPU3op, Dis_FPU3op, Int_FPU3op, 0),
|
|
INSTR("div.s", &Jit::Comp_FPU3op, Dis_FPU3op, Int_FPU3op, 0),
|
|
INSTR("sqrt.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
INSTR("abs.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
INSTR("mov.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
INSTR("neg.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
//8
|
|
{-2}, {-2}, {-2}, {-2},
|
|
INSTR("round.w.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
INSTR("trunc.w.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
INSTR("ceil.w.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
INSTR("floor.w.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
|
|
//16
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
//24
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
//32
|
|
INSTR("cvt.s.w", &Jit::Comp_Generic, Dis_FPU2op, Int_FPU2op, 0),
|
|
{-2}, {-2}, {-2},
|
|
//36
|
|
INSTR("cvt.w.s", &Jit::Comp_Generic, Dis_FPU2op, Int_FPU2op, 0),
|
|
{-2},
|
|
INSTR("dis.int", &Jit::Comp_Generic, Dis_Generic, Int_Interrupt, 0),
|
|
{-2},
|
|
//40
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
//48
|
|
INSTR("c.f", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.un", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.eq", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.ueq", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.olt", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.ult", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.ole", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.ule", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.sf", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.ngle",&Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.seq", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.ngl", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.lt", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.nge", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.le", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
INSTR("c.ngt", &Jit::Comp_Generic, Dis_FPUComp, Int_FPUComp, OUT_FPUFLAG),
|
|
};
|
|
|
|
|
|
const MIPSInstruction tableSpecial3[64] =
|
|
{
|
|
INSTR("ext", &Jit::Comp_Generic, Dis_Special3, Int_Special3, IN_RS|OUT_RT),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
INSTR("ins", &Jit::Comp_Generic, Dis_Special3, Int_Special3, IN_RS|OUT_RT),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
//8
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
//16
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
//32
|
|
{ALLEGREX0},
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
//40
|
|
{ALLEGREX0},
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
|
|
{-2}, {-2}, {-2},
|
|
INSTR("rdhwr", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2}, {-2}, {-2}, {-2},
|
|
};
|
|
|
|
|
|
const MIPSInstruction tableRegImm[32] =
|
|
{
|
|
INSTR("bltz", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
|
|
INSTR("bgez", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
|
|
INSTR("bltzl", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
|
|
INSTR("bgezl", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
|
|
INSTR("tgei", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("tgeiu", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("tlti", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("tltiu", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("teqi", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2},
|
|
INSTR("tnei", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2},
|
|
|
|
INSTR("bltzal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA),
|
|
INSTR("bgezal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA),
|
|
INSTR("bltzall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA), //L = likely
|
|
INSTR("bgezall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
INSTR("synci", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
};
|
|
|
|
const MIPSInstruction tableCop2[32] =
|
|
{
|
|
INSTR("mfc2", &Jit::Comp_Generic, Dis_Generic, 0, OUT_RT),
|
|
{-2},
|
|
INSTR("cfc2", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("mfv", &Jit::Comp_Generic, Dis_Mftv, Int_Mftv, 0),
|
|
INSTR("mtc2", &Jit::Comp_Generic, Dis_Generic, 0, IN_RT),
|
|
{-2},
|
|
INSTR("ctc2", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("mtv", &Jit::Comp_Generic, Dis_Mftv, Int_Mftv, 0),
|
|
|
|
{Cop2BC2},
|
|
INSTR("??", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("??", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("??", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("??", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("??", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("??", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("??", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
};
|
|
|
|
const MIPSInstruction tableCop2BC2[4] =
|
|
{
|
|
INSTR("bvf", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
|
|
INSTR("bvt", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
|
|
INSTR("bvfl", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
|
|
INSTR("bvtl", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
|
|
};
|
|
|
|
const MIPSInstruction tableCop0[32] =
|
|
{
|
|
INSTR("mfc0", &Jit::Comp_Generic, Dis_Generic, 0, OUT_RT),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
INSTR("mtc0", &Jit::Comp_Generic, Dis_Generic, 0, IN_RT),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
|
|
{-2},
|
|
{-2},
|
|
INSTR("rdpgpr", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("mfmc0", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
|
|
{-2},
|
|
{-2},
|
|
INSTR("wrpgpr", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2},
|
|
|
|
{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},
|
|
{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},{Cop0CO},
|
|
};
|
|
|
|
|
|
//we won't encounter these since we only do user mode emulation
|
|
MIPSInstruction tableCop0CO[64] =
|
|
{
|
|
{-2},
|
|
INSTR("tlbr", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("tlbwi", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
INSTR("tlbwr", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2},
|
|
|
|
INSTR("tlbp", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
|
|
INSTR("eret", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
INSTR("iack", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2}, {-2}, {-2}, {-2}, {-2},
|
|
INSTR("deret", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
|
|
INSTR("wait", &Jit::Comp_Generic, Dis_Generic, 0, 0),
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
};
|
|
|
|
|
|
MIPSInstruction tableCop1[32] =
|
|
{
|
|
INSTR("mfc1",&Jit::Comp_mxc1, Dis_mxc1,Int_mxc1, OUT_RT),
|
|
{-2},
|
|
INSTR("cfc1",&Jit::Comp_mxc1, Dis_mxc1,Int_mxc1, 0),
|
|
{-2},
|
|
INSTR("mtc1",&Jit::Comp_mxc1, Dis_mxc1,Int_mxc1, IN_RT),
|
|
{-2},
|
|
INSTR("ctc1",&Jit::Comp_mxc1, Dis_mxc1,Int_mxc1, 0),
|
|
{-2},
|
|
|
|
{Cop1BC}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
|
|
{Spe2}, {-2}, {-2}, {-2},
|
|
{Spe2}, {-2}, {-2}, {-2},
|
|
|
|
{-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2},
|
|
};
|
|
|
|
MIPSInstruction tableCop1BC[32] =
|
|
{
|
|
{-1,"bc1f", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
|
|
{-1,"bc1t", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
|
|
{-1,"bc1fl", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
|
|
{-1,"bc1tl", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
|
|
{-2},{-2},{-2},{-2},
|
|
{-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2},
|
|
{-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2},
|
|
{-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2},
|
|
};
|
|
|
|
MIPSInstruction tableVFPU0[8] =
|
|
{
|
|
INSTR("vadd",&Jit::Comp_Generic, Dis_VectorSet3, Int_VecDo3, IS_VFPU),
|
|
INSTR("vsub",&Jit::Comp_Generic, Dis_VectorSet3, Int_VecDo3, IS_VFPU),
|
|
INSTR("vsbn",&Jit::Comp_Generic, Dis_VectorSet3, 0, IS_VFPU),
|
|
{-2}, {-2}, {-2}, {-2},
|
|
|
|
INSTR("vdiv",&Jit::Comp_Generic, Dis_VectorSet3, Int_VecDo3, IS_VFPU),
|
|
};
|
|
|
|
MIPSInstruction tableVFPU1[8] =
|
|
{
|
|
INSTR("vmul",&Jit::Comp_Generic, Dis_VectorSet3, Int_VecDo3, IS_VFPU),
|
|
INSTR("vdot",&Jit::Comp_Generic, Dis_VectorDot, Int_VDot, IS_VFPU),
|
|
INSTR("vscl",&Jit::Comp_Generic, Dis_VScl, Int_VScl, IS_VFPU),
|
|
{-2},
|
|
INSTR("vhdp",&Jit::Comp_Generic, Dis_Generic, Int_VHdp, IS_VFPU),
|
|
INSTR("vcrs",&Jit::Comp_Generic, Dis_Vcrs, Int_Vcrs, IS_VFPU),
|
|
INSTR("vdet",&Jit::Comp_Generic, Dis_Generic, Int_Vdet, IS_VFPU),
|
|
{-2},
|
|
};
|
|
|
|
MIPSInstruction tableVFPU3[8] = //011011 xxx
|
|
{
|
|
INSTR("vcmp",&Jit::Comp_Generic, Dis_Vcmp, Int_Vcmp, IS_VFPU),
|
|
{-2},
|
|
INSTR("vmin",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vminmax, IS_VFPU),
|
|
INSTR("vmax",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vminmax, IS_VFPU),
|
|
{-2},
|
|
INSTR("vscmp",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vscmp, IS_VFPU),
|
|
INSTR("vsge",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vsge, IS_VFPU),
|
|
INSTR("vslt",&Jit::Comp_Generic, Dis_VectorSet3, Int_Vslt, IS_VFPU),
|
|
};
|
|
|
|
|
|
MIPSInstruction tableVFPU4Jump[32] = //110100 xxxxx
|
|
{
|
|
{VFPU4},
|
|
{VFPU7},
|
|
{VFPU9},
|
|
INSTR("vcst", &Jit::Comp_Generic, Dis_Vcst, Int_Vcst, IS_VFPU),
|
|
{-2},{-2},{-2},{-2},
|
|
|
|
//8
|
|
{-2},{-2},{-2},{-2},
|
|
{-2},{-2},{-2},{-2},
|
|
|
|
//16
|
|
INSTR("vf2in", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU),
|
|
INSTR("vf2iz", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU),
|
|
INSTR("vf2iu", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU),
|
|
INSTR("vf2id", &Jit::Comp_Generic, Dis_Vf2i, Int_Vf2i, IS_VFPU),
|
|
//20
|
|
INSTR("vi2f", &Jit::Comp_Generic, Dis_Vf2i, Int_Vi2f, IS_VFPU),
|
|
INSTR("vcmov", &Jit::Comp_Generic, Dis_Vcmov,Int_Vcmov,IS_VFPU),
|
|
{-2},
|
|
{-2},
|
|
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
INSTR("vwbn.s", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
};
|
|
|
|
MIPSInstruction tableVFPU7[32] =
|
|
{
|
|
INSTR("vrnds", &Jit::Comp_Generic, Dis_Generic, Int_Vrnds, IS_VFPU),
|
|
INSTR("vrndi", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU),
|
|
INSTR("vrndf1", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU),
|
|
INSTR("vrndf2", &Jit::Comp_Generic, Dis_Generic, Int_VrndX, IS_VFPU),
|
|
|
|
{-2},{-2},{-2},{-2},
|
|
//8
|
|
{-2},{-2},{-2},{-2},
|
|
{-2},{-2},{-2},{-2},
|
|
//16
|
|
{-2},
|
|
{-2},
|
|
INSTR("vf2h", &Jit::Comp_Generic, Dis_Generic, Int_Vf2h, IS_VFPU),
|
|
INSTR("vh2f", &Jit::Comp_Generic, Dis_Generic, Int_Vh2f, IS_VFPU),
|
|
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
INSTR("vlgb", &Jit::Comp_Generic, Dis_Generic, 0, IS_VFPU),
|
|
//24
|
|
INSTR("vuc2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU), // Seen in BraveStory, initialization 110100 00001110000 000 0001 0000 0000
|
|
INSTR("vc2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU),
|
|
INSTR("vus2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU),
|
|
INSTR("vs2i", &Jit::Comp_Generic, Dis_Vs2i, Int_Vx2i, IS_VFPU),
|
|
|
|
INSTR("vi2uc", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU),
|
|
INSTR("vi2c", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU),
|
|
INSTR("vi2us", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU),
|
|
INSTR("vi2s", &Jit::Comp_Generic, Dis_Vi2x, Int_Vi2x, IS_VFPU),
|
|
};
|
|
|
|
// 110100 00000 10100 0000000000000000
|
|
// 110100 00000 10111 0000000000000000
|
|
MIPSInstruction tableVFPU4[32] = //110100 00000 xxxxx
|
|
{
|
|
INSTR("vmov", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU),
|
|
INSTR("vabs", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU),
|
|
INSTR("vneg", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU),
|
|
INSTR("vidt", &Jit::Comp_Generic, Dis_VectorSet1, Int_Vidt,IS_VFPU),
|
|
INSTR("vsat0", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vsat1", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vzero", &Jit::Comp_Generic, Dis_VectorSet1, Int_VVectorInit, IS_VFPU),
|
|
INSTR("vone", &Jit::Comp_Generic, Dis_VectorSet1, Int_VVectorInit, IS_VFPU),
|
|
//8
|
|
{-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2},
|
|
//16
|
|
INSTR("vrcp", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vrsq", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vsin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vcos", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vexp2", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vlog2", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vsqrt", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
INSTR("vasin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
//24
|
|
INSTR("vnrcp", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU),
|
|
{-2},
|
|
INSTR("vnsin", &Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op,IS_VFPU),
|
|
{-2},
|
|
INSTR("vrexp2",&Jit::Comp_Generic, Dis_VectorSet2, Int_VV2Op, IS_VFPU),
|
|
{-2},{-2},{-2},
|
|
//32
|
|
};
|
|
|
|
MIPSInstruction tableVFPU5[8] = //110111 xxx
|
|
{
|
|
INSTR("vpfxs",&Jit::Comp_Generic, Dis_VPFXST, Int_VPFX, IS_VFPU),
|
|
INSTR("vpfxs",&Jit::Comp_Generic, Dis_VPFXST, Int_VPFX, IS_VFPU),
|
|
INSTR("vpfxt",&Jit::Comp_Generic, Dis_VPFXST, Int_VPFX, IS_VFPU),
|
|
INSTR("vpfxt",&Jit::Comp_Generic, Dis_VPFXST, Int_VPFX, IS_VFPU),
|
|
INSTR("vpfxd", &Jit::Comp_Generic, Dis_VPFXD, Int_VPFX, IS_VFPU),
|
|
INSTR("vpfxd", &Jit::Comp_Generic, Dis_VPFXD, Int_VPFX, IS_VFPU),
|
|
INSTR("viim.s",&Jit::Comp_Generic, Dis_Viim,Int_Viim, IS_VFPU),
|
|
INSTR("vfim.s",&Jit::Comp_Generic, Dis_Viim,Int_Viim, IS_VFPU),
|
|
};
|
|
|
|
MIPSInstruction tableVFPU6[32] = //111100 xxx
|
|
{
|
|
//0
|
|
INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU),
|
|
INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU),
|
|
INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU),
|
|
INSTR("vmmul",&Jit::Comp_Generic, Dis_MatrixMult, Int_Vmmul, IS_VFPU),
|
|
|
|
INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm2",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
//8
|
|
INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm3",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
|
|
INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
INSTR("v(h)tfm4",&Jit::Comp_Generic, Dis_Vtfm, Int_Vtfm, IS_VFPU),
|
|
//16
|
|
INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU),
|
|
INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU),
|
|
INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU),
|
|
INSTR("vmscl",&Jit::Comp_Generic, Dis_Generic, Int_Vmscl, IS_VFPU),
|
|
|
|
INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU),
|
|
INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU),
|
|
INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU),
|
|
INSTR("vcrsp.t/vqmul.q",&Jit::Comp_Generic, Dis_CrossQuat, Int_CrossQuat, IS_VFPU),
|
|
//24
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
|
|
{VFPUMatrix1},
|
|
INSTR("vrot",&Jit::Comp_Generic, Dis_VRot, Int_Vrot, IS_VFPU),
|
|
{-2},
|
|
{-2},
|
|
};
|
|
|
|
MIPSInstruction tableVFPUMatrixSet1[16] = //111100 11100 0xxxx (rm x is 16)
|
|
{
|
|
INSTR("vmmov",&Jit::Comp_Generic, Dis_MatrixSet2, Int_Vmmov, IS_VFPU),
|
|
{-2},
|
|
{-2},
|
|
INSTR("vmidt",&Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU),
|
|
|
|
{-2},
|
|
{-2},
|
|
INSTR("vmzero", &Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU),
|
|
INSTR("vmone", &Jit::Comp_Generic, Dis_MatrixSet1, Int_VMatrixInit, IS_VFPU),
|
|
|
|
{-2},{-2},{-2},{-2},
|
|
{-2},{-2},{-2},{-2},
|
|
};
|
|
|
|
MIPSInstruction tableVFPU9[32] = //110100 00010 xxxxx
|
|
{
|
|
INSTR("vsrt1", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsrt1, IS_VFPU),
|
|
INSTR("vsrt2", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsrt2, IS_VFPU),
|
|
INSTR("vbfy1", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IS_VFPU),
|
|
INSTR("vbfy2", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IS_VFPU),
|
|
//4
|
|
INSTR("vocp", &Jit::Comp_Generic, Dis_Vbfy, Int_Vocp, IS_VFPU), // one's complement
|
|
INSTR("vsocp", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsocp, IS_VFPU),
|
|
INSTR("vfad", &Jit::Comp_Generic, Dis_Vfad, Int_Vfad, IS_VFPU),
|
|
INSTR("vavg", &Jit::Comp_Generic, Dis_Vfad, Int_Vavg, IS_VFPU),
|
|
//8
|
|
INSTR("vsrt3", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsrt3, IS_VFPU),
|
|
INSTR("vsrt4", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsrt4, IS_VFPU),
|
|
INSTR("vsgn", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsgn, IS_VFPU),
|
|
{-2},
|
|
//12
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
|
|
//16
|
|
INSTR("vmfvc", &Jit::Comp_Generic, Dis_Generic, Int_Vmfvc, IS_VFPU),
|
|
INSTR("vmtvc", &Jit::Comp_Generic, Dis_Generic, Int_Vmtvc, IS_VFPU),
|
|
{-2},
|
|
{-2},
|
|
|
|
//20
|
|
{-2},{-2},{-2},{-2},
|
|
//24
|
|
{-2},
|
|
INSTR("vt4444", &Jit::Comp_Generic, Dis_Generic, Int_ColorConv, IS_VFPU),
|
|
INSTR("vt5551", &Jit::Comp_Generic, Dis_Generic, Int_ColorConv, IS_VFPU),
|
|
INSTR("vt5650", &Jit::Comp_Generic, Dis_Generic, Int_ColorConv, IS_VFPU),
|
|
|
|
//28
|
|
{-2},{-2},{-2},{-2},
|
|
};
|
|
|
|
MIPSInstruction tableALLEGREX0[32] = //111111
|
|
{
|
|
{-2},
|
|
{-2},
|
|
INSTR("wsbh",&Jit::Comp_Generic, Dis_Allegrex2,Int_Allegrex2,0),
|
|
INSTR("wsbw",&Jit::Comp_Generic, Dis_Allegrex2,Int_Allegrex2,0),
|
|
{-2}, {-2}, {-2}, {-2},
|
|
//8
|
|
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
|
|
//16
|
|
INSTR("seb", &Jit::Comp_Allegrex, Dis_Allegrex,Int_Allegrex, IN_RT|OUT_RD),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
//20
|
|
INSTR("bitrev",&Jit::Comp_Generic, Dis_Allegrex,Int_Allegrex, IN_RT|OUT_RD),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
//24
|
|
INSTR("seh", &Jit::Comp_Allegrex, Dis_Allegrex,Int_Allegrex, IN_RT|OUT_RD),
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
//28
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
{-2},
|
|
};
|
|
|
|
|
|
MIPSInstruction tableEMU[4] =
|
|
{
|
|
INSTR("RUNBLOCK",&Jit::Comp_RunBlock,Dis_Emuhack,Int_Emuhack, 0xFFFFFFFF),
|
|
INSTR("RetKrnl", 0,Dis_Emuhack,Int_Emuhack, 0),
|
|
{-2},
|
|
{-2},
|
|
};
|
|
|
|
const int encodingBits[NumEncodings][2] =
|
|
{
|
|
{26, 6}, //IMME
|
|
{0, 6}, //Special
|
|
{0, 6}, //special2
|
|
{0, 6}, //special3
|
|
{16, 5}, //RegImm
|
|
{21, 5}, //Cop0
|
|
{0, 6}, //Cop0CO
|
|
{21, 5}, //Cop1
|
|
{16, 5}, //Cop1BC
|
|
{21, 5}, //Cop2
|
|
{16, 2}, //Cop2BC2
|
|
{0, 0}, //Cop2Rese
|
|
{23, 3}, //VFPU0
|
|
{23, 3}, //VFPU1
|
|
{23, 3}, //VFPU3
|
|
{21, 5}, //VFPU4Jump
|
|
{16, 5}, //VFPU7
|
|
{16, 5}, //VFPU4
|
|
{23, 3}, //VFPU5
|
|
{21, 5}, //VFPU6
|
|
{16, 4}, //VFPUMatrix1
|
|
{16, 5}, //VFPU9
|
|
{6, 5}, //ALLEGREX0
|
|
{24, 2}, //EMUHACK
|
|
};
|
|
|
|
|
|
const MIPSInstruction *mipsTables[NumEncodings] =
|
|
{
|
|
tableImmediate,
|
|
tableSpecial,
|
|
tableSpecial2,
|
|
tableSpecial3,
|
|
tableRegImm,
|
|
tableCop0,
|
|
tableCop0CO,
|
|
tableCop1,
|
|
tableCop1BC,
|
|
tableCop2,
|
|
tableCop2BC2,
|
|
0,
|
|
tableVFPU0, //vfpu0
|
|
tableVFPU1, //vfpu1
|
|
tableVFPU3, //vfpu3
|
|
tableVFPU4Jump,
|
|
tableVFPU7, //vfpu4 110100 00001
|
|
tableVFPU4, //vfpu4 110100 00000
|
|
tableVFPU5, //vfpu5 110111
|
|
tableVFPU6, //vfpu6 111100
|
|
tableVFPUMatrixSet1,
|
|
tableVFPU9,
|
|
tableALLEGREX0,
|
|
tableEMU
|
|
};
|
|
|
|
|
|
|
|
//arm encoding table
|
|
//const MIPSInstruction mipsinstructions[] =
|
|
//{
|
|
//{Comp_Unimpl,Dis_Unimpl, Info_NN, 0, 0x601, 0x1FE,0}, //could be used for drec hook :) bits 5-24 plus 0-3 are available, 19 bits are more than enough
|
|
// DATA PROCESSING INSTRUCTIONS
|
|
// S
|
|
// {Comp_AND, Dis_AND, Info_DP, 0, DATAP(0, 0), 0x20F, {0}},
|
|
//};
|
|
|
|
|
|
//Todo : generate dispatcher functions from above tables
|
|
//instead of this horribly slow abomination
|
|
|
|
const MIPSInstruction *MIPSGetInstruction(u32 op)
|
|
{
|
|
MipsEncoding encoding = Imme;
|
|
const MIPSInstruction *instr = &tableImmediate[op>>26];
|
|
while (instr->altEncoding != -1)
|
|
{
|
|
const MIPSInstruction *table = mipsTables[encoding];
|
|
int mask = ((1<<encodingBits[encoding][1])-1);
|
|
int shift = encodingBits[encoding][0];
|
|
int subop = (op >> shift) & mask;
|
|
instr = &table[subop];
|
|
if (encoding == Rese)
|
|
return 0; //invalid instruction
|
|
if (!instr)
|
|
return 0;
|
|
if (instr->altEncoding == -2)
|
|
{
|
|
//ERROR_LOG(CPU, "Invalid instruction %08x in table %i, entry %i", op, (int)encoding, subop);
|
|
return 0; //invalid instruction
|
|
}
|
|
encoding = (MipsEncoding)instr->altEncoding;
|
|
}
|
|
//alright, we have a valid MIPS instruction!
|
|
return instr;
|
|
}
|
|
|
|
|
|
|
|
void MIPSCompileOp(u32 op)
|
|
{
|
|
if (op==0)
|
|
return;
|
|
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
|
if (instr)
|
|
{
|
|
if (instr->compile)
|
|
(MIPSComp::jit->*(instr->compile))(op); // woohoo, member functions pointers!
|
|
else
|
|
{
|
|
ERROR_LOG(CPU,"MIPSCompileOp %08x failed",op);
|
|
//MessageBox(0,"ARGH2",0,0);//compile an interpreter call
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERROR_LOG(CPU, "MIPSCompileOp: Invalid instruction %08x", op);
|
|
}
|
|
}
|
|
|
|
|
|
void MIPSDisAsm(u32 op, u32 pc, char *out)
|
|
{
|
|
if (op == 0)
|
|
{
|
|
//ANDEQ R0,R0,R0 is probably not used for legitimate purposes :P
|
|
sprintf(out,"---\t---");
|
|
}
|
|
else
|
|
{
|
|
disPC = pc;
|
|
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
|
if (instr && instr->disasm)
|
|
instr->disasm(op, out);
|
|
else
|
|
{
|
|
strcpy(out, "no instruction :(");
|
|
//__asm int 3
|
|
MIPSGetInstruction(op);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void MIPSInterpret(u32 op) //only for those rare ones
|
|
{
|
|
//if ((op&0xFFFFF000) == 0xd0110000)
|
|
// Crash();
|
|
//if (atable[CRUNCH_MIPS_OP(op)].interpret)
|
|
// atable[CRUNCH_MIPS_OP(op)].interpret(op);
|
|
// else
|
|
// _dbg_assert_msg_(MIPS,0,"Trying to interpret instruction that can't be interpreted");
|
|
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
|
if (instr && instr->interpret)
|
|
instr->interpret(op);
|
|
else
|
|
{
|
|
ERROR_LOG(CPU,"Unknown instruction %08x at %08x", op, currentMIPS->pc);
|
|
// Try to disassemble it
|
|
char disasm[256];
|
|
MIPSDisAsm(op, currentMIPS->pc, disasm);
|
|
_dbg_assert_msg_(CPU, 0, disasm);
|
|
currentMIPS->pc += 4;
|
|
}
|
|
}
|
|
|
|
#define _RS ((op>>21) & 0x1F)
|
|
#define _RT ((op>>16) & 0x1F)
|
|
#define _RD ((op>>11) & 0x1F)
|
|
#define R(i) (curMips->r[i])
|
|
|
|
|
|
int MIPSInterpret_RunUntil(u64 globalTicks)
|
|
{
|
|
MIPSState *curMips = currentMIPS;
|
|
while (coreState == CORE_RUNNING)
|
|
{
|
|
// NEVER stop in a delay slot!
|
|
while (CoreTiming::downcount >= 0 && coreState == CORE_RUNNING)
|
|
{
|
|
// int cycles = 0;
|
|
{
|
|
again:
|
|
u32 op = Memory::Read_U32(curMips->pc);
|
|
//u32 op = Memory::Read_Opcode_JIT(mipsr4k.pc);
|
|
/*
|
|
// Choke on VFPU
|
|
u32 info = MIPSGetInfo(op);
|
|
if (info & IS_VFPU)
|
|
{
|
|
if (!Core_IsStepping() && !GetAsyncKeyState(VK_LSHIFT))
|
|
{
|
|
Core_EnableStepping(true);
|
|
return;
|
|
}
|
|
}*/
|
|
|
|
//2: check for breakpoint (VERY SLOW)
|
|
#if defined(_DEBUG)
|
|
if (CBreakPoints::IsAddressBreakPoint(curMips->pc))
|
|
{
|
|
Core_EnableStepping(true);
|
|
if (CBreakPoints::IsTempBreakPoint(curMips->pc))
|
|
CBreakPoints::RemoveBreakPoint(curMips->pc);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
bool wasInDelaySlot = curMips->inDelaySlot;
|
|
|
|
MIPSInterpret(op);
|
|
|
|
if (curMips->inDelaySlot)
|
|
{
|
|
// The reason we have to check this is the delay slot hack in Int_Syscall.
|
|
if (wasInDelaySlot)
|
|
{
|
|
curMips->pc = curMips->nextPC;
|
|
curMips->inDelaySlot = false;
|
|
}
|
|
CoreTiming::downcount -= 1;
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
if (CoreTiming::GetTicks() > globalTicks)
|
|
{
|
|
// DEBUG_LOG(CPU, "Hit the max ticks, bailing 1 : %llu, %llu", globalTicks, CoreTiming::GetTicks());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
CoreTiming::Advance();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static inline void DelayBranchTo(MIPSState *curMips, u32 where)
|
|
{
|
|
curMips->pc += 4;
|
|
curMips->nextPC = where;
|
|
curMips->inDelaySlot = true;
|
|
}
|
|
|
|
// Optimized interpreter loop that shortcuts the most common instructions.
|
|
// For slow platforms without JITs.
|
|
#define SIMM16 (s32)(s16)(op & 0xFFFF)
|
|
#define UIMM16 (u32)(u16)(op & 0xFFFF)
|
|
#define SUIMM16 (u32)(s32)(s16)(op & 0xFFFF)
|
|
int MIPSInterpret_RunFastUntil(u64 globalTicks)
|
|
{
|
|
MIPSState *curMips = currentMIPS;
|
|
while (coreState == CORE_RUNNING)
|
|
{
|
|
while (CoreTiming::downcount >= 0 && coreState == CORE_RUNNING) // TODO: Try to get rid of the latter check
|
|
{
|
|
again:
|
|
bool wasInDelaySlot = curMips->inDelaySlot;
|
|
u32 op = Memory::ReadUnchecked_U32(curMips->pc);
|
|
switch (op >> 29)
|
|
{
|
|
case 0x0:
|
|
{
|
|
int imm = (s16)(op&0xFFFF) << 2;
|
|
int rs = _RS;
|
|
int rt = _RT;
|
|
u32 addr = curMips->pc + imm + 4;
|
|
switch (op >> 26)
|
|
{
|
|
case 4: if (R(rt) == R(rs)) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //beq
|
|
case 5: if (R(rt) != R(rs)) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //bne
|
|
case 6: if ((s32)R(rs) <= 0) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //blez
|
|
case 7: if ((s32)R(rs) > 0) DelayBranchTo(curMips, addr); else curMips->pc += 4; break; //bgtz
|
|
default:
|
|
goto interpret;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x1:
|
|
{
|
|
int rt = _RT;
|
|
int rs = _RS;
|
|
switch (op >> 26)
|
|
{
|
|
case 8: R(rt) = R(rs) + SIMM16; break; //addi
|
|
case 9: R(rt) = R(rs) + SIMM16; break; //addiu
|
|
case 10: R(rt) = (s32)R(rs) < SIMM16; break; //slti
|
|
case 11: R(rt) = R(rs) < SUIMM16; break; //sltiu
|
|
case 12: R(rt) = R(rs) & UIMM16; break; //andi
|
|
case 13: R(rt) = R(rs) | UIMM16; break; //ori
|
|
case 14: R(rt) = R(rs) ^ UIMM16; break; //xori
|
|
case 15: R(rt) = UIMM16 << 16; break; //lui
|
|
default:
|
|
goto interpret;
|
|
}
|
|
currentMIPS->pc += 4;
|
|
}
|
|
break;
|
|
|
|
case 0x4:
|
|
{
|
|
int rt = _RT;
|
|
int rs = _RS;
|
|
int imm = (s16)(op & 0xFFFF);
|
|
u32 addr = R(rs) + imm;
|
|
switch (op >> 26)
|
|
{
|
|
case 32: R(rt) = (u32)(s32)(s8) Memory::ReadUnchecked_U8(addr); break; //lb
|
|
case 33: R(rt) = (u32)(s32)(s16)Memory::ReadUnchecked_U16(addr); break; //lh
|
|
case 35: R(rt) = Memory::ReadUnchecked_U32(addr); break; //lw
|
|
case 36: R(rt) = Memory::ReadUnchecked_U8(addr); break; //lbu
|
|
case 37: R(rt) = Memory::ReadUnchecked_U16(addr); break; //lhu
|
|
default:
|
|
goto interpret;
|
|
}
|
|
currentMIPS->pc += 4;
|
|
}
|
|
break;
|
|
|
|
case 0x5:
|
|
{
|
|
int rt = _RT;
|
|
int rs = _RS;
|
|
int imm = (s16)(op & 0xFFFF);
|
|
u32 addr = R(rs) + imm;
|
|
switch (op >> 26)
|
|
{
|
|
case 40: Memory::WriteUnchecked_U8(R(rt), addr); break; //sb
|
|
case 41: Memory::WriteUnchecked_U16(R(rt), addr); break; //sh
|
|
case 43: Memory::WriteUnchecked_U32(R(rt), addr); break; //sw
|
|
default:
|
|
goto interpret;
|
|
}
|
|
currentMIPS->pc += 4;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
interpret:
|
|
MIPSInterpret(op);
|
|
}
|
|
|
|
if (curMips->inDelaySlot)
|
|
{
|
|
// The reason we have to check this is the delay slot hack in Int_Syscall.
|
|
if (wasInDelaySlot)
|
|
{
|
|
curMips->pc = curMips->nextPC;
|
|
curMips->inDelaySlot = false;
|
|
}
|
|
CoreTiming::downcount -= 1;
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
CoreTiming::Advance();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
const char *MIPSGetName(u32 op)
|
|
{
|
|
static const char *noname = "unk";
|
|
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
|
if (!instr)
|
|
return noname;
|
|
else
|
|
return instr->name;
|
|
}
|
|
|
|
u32 MIPSGetInfo(u32 op)
|
|
{
|
|
// int crunch = CRUNCH_MIPS_OP(op);
|
|
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
|
if (instr)
|
|
return instr->flags;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
MIPSInterpretFunc MIPSGetInterpretFunc(u32 op)
|
|
{
|
|
const MIPSInstruction *instr = MIPSGetInstruction(op);
|
|
if (instr->interpret)
|
|
return instr->interpret;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// TODO: Do something that makes sense here.
|
|
int MIPSGetInstructionCycleEstimate(u32 op)
|
|
{
|
|
u32 info = MIPSGetInfo(op);
|
|
if (info & DELAYSLOT)
|
|
return 2;
|
|
else
|
|
return 1;
|
|
}
|