Merge pull request #248 from Kingcom/OpcodeFlags

Add flags to R5900 opcodes, use them for the debugger
This commit is contained in:
Pseudonym 2014-08-22 20:55:08 +01:00
commit 4512306207
6 changed files with 532 additions and 660 deletions

View File

@ -32,9 +32,6 @@ extern AppCoreThread CoreThread;
R5900DebugInterface r5900Debug;
R3000DebugInterface r3000Debug;
enum { EECAT_GPR, EECAT_CP0, EECAT_CP1, EECAT_CP2F, EECAT_CP2I, EECAT_COUNT };
enum { IOPCAT_GPR, IOPCAT_COUNT };
#ifdef WIN32
#define strcasecmp stricmp
#endif
@ -281,12 +278,14 @@ const char* R5900DebugInterface::getRegisterCategoryName(int cat)
return "GPR";
case EECAT_CP0:
return "CP0";
case EECAT_CP1:
return "CP1";
case EECAT_CP2F:
return "CP2f";
case EECAT_CP2I:
return "CP2i";
case EECAT_FPR:
return "FPR";
case EECAT_FCR:
return "FCR";
case EECAT_VU0F:
return "VU0f";
case EECAT_VU0I:
return "VU0i";
default:
return "Invalid";
}
@ -297,11 +296,12 @@ int R5900DebugInterface::getRegisterSize(int cat)
switch (cat)
{
case EECAT_GPR:
case EECAT_CP2F:
case EECAT_VU0F:
return 128;
case EECAT_CP0:
case EECAT_CP1:
case EECAT_CP2I:
case EECAT_FPR:
case EECAT_FCR:
case EECAT_VU0I:
return 32;
default:
return 0;
@ -315,9 +315,10 @@ int R5900DebugInterface::getRegisterCount(int cat)
case EECAT_GPR:
return 35; // 32 + pc + hi + lo
case EECAT_CP0:
case EECAT_CP1:
case EECAT_CP2F:
case EECAT_CP2I:
case EECAT_FPR:
case EECAT_FCR:
case EECAT_VU0F:
case EECAT_VU0I:
return 32;
default:
return 0;
@ -330,11 +331,12 @@ DebugInterface::RegisterType R5900DebugInterface::getRegisterType(int cat)
{
case EECAT_GPR:
case EECAT_CP0:
case EECAT_CP2F:
case EECAT_CP2I:
case EECAT_VU0F:
case EECAT_VU0I:
case EECAT_FCR:
default:
return NORMAL;
case EECAT_CP1:
case EECAT_FPR:
return SPECIAL;
}
}
@ -357,11 +359,13 @@ const char* R5900DebugInterface::getRegisterName(int cat, int num)
}
case EECAT_CP0:
return R5900::COP0_REG[num];
case EECAT_CP1:
case EECAT_FPR:
return R5900::COP1_REG_FP[num];
case EECAT_CP2F:
case EECAT_FCR:
return R5900::COP1_REG_FCR[num];
case EECAT_VU0F:
return R5900::COP2_REG_FP[num];
case EECAT_CP2I:
case EECAT_VU0I:
return R5900::COP2_REG_CTL[num];
default:
return "Invalid";
@ -393,13 +397,16 @@ u128 R5900DebugInterface::getRegister(int cat, int num)
case EECAT_CP0:
result = u128::From32(cpuRegs.CP0.r[num]);
break;
case EECAT_CP1:
case EECAT_FPR:
result = u128::From32(fpuRegs.fpr[num].UL);
break;
case EECAT_CP2F:
case EECAT_FCR:
result = u128::From32(fpuRegs.fprc[num]);
break;
case EECAT_VU0F:
result = VU1.VF[num].UQ;
break;
case EECAT_CP2I:
case EECAT_VU0I:
result = u128::From32(VU1.VI[num].UL);
break;
default:
@ -416,8 +423,9 @@ wxString R5900DebugInterface::getRegisterString(int cat, int num)
{
case EECAT_GPR:
case EECAT_CP0:
case EECAT_FCR:
return getRegister(cat,num).ToString();
case EECAT_CP1:
case EECAT_FPR:
{
char str[64];
sprintf(str,"%f",fpuRegs.fpr[num].f);
@ -473,13 +481,16 @@ void R5900DebugInterface::setRegister(int cat, int num, u128 newValue)
case EECAT_CP0:
cpuRegs.CP0.r[num] = newValue._u32[0];
break;
case EECAT_CP1:
case EECAT_FPR:
fpuRegs.fpr[num].UL = newValue._u32[0];
break;
case EECAT_CP2F:
case EECAT_FCR:
fpuRegs.fprc[num] = newValue._u32[0];
break;
case EECAT_VU0F:
VU1.VF[num].UQ = newValue;
break;
case EECAT_CP2I:
case EECAT_VU0I:
VU1.VI[num].UL = newValue._u32[0];
break;
default:

View File

@ -17,6 +17,9 @@
#include "MemoryTypes.h"
#include "ExpressionParser.h"
enum { EECAT_GPR, EECAT_CP0, EECAT_FPR, EECAT_FCR, EECAT_VU0F, EECAT_VU0I, EECAT_COUNT };
enum { IOPCAT_GPR, IOPCAT_COUNT };
class DebugInterface
{
public:

View File

@ -20,6 +20,7 @@
#include "SymbolMap.h"
#include "DebugInterface.h"
#include "../R5900.h"
#include "../R5900OpcodeTables.h"
static std::vector<MIPSAnalyst::AnalyzedFunction> functions;
@ -160,296 +161,182 @@ namespace MIPSAnalyst
}
}
enum BranchType { NONE, JUMP, BRANCH };
struct BranchInfo
{
BranchType type;
bool link;
bool likely;
bool toRegister;
};
bool getBranchInfo(MipsOpcodeInfo& info)
{
BranchType type = NONE;
bool link = false;
bool likely = false;
bool toRegister = false;
bool met = false;
u32 op = info.encodedOpcode;
u32 opNum = MIPS_GET_OP(op);
u32 rsNum = MIPS_GET_RS(op);
u32 rtNum = MIPS_GET_RT(op);
u32 rs = info.cpu->getRegister(0,rsNum);
u32 rt = info.cpu->getRegister(0,rtNum);
switch (MIPS_GET_OP(op))
{
case 0x00: // special
switch (MIPS_GET_FUNC(op))
{
case 0x08: // jr
type = JUMP;
toRegister = true;
break;
case 0x09: // jalr
type = JUMP;
toRegister = true;
link = true;
break;
}
break;
case 0x01: // regimm
switch (MIPS_GET_RT(op))
{
case 0x00: // bltz
case 0x02: // bltzl
case 0x10: // bltzal
case 0x12: // bltzall
type = BRANCH;
met = (((s32)rs) < 0);
likely = (rt & 2) != 0;
link = rt >= 0x10;
break;
case 0x01: // bgez
case 0x03: // bgezl
case 0x11: // bgezal
case 0x13: // bgezall
type = BRANCH;
met = (((s32)rs) >= 0);
likely = (rt & 2) != 0;
link = rt >= 0x10;
break;
}
break;
case 0x02: // j
type = JUMP;
break;
case 0x03: // jal
type = JUMP;
link = true;
break;
case 0x04: // beq
case 0x14: // beql
type = BRANCH;
met = (rt == rs);
if (MIPS_GET_RT(op) == MIPS_GET_RS(op)) // always true
info.isConditional = false;
likely = opNum >= 0x10;
break;
case 0x05: // bne
case 0x15: // bnel
type = BRANCH;
met = (rt != rs);
if (MIPS_GET_RT(op) == MIPS_GET_RS(op)) // always false
info.isConditional = false;
likely = opNum >= 0x10;
break;
case 0x06: // blez
case 0x16: // blezl
type = BRANCH;
met = (((s32)rs) <= 0);
likely = opNum >= 0x10;
break;
case 0x07: // bgtz
case 0x17: // bgtzl
type = BRANCH;
met = (((s32)rs) > 0);
likely = opNum >= 0x10;
break;
}
if (type == NONE)
return false;
info.isBranch = true;
info.isLinkedBranch = link;
info.isLikelyBranch = true;
info.isBranchToRegister = toRegister;
info.isConditional = type == BRANCH;
info.conditionMet = met;
switch (type)
{
case JUMP:
if (toRegister)
{
info.branchRegisterNum = (int)MIPS_GET_RS(op);
info.branchTarget = info.cpu->getRegister(0,info.branchRegisterNum)._u32[0];
} else {
info.branchTarget = (info.opcodeAddress & 0xF0000000) | ((op&0x03FFFFFF) << 2);
}
break;
case BRANCH:
info.branchTarget = info.opcodeAddress + 4 + ((signed short)(op&0xFFFF)<<2);
break;
case NONE:
return false;
}
return true;
}
bool getDataAccessInfo(MipsOpcodeInfo& info)
{
int size = 0;
u32 op = info.encodedOpcode;
int off = 0;
switch (MIPS_GET_OP(op))
{
case 0x20: // lb
case 0x24: // lbu
case 0x28: // sb
size = 1;
break;
case 0x21: // lh
case 0x25: // lhu
case 0x29: // sh
size = 2;
break;
case 0x23: // lw
case 0x2B: // sw
size = 4;
break;
case 0x26: // lwr
case 0x2E: // swr
size = 4;
info.lrType = LOADSTORE_RIGHT;
break;
case 0x22: // lwl
case 0x2A: // swl
size = 4;
off = -3;
info.lrType = LOADSTORE_LEFT;
break;
case 0x37: // ld
case 0x3F: // sd
size = 8;
break;
case 0x1B: // ldr
case 0x2D: // sdr
size = 8;
info.lrType = LOADSTORE_RIGHT;
break;
case 0x1A: // ldl
case 0x2C: // sdl
size = 8;
off = -7;
info.lrType = LOADSTORE_LEFT;
break;
case 0x1E: // lq
case 0x1F: // sq
size = 16;
break;
}
if (size == 0)
return false;
info.isDataAccess = true;
info.dataSize = size;
u32 rs = info.cpu->getRegister(0, (int)MIPS_GET_RS(op));
s16 imm16 = op & 0xFFFF;
info.dataAddress = rs + imm16 + off;
info.hasRelevantAddress = true;
info.releventAddress = info.dataAddress;
return true;
}
MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address) {
MipsOpcodeInfo info;
memset(&info, 0, sizeof(info));
if (cpu->isValidAddress(address) == false) {
if (cpu->isValidAddress(address) == false)
return info;
}
info.cpu = cpu;
info.opcodeAddress = address;
info.encodedOpcode = cpu->read32(address);
u32 op = info.encodedOpcode;
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
if (getBranchInfo(info) == true)
return info;
// extract all the branch related information
info.isBranch = (opcode.flags & IS_BRANCH) != 0;
if (info.isBranch)
{
info.isLinkedBranch = (opcode.flags & IS_LINKED) != 0;
info.isLikelyBranch = (opcode.flags & IS_LIKELY) != 0;
if (getDataAccessInfo(info) == true)
return info;
// gather relevant address for alu operations
// that's usually the value of the dest register
switch (MIPS_GET_OP(op)) {
case 0: // special
switch (MIPS_GET_FUNC(op)) {
case 0x0C: // syscall
u64 rs,rt;
u32 value;
switch (opcode.flags & BRANCHTYPE_MASK)
{
case BRANCHTYPE_JUMP:
info.isConditional = false;
info.branchTarget = (info.opcodeAddress & 0xF0000000) | ((op&0x03FFFFFF) << 2);
break;
case BRANCHTYPE_BRANCH:
info.isConditional = true;
info.branchTarget = info.opcodeAddress + 4 + ((s16)(op&0xFFFF)<<2);
rs = info.cpu->getRegister(0,MIPS_GET_RS(op))._u64[0];
rt = info.cpu->getRegister(0,MIPS_GET_RT(op))._u64[0];
switch (opcode.flags & CONDTYPE_MASK)
{
case CONDTYPE_EQ:
info.conditionMet = (rt == rs);
if (MIPS_GET_RT(op) == MIPS_GET_RS(op)) // always true
info.isConditional = false;
break;
case CONDTYPE_NE:
info.conditionMet = (rt != rs);
if (MIPS_GET_RT(op) == MIPS_GET_RS(op)) // always false
info.isConditional = false;
break;
case CONDTYPE_LEZ:
info.conditionMet = (((s64)rs) <= 0);
break;
case CONDTYPE_GTZ:
info.conditionMet = (((s64)rs) > 0);
break;
case CONDTYPE_LTZ:
info.conditionMet = (((s64)rs) < 0);
break;
case CONDTYPE_GEZ:
info.conditionMet = (((s64)rs) >= 0);
break;
}
break;
case BRANCHTYPE_REGISTER:
info.isConditional = false;
info.isBranchToRegister = true;
info.branchRegisterNum = (int)MIPS_GET_RS(op);
info.branchTarget = info.cpu->getRegister(0,info.branchRegisterNum)._u32[0];
break;
case BRANCHTYPE_SYSCALL:
info.isConditional = false;
info.isSyscall = true;
info.branchTarget = 0x80000000+0x180;
break;
case 0x20: // add
case 0x21: // addu
info.hasRelevantAddress = true;
info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]+cpu->getRegister(0,MIPS_GET_RT(op))._u32[0];
break;
case 0x22: // sub
case 0x23: // subu
info.hasRelevantAddress = true;
info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]-cpu->getRegister(0,MIPS_GET_RT(op))._u32[0];
break;
}
break;
case 0x08: // addi
case 0x09: // adiu
info.hasRelevantAddress = true;
info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]+((s16)(op & 0xFFFF));
break;
case 0x10: // cop0
switch (MIPS_GET_RS(op))
{
case 0x10: // tlb
switch (MIPS_GET_FUNC(op))
case BRANCHTYPE_ERET:
info.isConditional = false;
// probably shouldn't be hard coded like this...
if (cpuRegs.CP0.n.Status.b.ERL)
{
case 0x18: // eret
info.isBranch = true;
info.isConditional = false;
info.branchTarget = cpuRegs.CP0.n.ErrorEPC;
} else {
info.branchTarget = cpuRegs.CP0.n.EPC;
}
break;
case BRANCHTYPE_BC1:
info.isConditional = true;
value = info.cpu->getRegister(EECAT_FCR,31)._u32[0] & 0x00800000;
info.branchTarget = info.opcodeAddress + 4 + ((s16)(op&0xFFFF)<<2);
// probably shouldn't be hard coded like this...
if (cpuRegs.CP0.n.Status.b.ERL) {
info.branchTarget = cpuRegs.CP0.n.ErrorEPC;
} else {
info.branchTarget = cpuRegs.CP0.n.EPC;
}
switch (opcode.flags & CONDTYPE_MASK)
{
case CONDTYPE_EQ:
info.conditionMet = value == 0;
break;
case CONDTYPE_NE:
info.conditionMet = value != 0;
break;
}
break;
}
break;
}
// TODO: rest
/* // movn, movz
if (opInfo & IS_CONDMOVE) {
info.isConditional = true;
// extract the accessed memory address
info.isDataAccess = opcode.flags & IS_MEMORY;
if (info.isDataAccess)
{
if (opcode.flags & IS_LEFT)
info.lrType = LOADSTORE_LEFT;
else if (opcode.flags & IS_RIGHT)
info.lrType = LOADSTORE_RIGHT;
u32 rs = info.cpu->getRegister(0, (int)MIPS_GET_RS(op));
s16 imm16 = op & 0xFFFF;
info.dataAddress = rs + imm16;
u32 rt = cpu->GetRegValue(0, (int)MIPS_GET_RT(op));
switch (opInfo & CONDTYPE_MASK) {
case CONDTYPE_EQ:
info.conditionMet = (rt == 0);
switch (opcode.flags & MEMTYPE_MASK)
{
case MEMTYPE_BYTE:
info.dataSize = 1;
break;
case CONDTYPE_NE:
info.conditionMet = (rt != 0);
case MEMTYPE_HALF:
info.dataSize = 2;
break;
case MEMTYPE_WORD:
info.dataSize = 4;
if (info.lrType == LOADSTORE_LEFT)
info.dataAddress -= 3;
break;
case MEMTYPE_DWORD:
info.dataSize = 8;
if (info.lrType == LOADSTORE_LEFT)
info.dataAddress -= 7;
break;
case MEMTYPE_QWORD:
info.dataSize = 16;
break;
}
}*/
info.hasRelevantAddress = true;
info.releventAddress = info.dataAddress;
}
// gather relevant address for alu operations
if (opcode.flags & IS_ALU)
{
u64 rs,rt;
rs = info.cpu->getRegister(0,MIPS_GET_RS(op))._u64[0];
rt = info.cpu->getRegister(0,MIPS_GET_RT(op))._u64[0];
switch (opcode.flags & ALUTYPE_MASK)
{
case ALUTYPE_ADDI:
info.hasRelevantAddress = true;
info.releventAddress = rs+((s16)(op & 0xFFFF));
break;
case ALUTYPE_ADD:
info.hasRelevantAddress = true;
info.releventAddress = rs+rt;
break;
case ALUTYPE_SUB:
info.hasRelevantAddress = true;
info.releventAddress = rs-rt;
break;
case ALUTYPE_CONDMOVE:
info.isConditional = true;
switch (opcode.flags & CONDTYPE_MASK)
{
case CONDTYPE_EQ:
info.conditionMet = (rt == 0);
break;
case CONDTYPE_NE:
info.conditionMet = (rt != 0);
break;
}
break;
}
}
return info;
}

View File

@ -39,40 +39,44 @@ namespace R5900
{
// Generates an entry for the given opcode name.
// Assumes the default function naming schemes for interpreter and recompiler functions.
# define MakeOpcode( name, cycles ) \
# define MakeOpcode( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::name, \
::R5900::Dynarec::OpcodeImpl::rec##name, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcodeM( name, cycles ) \
# define MakeOpcodeM( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::MMI::name, \
::R5900::Dynarec::OpcodeImpl::MMI::rec##name, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcode0( name, cycles ) \
# define MakeOpcode0( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::COP0::name, \
::R5900::Dynarec::OpcodeImpl::COP0::rec##name, \
::R5900::OpcodeDisasm::name \
}
# define MakeOpcode1( name, cycles ) \
# define MakeOpcode1( name, cycles, flags ) \
static const OPCODE name = { \
#name, \
cycles, \
flags, \
NULL, \
::R5900::Interpreter::OpcodeImpl::COP1::name, \
::R5900::Dynarec::OpcodeImpl::COP1::rec##name, \
@ -83,6 +87,7 @@ namespace R5900
static const OPCODE name = { \
#name, \
0, \
0, \
R5900::Opcodes::Class_##name, \
NULL, \
NULL, \
@ -113,10 +118,10 @@ namespace R5900
using namespace Cycles;
MakeOpcode( Unknown, Default );
MakeOpcode( MMI_Unknown, Default );
MakeOpcode( COP0_Unknown, Default );
MakeOpcode( COP1_Unknown, Default );
MakeOpcode( Unknown, Default, 0 );
MakeOpcode( MMI_Unknown, Default, 0 );
MakeOpcode( COP0_Unknown, Default, 0 );
MakeOpcode( COP1_Unknown, Default, 0 );
// Class Subset Opcodes
// (not really opcodes, but rather entire subsets of other opcode classes)
@ -135,250 +140,250 @@ namespace R5900
// Misc Junk
MakeOpcode( COP2, Default );
MakeOpcode( COP2, Default, 0 );
MakeOpcode( CACHE, Default );
MakeOpcode( PREF, Default );
MakeOpcode( SYSCALL, Default );
MakeOpcode( BREAK, Default );
MakeOpcode( SYNC, Default );
MakeOpcode( CACHE, Default, 0 );
MakeOpcode( PREF, Default, 0 );
MakeOpcode( SYSCALL, Default, IS_BRANCH|BRANCHTYPE_SYSCALL );
MakeOpcode( BREAK, Default, 0 );
MakeOpcode( SYNC, Default, 0 );
// Branch/Jump Opcodes
MakeOpcode( J , Default );
MakeOpcode( JAL, Default );
MakeOpcode( JR, Default );
MakeOpcode( JALR, Default );
MakeOpcode( J , Default, IS_BRANCH|BRANCHTYPE_JUMP );
MakeOpcode( JAL, Default, IS_BRANCH|BRANCHTYPE_JUMP|IS_LINKED );
MakeOpcode( JR, Default, IS_BRANCH|BRANCHTYPE_REGISTER );
MakeOpcode( JALR, Default, IS_BRANCH|BRANCHTYPE_REGISTER|IS_LINKED );
MakeOpcode( BEQ, Branch );
MakeOpcode( BNE, Branch );
MakeOpcode( BLEZ, Branch );
MakeOpcode( BGTZ, Branch );
MakeOpcode( BEQL, Branch );
MakeOpcode( BNEL, Branch );
MakeOpcode( BLEZL, Branch );
MakeOpcode( BGTZL, Branch );
MakeOpcode( BLTZ, Branch );
MakeOpcode( BGEZ, Branch );
MakeOpcode( BLTZL, Branch );
MakeOpcode( BGEZL, Branch );
MakeOpcode( BLTZAL, Branch );
MakeOpcode( BGEZAL, Branch );
MakeOpcode( BLTZALL, Branch );
MakeOpcode( BGEZALL, Branch );
MakeOpcode( BEQ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_EQ );
MakeOpcode( BNE, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_NE );
MakeOpcode( BLEZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LEZ );
MakeOpcode( BGTZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GTZ );
MakeOpcode( BEQL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_EQ|IS_LIKELY );
MakeOpcode( BNEL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_NE|IS_LIKELY );
MakeOpcode( BLEZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LEZ|IS_LIKELY );
MakeOpcode( BGTZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GTZ|IS_LIKELY );
MakeOpcode( BLTZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ );
MakeOpcode( BGEZ, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ );
MakeOpcode( BLTZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ|IS_LIKELY );
MakeOpcode( BGEZL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ|IS_LIKELY );
MakeOpcode( BLTZAL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ|IS_LINKED );
MakeOpcode( BGEZAL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ|IS_LINKED );
MakeOpcode( BLTZALL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_LTZ|IS_LINKED|IS_LIKELY );
MakeOpcode( BGEZALL, Branch, IS_BRANCH|BRANCHTYPE_BRANCH|CONDTYPE_GEZ|IS_LINKED|IS_LIKELY );
MakeOpcode( TGEI, Branch );
MakeOpcode( TGEIU, Branch );
MakeOpcode( TLTI, Branch );
MakeOpcode( TLTIU, Branch );
MakeOpcode( TEQI, Branch );
MakeOpcode( TNEI, Branch );
MakeOpcode( TGE, Branch );
MakeOpcode( TGEU, Branch );
MakeOpcode( TLT, Branch );
MakeOpcode( TLTU, Branch );
MakeOpcode( TEQ, Branch );
MakeOpcode( TNE, Branch );
MakeOpcode( TGEI, Branch, 0 );
MakeOpcode( TGEIU, Branch, 0 );
MakeOpcode( TLTI, Branch, 0 );
MakeOpcode( TLTIU, Branch, 0 );
MakeOpcode( TEQI, Branch, 0 );
MakeOpcode( TNEI, Branch, 0 );
MakeOpcode( TGE, Branch, 0 );
MakeOpcode( TGEU, Branch, 0 );
MakeOpcode( TLT, Branch, 0 );
MakeOpcode( TLTU, Branch, 0 );
MakeOpcode( TEQ, Branch, 0 );
MakeOpcode( TNE, Branch, 0 );
// Arithmetic
MakeOpcode( MULT, Mult );
MakeOpcode( MULTU, Mult );
MakeOpcode( MULT1, Mult );
MakeOpcode( MULTU1, Mult );
MakeOpcode( MADD, Mult );
MakeOpcode( MADDU, Mult );
MakeOpcode( MADD1, Mult );
MakeOpcode( MADDU1, Mult );
MakeOpcode( DIV, Div );
MakeOpcode( DIVU, Div );
MakeOpcode( DIV1, Div );
MakeOpcode( DIVU1, Div );
MakeOpcode( MULT, Mult, 0 );
MakeOpcode( MULTU, Mult, 0 );
MakeOpcode( MULT1, Mult, 0 );
MakeOpcode( MULTU1, Mult, 0 );
MakeOpcode( MADD, Mult, 0 );
MakeOpcode( MADDU, Mult, 0 );
MakeOpcode( MADD1, Mult, 0 );
MakeOpcode( MADDU1, Mult, 0 );
MakeOpcode( DIV, Div, 0 );
MakeOpcode( DIVU, Div, 0 );
MakeOpcode( DIV1, Div, 0 );
MakeOpcode( DIVU1, Div, 0 );
MakeOpcode( ADDI, Default );
MakeOpcode( ADDIU, Default );
MakeOpcode( DADDI, Default );
MakeOpcode( DADDIU, Default );
MakeOpcode( DADD, Default );
MakeOpcode( DADDU, Default );
MakeOpcode( DSUB, Default );
MakeOpcode( DSUBU, Default );
MakeOpcode( ADD, Default );
MakeOpcode( ADDU, Default );
MakeOpcode( SUB, Default );
MakeOpcode( SUBU, Default );
MakeOpcode( ADDI, Default, IS_ALU|ALUTYPE_ADDI );
MakeOpcode( ADDIU, Default, IS_ALU|ALUTYPE_ADDI );
MakeOpcode( DADDI, Default, IS_ALU|ALUTYPE_ADDI|IS_64BIT );
MakeOpcode( DADDIU, Default, IS_ALU|ALUTYPE_ADDI|IS_64BIT );
MakeOpcode( DADD, Default, IS_ALU|ALUTYPE_ADD|IS_64BIT );
MakeOpcode( DADDU, Default, IS_ALU|ALUTYPE_ADD|IS_64BIT );
MakeOpcode( DSUB, Default, IS_ALU|ALUTYPE_SUB|IS_64BIT );
MakeOpcode( DSUBU, Default, IS_ALU|ALUTYPE_SUB|IS_64BIT );
MakeOpcode( ADD, Default, IS_ALU|ALUTYPE_ADD );
MakeOpcode( ADDU, Default, IS_ALU|ALUTYPE_ADD );
MakeOpcode( SUB, Default, IS_ALU|ALUTYPE_SUB );
MakeOpcode( SUBU, Default, IS_ALU|ALUTYPE_SUB );
MakeOpcode( ANDI, Default );
MakeOpcode( ORI, Default );
MakeOpcode( XORI, Default );
MakeOpcode( AND, Default );
MakeOpcode( OR, Default );
MakeOpcode( XOR, Default );
MakeOpcode( NOR, Default );
MakeOpcode( SLTI, Default );
MakeOpcode( SLTIU, Default );
MakeOpcode( SLT, Default );
MakeOpcode( SLTU, Default );
MakeOpcode( LUI, Default );
MakeOpcode( SLL, Default );
MakeOpcode( SRL, Default );
MakeOpcode( SRA, Default );
MakeOpcode( SLLV, Default );
MakeOpcode( SRLV, Default );
MakeOpcode( SRAV, Default );
MakeOpcode( MOVZ, Default );
MakeOpcode( MOVN, Default );
MakeOpcode( DSLLV, Default );
MakeOpcode( DSRLV, Default );
MakeOpcode( DSRAV, Default );
MakeOpcode( DSLL, Default );
MakeOpcode( DSRL, Default );
MakeOpcode( DSRA, Default );
MakeOpcode( DSLL32, Default );
MakeOpcode( DSRL32, Default );
MakeOpcode( DSRA32, Default );
MakeOpcode( ANDI, Default, 0 );
MakeOpcode( ORI, Default, 0 );
MakeOpcode( XORI, Default, 0 );
MakeOpcode( AND, Default, 0 );
MakeOpcode( OR, Default, 0 );
MakeOpcode( XOR, Default, 0 );
MakeOpcode( NOR, Default, 0 );
MakeOpcode( SLTI, Default, 0 );
MakeOpcode( SLTIU, Default, 0 );
MakeOpcode( SLT, Default, 0 );
MakeOpcode( SLTU, Default, 0 );
MakeOpcode( LUI, Default, 0 );
MakeOpcode( SLL, Default, 0 );
MakeOpcode( SRL, Default, 0 );
MakeOpcode( SRA, Default, 0 );
MakeOpcode( SLLV, Default, 0 );
MakeOpcode( SRLV, Default, 0 );
MakeOpcode( SRAV, Default, 0 );
MakeOpcode( MOVZ, Default, IS_ALU|ALUTYPE_CONDMOVE|CONDTYPE_EQ );
MakeOpcode( MOVN, Default, IS_ALU|ALUTYPE_CONDMOVE|CONDTYPE_NE );
MakeOpcode( DSLLV, Default, 0 );
MakeOpcode( DSRLV, Default, 0 );
MakeOpcode( DSRAV, Default, 0 );
MakeOpcode( DSLL, Default, 0 );
MakeOpcode( DSRL, Default, 0 );
MakeOpcode( DSRA, Default, 0 );
MakeOpcode( DSLL32, Default, 0 );
MakeOpcode( DSRL32, Default, 0 );
MakeOpcode( DSRA32, Default, 0 );
MakeOpcode( MFHI, Default );
MakeOpcode( MTHI, Default );
MakeOpcode( MFLO, Default );
MakeOpcode( MTLO, Default );
MakeOpcode( MFSA, Default );
MakeOpcode( MTSA, Default );
MakeOpcode( MTSAB, Default );
MakeOpcode( MTSAH, Default );
MakeOpcode( MFHI1, Default );
MakeOpcode( MTHI1, Default );
MakeOpcode( MFLO1, Default );
MakeOpcode( MTLO1, Default );
MakeOpcode( MFHI, Default, 0 );
MakeOpcode( MTHI, Default, 0 );
MakeOpcode( MFLO, Default, 0 );
MakeOpcode( MTLO, Default, 0 );
MakeOpcode( MFSA, Default, 0 );
MakeOpcode( MTSA, Default, 0 );
MakeOpcode( MTSAB, Default, 0 );
MakeOpcode( MTSAH, Default, 0 );
MakeOpcode( MFHI1, Default, 0 );
MakeOpcode( MTHI1, Default, 0 );
MakeOpcode( MFLO1, Default, 0 );
MakeOpcode( MTLO1, Default, 0 );
// Loads!
MakeOpcode( LDL, Load );
MakeOpcode( LDR, Load );
MakeOpcode( LQ, Load );
MakeOpcode( LB, Load );
MakeOpcode( LH, Load );
MakeOpcode( LWL, Load );
MakeOpcode( LW, Load );
MakeOpcode( LBU, Load );
MakeOpcode( LHU, Load );
MakeOpcode( LWR, Load );
MakeOpcode( LWU, Load );
MakeOpcode( LWC1, Load );
MakeOpcode( LQC2, Load );
MakeOpcode( LD, Load );
MakeOpcode( LDL, Load, IS_MEMORY|IS_LOAD|MEMTYPE_DWORD|IS_LEFT );
MakeOpcode( LDR, Load, IS_MEMORY|IS_LOAD|MEMTYPE_DWORD|IS_RIGHT );
MakeOpcode( LQ, Load, IS_MEMORY|IS_LOAD|MEMTYPE_QWORD );
MakeOpcode( LB, Load, IS_MEMORY|IS_LOAD|MEMTYPE_BYTE );
MakeOpcode( LH, Load, IS_MEMORY|IS_LOAD|MEMTYPE_HALF );
MakeOpcode( LWL, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD|IS_LEFT );
MakeOpcode( LW, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD );
MakeOpcode( LBU, Load, IS_MEMORY|IS_LOAD|MEMTYPE_BYTE );
MakeOpcode( LHU, Load, IS_MEMORY|IS_LOAD|MEMTYPE_HALF );
MakeOpcode( LWR, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD|IS_RIGHT );
MakeOpcode( LWU, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD );
MakeOpcode( LWC1, Load, IS_MEMORY|IS_LOAD|MEMTYPE_WORD );
MakeOpcode( LQC2, Load, IS_MEMORY|IS_LOAD|MEMTYPE_QWORD );
MakeOpcode( LD, Load, IS_MEMORY|IS_LOAD|MEMTYPE_DWORD );
// Stores!
MakeOpcode( SQ, Store );
MakeOpcode( SB, Store );
MakeOpcode( SH, Store );
MakeOpcode( SWL, Store );
MakeOpcode( SW, Store );
MakeOpcode( SDL, Store );
MakeOpcode( SDR, Store );
MakeOpcode( SWR, Store );
MakeOpcode( SWC1, Store );
MakeOpcode( SQC2, Store );
MakeOpcode( SD, Store );
MakeOpcode( SQ, Store, IS_MEMORY|IS_STORE|MEMTYPE_QWORD );
MakeOpcode( SB, Store, IS_MEMORY|IS_STORE|MEMTYPE_BYTE );
MakeOpcode( SH, Store, IS_MEMORY|IS_STORE|MEMTYPE_HALF );
MakeOpcode( SWL, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD|IS_LEFT );
MakeOpcode( SW, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD );
MakeOpcode( SDL, Store, IS_MEMORY|IS_STORE|MEMTYPE_DWORD|IS_LEFT );
MakeOpcode( SDR, Store, IS_MEMORY|IS_STORE|MEMTYPE_DWORD|IS_RIGHT );
MakeOpcode( SWR, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD|IS_RIGHT );
MakeOpcode( SWC1, Store, IS_MEMORY|IS_STORE|MEMTYPE_WORD );
MakeOpcode( SQC2, Store, IS_MEMORY|IS_STORE|MEMTYPE_QWORD );
MakeOpcode( SD, Store, IS_MEMORY|IS_STORE|MEMTYPE_DWORD );
// Multimedia Instructions!
MakeOpcodeM( PLZCW, MMI_Default );
MakeOpcodeM( PMFHL, MMI_Default );
MakeOpcodeM( PMTHL, MMI_Default );
MakeOpcodeM( PSLLH, MMI_Default );
MakeOpcodeM( PSRLH, MMI_Default );
MakeOpcodeM( PSRAH, MMI_Default );
MakeOpcodeM( PSLLW, MMI_Default );
MakeOpcodeM( PSRLW, MMI_Default );
MakeOpcodeM( PSRAW, MMI_Default );
MakeOpcodeM( PLZCW, MMI_Default, 0 );
MakeOpcodeM( PMFHL, MMI_Default, 0 );
MakeOpcodeM( PMTHL, MMI_Default, 0 );
MakeOpcodeM( PSLLH, MMI_Default, 0 );
MakeOpcodeM( PSRLH, MMI_Default, 0 );
MakeOpcodeM( PSRAH, MMI_Default, 0 );
MakeOpcodeM( PSLLW, MMI_Default, 0 );
MakeOpcodeM( PSRLW, MMI_Default, 0 );
MakeOpcodeM( PSRAW, MMI_Default, 0 );
MakeOpcodeM( PADDW, MMI_Default );
MakeOpcodeM( PADDH, MMI_Default );
MakeOpcodeM( PADDB, MMI_Default );
MakeOpcodeM( PADDSW, MMI_Default );
MakeOpcodeM( PADDSH, MMI_Default );
MakeOpcodeM( PADDSB, MMI_Default );
MakeOpcodeM( PADDUW, MMI_Default );
MakeOpcodeM( PADDUH, MMI_Default );
MakeOpcodeM( PADDUB, MMI_Default );
MakeOpcodeM( PSUBW, MMI_Default );
MakeOpcodeM( PSUBH, MMI_Default );
MakeOpcodeM( PSUBB, MMI_Default );
MakeOpcodeM( PSUBSW, MMI_Default );
MakeOpcodeM( PSUBSH, MMI_Default );
MakeOpcodeM( PSUBSB, MMI_Default );
MakeOpcodeM( PSUBUW, MMI_Default );
MakeOpcodeM( PSUBUH, MMI_Default );
MakeOpcodeM( PSUBUB, MMI_Default );
MakeOpcodeM( PADDW, MMI_Default, 0 );
MakeOpcodeM( PADDH, MMI_Default, 0 );
MakeOpcodeM( PADDB, MMI_Default, 0 );
MakeOpcodeM( PADDSW, MMI_Default, 0 );
MakeOpcodeM( PADDSH, MMI_Default, 0 );
MakeOpcodeM( PADDSB, MMI_Default, 0 );
MakeOpcodeM( PADDUW, MMI_Default, 0 );
MakeOpcodeM( PADDUH, MMI_Default, 0 );
MakeOpcodeM( PADDUB, MMI_Default, 0 );
MakeOpcodeM( PSUBW, MMI_Default, 0 );
MakeOpcodeM( PSUBH, MMI_Default, 0 );
MakeOpcodeM( PSUBB, MMI_Default, 0 );
MakeOpcodeM( PSUBSW, MMI_Default, 0 );
MakeOpcodeM( PSUBSH, MMI_Default, 0 );
MakeOpcodeM( PSUBSB, MMI_Default, 0 );
MakeOpcodeM( PSUBUW, MMI_Default, 0 );
MakeOpcodeM( PSUBUH, MMI_Default, 0 );
MakeOpcodeM( PSUBUB, MMI_Default, 0 );
MakeOpcodeM( PCGTW, MMI_Default );
MakeOpcodeM( PMAXW, MMI_Default );
MakeOpcodeM( PMAXH, MMI_Default );
MakeOpcodeM( PCGTH, MMI_Default );
MakeOpcodeM( PCGTB, MMI_Default );
MakeOpcodeM( PEXTLW, MMI_Default );
MakeOpcodeM( PEXTLH, MMI_Default );
MakeOpcodeM( PEXTLB, MMI_Default );
MakeOpcodeM( PEXT5, MMI_Default );
MakeOpcodeM( PPACW, MMI_Default );
MakeOpcodeM( PPACH, MMI_Default );
MakeOpcodeM( PPACB, MMI_Default );
MakeOpcodeM( PPAC5, MMI_Default );
MakeOpcodeM( PCGTW, MMI_Default, 0 );
MakeOpcodeM( PMAXW, MMI_Default, 0 );
MakeOpcodeM( PMAXH, MMI_Default, 0 );
MakeOpcodeM( PCGTH, MMI_Default, 0 );
MakeOpcodeM( PCGTB, MMI_Default, 0 );
MakeOpcodeM( PEXTLW, MMI_Default, 0 );
MakeOpcodeM( PEXTLH, MMI_Default, 0 );
MakeOpcodeM( PEXTLB, MMI_Default, 0 );
MakeOpcodeM( PEXT5, MMI_Default, 0 );
MakeOpcodeM( PPACW, MMI_Default, 0 );
MakeOpcodeM( PPACH, MMI_Default, 0 );
MakeOpcodeM( PPACB, MMI_Default, 0 );
MakeOpcodeM( PPAC5, MMI_Default, 0 );
MakeOpcodeM( PABSW, MMI_Default );
MakeOpcodeM( PABSH, MMI_Default );
MakeOpcodeM( PCEQW, MMI_Default );
MakeOpcodeM( PMINW, MMI_Default );
MakeOpcodeM( PMINH, MMI_Default );
MakeOpcodeM( PADSBH, MMI_Default );
MakeOpcodeM( PCEQH, MMI_Default );
MakeOpcodeM( PCEQB, MMI_Default );
MakeOpcodeM( PEXTUW, MMI_Default );
MakeOpcodeM( PEXTUH, MMI_Default );
MakeOpcodeM( PEXTUB, MMI_Default );
MakeOpcodeM( PSLLVW, MMI_Default );
MakeOpcodeM( PSRLVW, MMI_Default );
MakeOpcodeM( PABSW, MMI_Default, 0 );
MakeOpcodeM( PABSH, MMI_Default, 0 );
MakeOpcodeM( PCEQW, MMI_Default, 0 );
MakeOpcodeM( PMINW, MMI_Default, 0 );
MakeOpcodeM( PMINH, MMI_Default, 0 );
MakeOpcodeM( PADSBH, MMI_Default, 0 );
MakeOpcodeM( PCEQH, MMI_Default, 0 );
MakeOpcodeM( PCEQB, MMI_Default, 0 );
MakeOpcodeM( PEXTUW, MMI_Default, 0 );
MakeOpcodeM( PEXTUH, MMI_Default, 0 );
MakeOpcodeM( PEXTUB, MMI_Default, 0 );
MakeOpcodeM( PSLLVW, MMI_Default, 0 );
MakeOpcodeM( PSRLVW, MMI_Default, 0 );
MakeOpcodeM( QFSRV, MMI_Default );
MakeOpcodeM( QFSRV, MMI_Default, 0 );
MakeOpcodeM( PMADDH, MMI_Mult );
MakeOpcodeM( PHMADH, MMI_Mult );
MakeOpcodeM( PMSUBH, MMI_Mult );
MakeOpcodeM( PHMSBH, MMI_Mult );
MakeOpcodeM( PMULTH, MMI_Mult );
MakeOpcodeM( PMADDW, MMI_Mult );
MakeOpcodeM( PMSUBW, MMI_Mult );
MakeOpcodeM( PMFHI, MMI_Mult );
MakeOpcodeM( PMFLO, MMI_Mult );
MakeOpcodeM( PMULTW, MMI_Mult );
MakeOpcodeM( PMADDUW, MMI_Mult );
MakeOpcodeM( PMULTUW, MMI_Mult );
MakeOpcodeM( PDIVUW, MMI_Div );
MakeOpcodeM( PDIVW, MMI_Div );
MakeOpcodeM( PDIVBW, MMI_Div );
MakeOpcodeM( PMADDH, MMI_Mult, 0 );
MakeOpcodeM( PHMADH, MMI_Mult, 0 );
MakeOpcodeM( PMSUBH, MMI_Mult, 0 );
MakeOpcodeM( PHMSBH, MMI_Mult, 0 );
MakeOpcodeM( PMULTH, MMI_Mult, 0 );
MakeOpcodeM( PMADDW, MMI_Mult, 0 );
MakeOpcodeM( PMSUBW, MMI_Mult, 0 );
MakeOpcodeM( PMFHI, MMI_Mult, 0 );
MakeOpcodeM( PMFLO, MMI_Mult, 0 );
MakeOpcodeM( PMULTW, MMI_Mult, 0 );
MakeOpcodeM( PMADDUW, MMI_Mult, 0 );
MakeOpcodeM( PMULTUW, MMI_Mult, 0 );
MakeOpcodeM( PDIVUW, MMI_Div, 0 );
MakeOpcodeM( PDIVW, MMI_Div, 0 );
MakeOpcodeM( PDIVBW, MMI_Div, 0 );
MakeOpcodeM( PINTH, MMI_Default );
MakeOpcodeM( PCPYLD, MMI_Default );
MakeOpcodeM( PAND, MMI_Default );
MakeOpcodeM( PXOR, MMI_Default );
MakeOpcodeM( PEXEH, MMI_Default );
MakeOpcodeM( PREVH, MMI_Default );
MakeOpcodeM( PEXEW, MMI_Default );
MakeOpcodeM( PROT3W, MMI_Default );
MakeOpcodeM( PINTH, MMI_Default, 0 );
MakeOpcodeM( PCPYLD, MMI_Default, 0 );
MakeOpcodeM( PAND, MMI_Default, 0 );
MakeOpcodeM( PXOR, MMI_Default, 0 );
MakeOpcodeM( PEXEH, MMI_Default, 0 );
MakeOpcodeM( PREVH, MMI_Default, 0 );
MakeOpcodeM( PEXEW, MMI_Default, 0 );
MakeOpcodeM( PROT3W, MMI_Default, 0 );
MakeOpcodeM( PSRAVW, MMI_Default );
MakeOpcodeM( PMTHI, MMI_Default );
MakeOpcodeM( PMTLO, MMI_Default );
MakeOpcodeM( PINTEH, MMI_Default );
MakeOpcodeM( PCPYUD, MMI_Default );
MakeOpcodeM( POR, MMI_Default );
MakeOpcodeM( PNOR, MMI_Default );
MakeOpcodeM( PEXCH, MMI_Default );
MakeOpcodeM( PCPYH, MMI_Default );
MakeOpcodeM( PEXCW, MMI_Default );
MakeOpcodeM( PSRAVW, MMI_Default, 0 );
MakeOpcodeM( PMTHI, MMI_Default, 0 );
MakeOpcodeM( PMTLO, MMI_Default, 0 );
MakeOpcodeM( PINTEH, MMI_Default, 0 );
MakeOpcodeM( PCPYUD, MMI_Default, 0 );
MakeOpcodeM( POR, MMI_Default, 0 );
MakeOpcodeM( PNOR, MMI_Default, 0 );
MakeOpcodeM( PEXCH, MMI_Default, 0 );
MakeOpcodeM( PCPYH, MMI_Default, 0 );
MakeOpcodeM( PEXCW, MMI_Default, 0 );
//////////////////////////////////////////////////////////
// COP0 Instructions
@ -386,21 +391,21 @@ namespace R5900
MakeOpcodeClass( COP0_C0 );
MakeOpcodeClass( COP0_BC0 );
MakeOpcode0( MFC0, CopDefault );
MakeOpcode0( MTC0, CopDefault );
MakeOpcode0( MFC0, CopDefault, 0 );
MakeOpcode0( MTC0, CopDefault, 0 );
MakeOpcode0( BC0F, Branch );
MakeOpcode0( BC0T, Branch );
MakeOpcode0( BC0FL, Branch );
MakeOpcode0( BC0TL, Branch );
MakeOpcode0( BC0F, Branch, 0 );
MakeOpcode0( BC0T, Branch, 0 );
MakeOpcode0( BC0FL, Branch, 0 );
MakeOpcode0( BC0TL, Branch, 0 );
MakeOpcode0( TLBR, CopDefault );
MakeOpcode0( TLBWI, CopDefault );
MakeOpcode0( TLBWR, CopDefault );
MakeOpcode0( TLBP, CopDefault );
MakeOpcode0( ERET, CopDefault );
MakeOpcode0( EI, CopDefault );
MakeOpcode0( DI, CopDefault );
MakeOpcode0( TLBR, CopDefault, 0 );
MakeOpcode0( TLBWI, CopDefault, 0 );
MakeOpcode0( TLBWR, CopDefault, 0 );
MakeOpcode0( TLBP, CopDefault, 0 );
MakeOpcode0( ERET, CopDefault, IS_BRANCH|BRANCHTYPE_ERET );
MakeOpcode0( EI, CopDefault, 0 );
MakeOpcode0( DI, CopDefault, 0 );
//////////////////////////////////////////////////////////
// COP1 Instructions!
@ -409,44 +414,44 @@ namespace R5900
MakeOpcodeClass( COP1_S );
MakeOpcodeClass( COP1_W ); // contains CVT_S instruction *only*
MakeOpcode1( MFC1, CopDefault );
MakeOpcode1( CFC1, CopDefault );
MakeOpcode1( MTC1, CopDefault );
MakeOpcode1( CTC1, CopDefault );
MakeOpcode1( MFC1, CopDefault, 0 );
MakeOpcode1( CFC1, CopDefault, 0 );
MakeOpcode1( MTC1, CopDefault, 0 );
MakeOpcode1( CTC1, CopDefault, 0 );
MakeOpcode1( BC1F, Branch );
MakeOpcode1( BC1T, Branch );
MakeOpcode1( BC1FL, Branch );
MakeOpcode1( BC1TL, Branch );
MakeOpcode1( BC1F, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_EQ );
MakeOpcode1( BC1T, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_NE );
MakeOpcode1( BC1FL, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_EQ|IS_LIKELY );
MakeOpcode1( BC1TL, Branch, IS_BRANCH|BRANCHTYPE_BC1|CONDTYPE_NE|IS_LIKELY );
MakeOpcode1( ADD_S, CopDefault );
MakeOpcode1( ADDA_S, CopDefault );
MakeOpcode1( SUB_S, CopDefault );
MakeOpcode1( SUBA_S, CopDefault );
MakeOpcode1( ADD_S, CopDefault, 0 );
MakeOpcode1( ADDA_S, CopDefault, 0 );
MakeOpcode1( SUB_S, CopDefault, 0 );
MakeOpcode1( SUBA_S, CopDefault, 0 );
MakeOpcode1( ABS_S, CopDefault );
MakeOpcode1( MOV_S, CopDefault );
MakeOpcode1( NEG_S, CopDefault );
MakeOpcode1( MAX_S, CopDefault );
MakeOpcode1( MIN_S, CopDefault );
MakeOpcode1( ABS_S, CopDefault, 0 );
MakeOpcode1( MOV_S, CopDefault, 0 );
MakeOpcode1( NEG_S, CopDefault, 0 );
MakeOpcode1( MAX_S, CopDefault, 0 );
MakeOpcode1( MIN_S, CopDefault, 0 );
MakeOpcode1( MUL_S, FPU_Mult );
MakeOpcode1( DIV_S, 6*8 );
MakeOpcode1( SQRT_S, 6*8 );
MakeOpcode1( RSQRT_S, 8*8 );
MakeOpcode1( MULA_S, FPU_Mult );
MakeOpcode1( MADD_S, FPU_Mult );
MakeOpcode1( MSUB_S, FPU_Mult );
MakeOpcode1( MADDA_S, FPU_Mult );
MakeOpcode1( MSUBA_S, FPU_Mult );
MakeOpcode1( MUL_S, FPU_Mult, 0 );
MakeOpcode1( DIV_S, 6*8, 0 );
MakeOpcode1( SQRT_S, 6*8, 0 );
MakeOpcode1( RSQRT_S, 8*8, 0 );
MakeOpcode1( MULA_S, FPU_Mult, 0 );
MakeOpcode1( MADD_S, FPU_Mult, 0 );
MakeOpcode1( MSUB_S, FPU_Mult, 0 );
MakeOpcode1( MADDA_S, FPU_Mult, 0 );
MakeOpcode1( MSUBA_S, FPU_Mult, 0 );
MakeOpcode1( C_F, CopDefault );
MakeOpcode1( C_EQ, CopDefault );
MakeOpcode1( C_LT, CopDefault );
MakeOpcode1( C_LE, CopDefault );
MakeOpcode1( C_F, CopDefault, 0 );
MakeOpcode1( C_EQ, CopDefault, 0 );
MakeOpcode1( C_LT, CopDefault, 0 );
MakeOpcode1( C_LE, CopDefault, 0 );
MakeOpcode1( CVT_S, CopDefault );
MakeOpcode1( CVT_W, CopDefault );
MakeOpcode1( CVT_S, CopDefault, 0 );
MakeOpcode1( CVT_W, CopDefault, 0 );
}
namespace OpcodeTables

View File

@ -28,6 +28,49 @@ void COP2_SPECIAL();
void COP2_SPECIAL2();
void COP2_Unknown();
// reserve the lower 8 bits for opcode specific types
// which of these are actually used depends on the opcode
// flags further below
#define MEMTYPE_MASK (0x07 << 0)
#define MEMTYPE_BYTE (0x01 << 0)
#define MEMTYPE_HALF (0x02 << 0)
#define MEMTYPE_WORD (0x03 << 0)
#define MEMTYPE_DWORD (0x04 << 0)
#define MEMTYPE_QWORD (0x05 << 0)
#define CONDTYPE_MASK (0x07 << 0)
#define CONDTYPE_EQ (0x01 << 0)
#define CONDTYPE_NE (0x02 << 0)
#define CONDTYPE_LEZ (0x03 << 0)
#define CONDTYPE_GTZ (0x04 << 0)
#define CONDTYPE_LTZ (0x05 << 0)
#define CONDTYPE_GEZ (0x06 << 0)
#define BRANCHTYPE_MASK (0x07 << 3)
#define BRANCHTYPE_JUMP (0x01 << 3)
#define BRANCHTYPE_BRANCH (0x02 << 3)
#define BRANCHTYPE_SYSCALL (0x03 << 3)
#define BRANCHTYPE_ERET (0x04 << 3)
#define BRANCHTYPE_REGISTER (0x05 << 3)
#define BRANCHTYPE_BC1 (0x06 << 3)
#define ALUTYPE_MASK (0x07 << 3)
#define ALUTYPE_ADD (0x01 << 3)
#define ALUTYPE_ADDI (0x02 << 3)
#define ALUTYPE_SUB (0x03 << 3)
#define ALUTYPE_CONDMOVE (0x04 << 3)
#define IS_LOAD 0x00000100
#define IS_STORE 0x00000200
#define IS_BRANCH 0x00000400
#define IS_LINKED 0x00001000
#define IS_LIKELY 0x00002000
#define IS_MEMORY 0x00004000
#define IS_CONDMOVE 0x00010000
#define IS_ALU 0x00020000
#define IS_64BIT 0x00040000
#define IS_LEFT 0x00080000
#define IS_RIGHT 0x00100000
namespace R5900
{
@ -79,6 +122,9 @@ namespace R5900
// Number of cycles this instruction normally uses.
u8 cycles;
// Information about the opcode
u32 flags;
const OPCODE& (*getsubclass)(u32 op);
// Process the instruction using the interpreter.

View File

@ -1359,45 +1359,9 @@ void recMemcheck(u32 op, u32 bits, bool store)
inline bool isBranchOrJump(u32 addr)
{
u32 op = memRead32(addr);
const OPCODE& opcode = GetInstruction(op);
switch (op >> 26)
{
case 0x02: // j
case 0x03: // jal
case 0x04: // beq
case 0x05: // bne
case 0x06: // blez
case 0x07: // bgtz
case 0x14: // beql
case 0x15: // bnel
case 0x16: // blezl
case 0x17: // bgtzl
return true;
case 0x00: // special
switch (op & 0x3F)
{
case 0x08: // jr
case 0x09: // jalr
return true;
}
break;
case 0x01: // regimm
switch ((op >> 16) & 0x1F)
{
case 0x00: // bltz
case 0x01: // bgez
case 0x02: // bltzl
case 0x03: // bgezl
case 0x10: // bltzal
case 0x11: // bgezal
case 0x12: // bltzall
case 0x13: // bgezall
return true;
}
break;
}
return false;
return (opcode.flags & IS_BRANCH) != 0;
}
// The next two functions return 0 if no breakpoint is needed,
@ -1419,39 +1383,18 @@ int isMemcheckNeeded(u32 pc)
{
if (CBreakPoints::GetMemChecks().size() == 0)
return 0;
u32 addr = pc;
if (isBranchOrJump(addr))
addr += 4;
u32 op = memRead32(addr);
const OPCODE& opcode = GetInstruction(op);
switch (op >> 26)
{
case 0x20: // lb
case 0x21: // lh
case 0x22: // lwl
case 0x23: // lw
case 0x24: // lbu
case 0x25: // lhu
case 0x26: // lwr
case 0x28: // sb
case 0x29: // sh
case 0x2A: // swl
case 0x2B: // sw
case 0x2E: // swr
case 0x37: // ld
case 0x1B: // ldr
case 0x3F: // sd
case 0x3D: // sdr
case 0x1A: // ldl
case 0x2C: // sdl
case 0x1E: // lq
case 0x1F: // sq
if ((opcode.flags & IS_MEMORY) && (opcode.flags & MEMTYPE_MASK) != 0)
return addr == pc ? 1 : 2;
default:
return 0;
}
return 0;
}
void encodeBreakpoint()
@ -1470,50 +1413,27 @@ void encodeMemcheck()
return;
u32 op = memRead32(needed == 2 ? pc+4 : pc);
switch (cpuRegs.code >> 26)
const OPCODE& opcode = GetInstruction(op);
bool store = (opcode.flags & IS_STORE) != 0;
switch (opcode.flags & MEMTYPE_MASK)
{
case 0x20: // lb
case 0x24: // lbu
recMemcheck(op,8,false);
case MEMTYPE_BYTE:
recMemcheck(op,8,store);
break;
case 0x28: // sb
recMemcheck(op,8,true);
case MEMTYPE_HALF:
recMemcheck(op,16,store);
break;
case 0x21: // lh
case 0x25: // lhu
recMemcheck(op,16,false);
case MEMTYPE_WORD:
recMemcheck(op,32,store);
break;
case 0x22: // lwl
case 0x23: // lw
case 0x26: // lwr
recMemcheck(op,32,false);
case MEMTYPE_DWORD:
recMemcheck(op,64,store);
break;
case 0x29: // sh
recMemcheck(op,16,true);
break;
case 0x2A: // swl
case 0x2B: // sw
case 0x2E: // swr
recMemcheck(op,32,true);
break;
case 0x37: // ld
case 0x1B: // ldr
case 0x1A: // ldl
recMemcheck(op,64,false);
break;
case 0x3F: // sd
case 0x3D: // sdr
case 0x2C: // sdl
recMemcheck(op,64,true);
break;
case 0x1E: // lq
recMemcheck(op,128,false);
break;
case 0x1F: // sq
recMemcheck(op,128,true);
case MEMTYPE_QWORD:
recMemcheck(op,128,store);
break;
}
}
void recompileNextInstruction(int delayslot)