Snippets
Displaying:
CNoeR3000A.cpp |
View full page
#include "CNoeR3000A.h"
#define NOER3000A_DISASM_VALUES() 0 //useful for debugging - shows register values as ints when disassembling from a live context
struct SR3000ADefaultOpHandler
{
typedef void (*TDefaultOpHandlerFunction)(CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandler);
typedef void (*TDefaultOpStringFormatFunction)(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const uint32_t opAddr, const SR3000ADefaultOpHandler *pHandler);
explicit SR3000ADefaultOpHandler(const char *pOpName, TDefaultOpHandlerFunction pOpHandler, TDefaultOpStringFormatFunction pOpStringFormat)
: mpOpName(pOpName)
, mpOpHandler(pOpHandler)
, mpOpStringFormat(pOpStringFormat)
{
NoeAssert(strlen(pOpName) <= CNoeR3000A::skMaximumOpNameLength);
}
const char *mpOpName;
TDefaultOpHandlerFunction mpOpHandler;
TDefaultOpStringFormatFunction mpOpStringFormat;
};
namespace
{
const uint64_t skDefaultCyclesPerOp = 1;
const uint32_t skDefaultDelayBranchCycles = 0;
const uint32_t skDefaultDelayLoadCycles = 0;
const char *skGPRNameForIndex[CNoeR3000A::kGPR_Count] =
{
"r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" };
const char *skIRNameForIndex[CNoeR3000A::kIR_Count] =
{
"lo", "hi", "pc", "op", };
template<typename DataType>
DataType default_read_memory(CNoeR3000A *pCpu, const uint32_t addr, const CNoeR3000A::EAccessType accessType)
{
return 0;
}
template<typename DataType>
void default_write_memory(CNoeR3000A *pCpu, const uint32_t addr, const DataType memVal, const CNoeR3000A::EAccessType accessType)
{
}
void default_write_cop0_reg(CNoeR3000A *pCpu, const CNoeR3000A::EC0R cop0Reg, const uint32_t regVal)
{
pCpu->C0R()[cop0Reg] = regVal;
}
#if NOER3000A_DEBUGGER()
CNoeDebugger::EDebuggerReadWriteResult debugger_read_data(CNoeDebugger *pDebugger, void *pDest, const uint64_t readAddr, const uint32_t readSize)
{
CNoeR3000A *pCpu = static_cast<CNoeR3000A *>(pDebugger->GetUserData());
switch (readSize)
{
case 1:
*static_cast<uint8_t *>(pDest) = pCpu->ReadMemory8(static_cast<uint32_t>(readAddr), CNoeR3000A::kAT_External);
break;
case 2:
*static_cast<uint16_t *>(pDest) = pCpu->ReadMemory16(static_cast<uint32_t>(readAddr), CNoeR3000A::kAT_External);
break;
case 4:
*static_cast<uint32_t *>(pDest) = pCpu->ReadMemory32(static_cast<uint32_t>(readAddr), CNoeR3000A::kAT_External);
break;
default:
for (uint32_t readAmount = 0; readAmount < readSize; ++readAmount)
{
static_cast<uint8_t *>(pDest)[readAmount] = pCpu->ReadMemory8(static_cast<uint32_t>(readAddr + readAmount), CNoeR3000A::kAT_External);
}
break;
}
return CNoeDebugger::kDRWR_Success;
}
CNoeDebugger::EDebuggerReadWriteResult debugger_write_data(CNoeDebugger *pDebugger, const void *pSrc, const uint64_t writeAddr, const uint32_t writeSize)
{
CNoeR3000A *pCpu = static_cast<CNoeR3000A *>(pDebugger->GetUserData());
switch (writeSize)
{
case 1:
pCpu->WriteMemory8(static_cast<uint32_t>(writeAddr), *static_cast<const uint8_t *>(pSrc), CNoeR3000A::kAT_External);
break;
case 2:
pCpu->WriteMemory16(static_cast<uint32_t>(writeAddr), *static_cast<const uint16_t *>(pSrc), CNoeR3000A::kAT_External);
break;
case 4:
pCpu->WriteMemory32(static_cast<uint32_t>(writeAddr), *static_cast<const uint32_t *>(pSrc), CNoeR3000A::kAT_External);
break;
default:
for (uint32_t writeAmount = 0; writeAmount < writeSize; ++writeAmount)
{
pCpu->WriteMemory8(static_cast<uint32_t>(writeAddr + writeAmount), static_cast<const uint8_t *>(pSrc)[writeAmount], CNoeR3000A::kAT_External);
}
break;
}
return CNoeDebugger::kDRWR_Success;
}
uint32_t *debugger_reg_pointer(CNoeDebugger *pDebugger, const uint32_t regIndex)
{
CNoeR3000A *pCpu = static_cast<CNoeR3000A *>(pDebugger->GetUserData());
if (regIndex < CNoeR3000A::kGPR_Count)
{
return &pCpu->GPR()[regIndex];
}
else if (regIndex < (CNoeR3000A::kGPR_Count + CNoeR3000A::kIR_Count))
{
return &pCpu->IR()[regIndex - CNoeR3000A::kGPR_Count];
}
else if (regIndex < (CNoeR3000A::kGPR_Count + CNoeR3000A::kIR_Count + CNoeR3000A::kC0R_Count))
{
return &pCpu->C0R()[regIndex - (CNoeR3000A::kGPR_Count + CNoeR3000A::kIR_Count)];
}
return NULL;
}
CNoeDebugger::EDebuggerReadWriteResult debugger_read_reg(CNoeDebugger *pDebugger, void *pDest, const uint32_t regIndex)
{
if (uint32_t *pReg = debugger_reg_pointer(pDebugger, regIndex))
{
memcpy(pDest, pReg, sizeof(uint32_t));
return CNoeDebugger::kDRWR_Success;
}
return CNoeDebugger::kDRWR_Failure;
}
CNoeDebugger::EDebuggerReadWriteResult debugger_write_reg(CNoeDebugger *pDebugger, const void *pSrc, const uint32_t regIndex)
{
if (uint32_t *pReg = debugger_reg_pointer(pDebugger, regIndex))
{
memcpy(pReg, pSrc, sizeof(uint32_t));
return CNoeDebugger::kDRWR_Success;
}
return CNoeDebugger::kDRWR_Failure;
}
void debugger_disassemble(CNoeDebugger *pDebugger, CNoeMemWriteBuffer *pDisasmOut, const uint64_t addr, const uint64_t refAddr, const uint32_t instructionCount)
{
CNoeR3000A *pCpu = static_cast<CNoeR3000A *>(pDebugger->GetUserData());
char disasmString[CNoeR3000A::skMaximumOpStringLength];
for (uint32_t instructionIndex = 0; instructionIndex < instructionCount; ++instructionIndex)
{
const uint32_t opAddr = static_cast<uint32_t>(addr) + instructionIndex * CNoeR3000A::skInstructionSize;
const uint32_t opVal = pCpu->ReadInstruction(opAddr, CNoeR3000A::kAT_External);
pCpu->FormatOpString(disasmString, opVal, opAddr);
NoeAssert(CNoeR3000A::skInstructionSize == sizeof(opVal));
pDisasmOut->Write(NNoeDebugProtocol::SDisasmEntry(opAddr, CNoeR3000A::skInstructionSize));
pDisasmOut->Write(opVal);
pDisasmOut->WriteString("%s", disasmString);
}
}
#endif
#define OP_OB(opName) SR3000ADefaultOpHandler(#opName, CNoeR3000AOps::opName, CNoeR3000AOps::opName##_format)
#define OP_IMPLEMENT(opName) static void opName(CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
#define OP_IMPLEMENT_FMT(opName) static void opName##_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const uint32_t opAddr, const SR3000ADefaultOpHandler *pHandlerObject)
uint32_t ®_sa(CNoeR3000A *pCpu, const uint32_t opVal)
{
const uint32_t regIndex = CNoeR3000A::GetInstructionSA(opVal);
return pCpu->GPR()[regIndex];
}
uint32_t ®_rd(CNoeR3000A *pCpu, const uint32_t opVal)
{
const uint32_t regIndex = CNoeR3000A::GetInstructionRD(opVal);
return pCpu->GPR()[regIndex];
}
uint32_t ®_rt(CNoeR3000A *pCpu, const uint32_t opVal)
{
const uint32_t regIndex = CNoeR3000A::GetInstructionRT(opVal);
return pCpu->GPR()[regIndex];
}
uint32_t ®_rs(CNoeR3000A *pCpu, const uint32_t opVal)
{
const uint32_t regIndex = CNoeR3000A::GetInstructionRS(opVal);
return pCpu->GPR()[regIndex];
}
bool sa_is_r0(const uint32_t opVal)
{
return CNoeR3000A::GetInstructionSA(opVal) == CNoeR3000A::kGPR_Zero;
}
bool rd_is_r0(const uint32_t opVal)
{
return CNoeR3000A::GetInstructionRD(opVal) == CNoeR3000A::kGPR_Zero;
}
bool rt_is_r0(const uint32_t opVal)
{
return CNoeR3000A::GetInstructionRT(opVal) == CNoeR3000A::kGPR_Zero;
}
bool rs_is_r0(const uint32_t opVal)
{
return CNoeR3000A::GetInstructionRS(opVal) == CNoeR3000A::kGPR_Zero;
}
uint32_t op_imm_16(const uint32_t opVal)
{
return (opVal & 0xFFFF);
}
int16_t op_imm_s16(const uint32_t opVal)
{
return int16_t(opVal & 0xFFFF);
}
const int skCircularTempStringBufferSize = CNoeR3000A::skMaximumOpStringLength * 8;
char sCircularTempStringBuffer[skCircularTempStringBufferSize];
int sCircularTempStringBufferOffset = 0;
char *get_temp_string_buffer(const int bufferSize)
{
NoeAssert(bufferSize < skCircularTempStringBufferSize);
if ((sCircularTempStringBufferOffset + bufferSize) > skCircularTempStringBufferSize)
{ sCircularTempStringBufferOffset = 0;
}
char *pBuffer = &sCircularTempStringBuffer[sCircularTempStringBufferOffset];
sCircularTempStringBufferOffset += bufferSize;
return pBuffer;
}
const char *string_for_op(const SR3000ADefaultOpHandler *pHandlerObject)
{
const int opNameLength = strlen(pHandlerObject->mpOpName);
const int paddedNameLength = CNoeR3000A::skMaximumOpNameLength + 4;
char *pOpString = get_temp_string_buffer(paddedNameLength + 1);
memcpy(pOpString, pHandlerObject->mpOpName, opNameLength);
memset(pOpString + opNameLength, ' ', paddedNameLength - opNameLength);
pOpString[paddedNameLength] = 0;
return pOpString;
}
#if NOER3000A_DISASM_VALUES()
const char *reg_string_internal(CNoeR3000A *pCpu, const uint32_t regIndex)
{
char *pRegString = get_temp_string_buffer(32);
NoeSPrintF(pRegString, 32, "%s(%i)", CNoeR3000A::GetGPRName(CNoeR3000A::EGPR(regIndex)), pCpu->GPR()[regIndex]);
return pRegString;
}
const char *reg_string_sa_internal(CNoeR3000A *pCpu, const uint32_t opVal)
{
return reg_string_internal(pCpu, CNoeR3000A::GetInstructionSA(opVal));
}
const char *reg_string_rd_internal(CNoeR3000A *pCpu, const uint32_t opVal)
{
return reg_string_internal(pCpu, CNoeR3000A::GetInstructionRD(opVal));
}
const char *reg_string_rt_internal(CNoeR3000A *pCpu, const uint32_t opVal)
{
return reg_string_internal(pCpu, CNoeR3000A::GetInstructionRT(opVal));
}
const char *reg_string_rs_internal(CNoeR3000A *pCpu, const uint32_t opVal)
{
return reg_string_internal(pCpu, CNoeR3000A::GetInstructionRS(opVal));
}
#define reg_string_sa(opVal) reg_string_sa_internal(pCpu, opVal)
#define reg_string_rd(opVal) reg_string_rd_internal(pCpu, opVal)
#define reg_string_rt(opVal) reg_string_rt_internal(pCpu, opVal)
#define reg_string_rs(opVal) reg_string_rs_internal(pCpu, opVal)
#else
const char *reg_string_sa(const uint32_t opVal)
{
return CNoeR3000A::GetGPRName(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionSA(opVal)));
}
const char *reg_string_rd(const uint32_t opVal)
{
return CNoeR3000A::GetGPRName(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRD(opVal)));
}
const char *reg_string_rt(const uint32_t opVal)
{
return CNoeR3000A::GetGPRName(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)));
}
const char *reg_string_rs(const uint32_t opVal)
{
return CNoeR3000A::GetGPRName(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRS(opVal)));
}
#endif
const char *cop0_reg_string(const uint32_t regIndex)
{
NoeAssert(regIndex < CNoeR3000A::kC0R_Count);
char *pRegString = get_temp_string_buffer(4);
NoeSPrintF(pRegString, 4, "c%i", regIndex);
return pRegString;
}
void jump_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const uint32_t opAddr, const SR3000ADefaultOpHandler *pHandlerObject)
{
const uint32_t jumpAddr = CNoeR3000A::GetInstructionJumpAddress(opVal) +
(opAddr & CNoeR3000A::skInstructionJumpAddressPCMask);
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s$%0x",
string_for_op(pHandlerObject), jumpAddr);
}
void conditional_branch_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const uint32_t opAddr, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, $%0x",
string_for_op(pHandlerObject), reg_string_rs(opVal), opAddr + (op_imm_16(opVal) << 2));
}
void conditional_branch_reg_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const uint32_t opAddr, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s, $%0x",
string_for_op(pHandlerObject), reg_string_rs(opVal), reg_string_rt(opVal), opAddr + (op_imm_16(opVal) << 2));
}
void load_store_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %i(%s)",
string_for_op(pHandlerObject), reg_string_rt(opVal), op_imm_s16(opVal), reg_string_rs(opVal));
}
void op_reg_st_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s",
string_for_op(pHandlerObject), reg_string_rs(opVal), reg_string_rt(opVal));
}
void op_reg_ts_is16_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s, %i",
string_for_op(pHandlerObject), reg_string_rt(opVal), reg_string_rs(opVal), int32_t(op_imm_s16(opVal)));
}
void op_reg_ts_iu16_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s, %i",
string_for_op(pHandlerObject), reg_string_rt(opVal), reg_string_rs(opVal), op_imm_16(opVal));
}
void op_reg_dt_sa_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s, %i",
string_for_op(pHandlerObject), reg_string_rd(opVal), reg_string_rt(opVal), CNoeR3000A::GetInstructionSA(opVal));
}
void op_reg_d_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s",
string_for_op(pHandlerObject), reg_string_rd(opVal));
}
void op_reg_s_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s",
string_for_op(pHandlerObject), reg_string_rs(opVal));
}
void op_reg_dts_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s, %s",
string_for_op(pHandlerObject), reg_string_rd(opVal), reg_string_rt(opVal), reg_string_rs(opVal));
}
void op_reg_dst_string_format(char *pStringOut, CNoeR3000A *pCpu, const uint32_t opVal, const SR3000ADefaultOpHandler *pHandlerObject)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s, %s",
string_for_op(pHandlerObject), reg_string_rd(opVal), reg_string_rs(opVal), reg_string_rt(opVal));
}
}
class CNoeR3000AOps
{
public: OP_IMPLEMENT(invalid)
{
}
OP_IMPLEMENT_FMT(invalid)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "<invalid op>");
} OP_IMPLEMENT(nop)
{
}
OP_IMPLEMENT_FMT(nop)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "nop");
} OP_IMPLEMENT(table2)
{
const SR3000ADefaultOpHandler &opHandler = CNoeR3000A::mspTable2OpHandlers[CNoeR3000A::GetInstructionOp2(opVal)];
opHandler.mpOpHandler(pCpu, opVal, &opHandler);
}
OP_IMPLEMENT_FMT(table2)
{
const SR3000ADefaultOpHandler &opHandler = CNoeR3000A::mspTable2OpHandlers[CNoeR3000A::GetInstructionOp2(opVal)];
opHandler.mpOpStringFormat(pStringOut, pCpu, opVal, opAddr, &opHandler);
} OP_IMPLEMENT(cbranch)
{
const SR3000ADefaultOpHandler &opHandler = CNoeR3000A::mspCBranchOpHandlers[CNoeR3000A::GetInstructionRT(opVal)];
opHandler.mpOpHandler(pCpu, opVal, &opHandler);
}
OP_IMPLEMENT_FMT(cbranch)
{
const SR3000ADefaultOpHandler &opHandler = CNoeR3000A::mspCBranchOpHandlers[CNoeR3000A::GetInstructionRT(opVal)];
opHandler.mpOpStringFormat(pStringOut, pCpu, opVal, opAddr, &opHandler);
} OP_IMPLEMENT(j)
{
const uint32_t jumpAddr = CNoeR3000A::GetInstructionJumpAddress(opVal) +
(pCpu->mpIR[CNoeR3000A::kIR_PC] & CNoeR3000A::skInstructionJumpAddressPCMask);
pCpu->TakeBranch(jumpAddr);
}
OP_IMPLEMENT_FMT(j)
{
jump_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(jr)
{
pCpu->TakeBranch(reg_rs(pCpu, opVal));
}
OP_IMPLEMENT_FMT(jr)
{
op_reg_s_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(jalr)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = pCpu->mpIR[CNoeR3000A::kIR_PC] + CNoeR3000A::skInstructionSize;
}
pCpu->TakeBranch(reg_rs(pCpu, opVal));
}
OP_IMPLEMENT_FMT(jalr)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s",
string_for_op(pHandlerObject), reg_string_rd(opVal), reg_string_rs(opVal));
} OP_IMPLEMENT(jal)
{
const uint32_t jumpAddr = CNoeR3000A::GetInstructionJumpAddress(opVal) +
(pCpu->mpIR[CNoeR3000A::kIR_PC] & CNoeR3000A::skInstructionJumpAddressPCMask);
SetReturnAddress(pCpu);
pCpu->TakeBranch(jumpAddr);
}
OP_IMPLEMENT_FMT(jal)
{
jump_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(addi)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = reg_rs(pCpu, opVal) + op_imm_s16(opVal);
}
}
OP_IMPLEMENT_FMT(addi)
{
op_reg_ts_is16_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(addiu)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = reg_rs(pCpu, opVal) + op_imm_s16(opVal);
}
}
OP_IMPLEMENT_FMT(addiu)
{
op_reg_ts_is16_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(slti)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = (int32_t(reg_rs(pCpu, opVal)) < op_imm_s16(opVal)) ? 1 : 0;
}
}
OP_IMPLEMENT_FMT(slti)
{
op_reg_ts_is16_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sltiu)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = (reg_rs(pCpu, opVal) < op_imm_16(opVal)) ? 1 : 0;
}
}
OP_IMPLEMENT_FMT(sltiu)
{
op_reg_ts_iu16_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(andi)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = reg_rs(pCpu, opVal) & op_imm_16(opVal);
}
}
OP_IMPLEMENT_FMT(andi)
{
op_reg_ts_iu16_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(ori)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = reg_rs(pCpu, opVal) | op_imm_16(opVal);
}
}
OP_IMPLEMENT_FMT(ori)
{
op_reg_ts_iu16_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(xori)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = reg_rs(pCpu, opVal) ^ op_imm_16(opVal);
}
}
OP_IMPLEMENT_FMT(xori)
{
op_reg_ts_iu16_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(lui)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = (op_imm_16(opVal) << 16);
}
}
OP_IMPLEMENT_FMT(lui)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %i",
string_for_op(pHandlerObject), reg_string_rt(opVal), op_imm_16(opVal));
} OP_IMPLEMENT(cop0)
{
const SR3000ADefaultOpHandler &opHandler = CNoeR3000A::mspCOP0OpHandlers[CNoeR3000A::GetInstructionRS(opVal)];
opHandler.mpOpHandler(pCpu, opVal, &opHandler);
}
OP_IMPLEMENT_FMT(cop0)
{
const SR3000ADefaultOpHandler &opHandler = CNoeR3000A::mspCOP0OpHandlers[CNoeR3000A::GetInstructionRS(opVal)];
opHandler.mpOpStringFormat(pStringOut, pCpu, opVal, opAddr, &opHandler);
} OP_IMPLEMENT(lb)
{
const int8_t readVal = pCpu->ReadMemory8(reg_rs(pCpu, opVal) + op_imm_s16(opVal));
pCpu->LoadGPR(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)), opVal, int32_t(readVal));
}
OP_IMPLEMENT_FMT(lb)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(lh)
{
const int16_t readVal = pCpu->ReadMemory16(reg_rs(pCpu, opVal) + op_imm_s16(opVal));
pCpu->LoadGPR(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)), opVal, int32_t(readVal));
}
OP_IMPLEMENT_FMT(lh)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(lwl)
{
const uint32_t readAddr = reg_rs(pCpu, opVal) + op_imm_s16(opVal);
const uint32_t readVal = pCpu->ReadMemory32((readAddr & ~3));
const uint32_t unalignedShift = ((3 - (readAddr & 3)) << 3);
const uint32_t rtMask = (1 << unalignedShift) - 1;
uint32_t &rt = reg_rt(pCpu, opVal);
const uint32_t newRegVal = (rt & rtMask) | (readVal << unalignedShift);
pCpu->LoadGPR(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)), opVal, newRegVal);
}
OP_IMPLEMENT_FMT(lwl)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(lw)
{
const uint32_t readVal = pCpu->ReadMemory32(reg_rs(pCpu, opVal) + op_imm_s16(opVal));
pCpu->LoadGPR(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)), opVal, readVal);
}
OP_IMPLEMENT_FMT(lw)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(lbu)
{
const uint8_t readVal = pCpu->ReadMemory8(reg_rs(pCpu, opVal) + op_imm_s16(opVal));
pCpu->LoadGPR(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)), opVal, readVal);
}
OP_IMPLEMENT_FMT(lbu)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(lhu)
{
const uint16_t readVal = pCpu->ReadMemory16(reg_rs(pCpu, opVal) + op_imm_s16(opVal));
pCpu->LoadGPR(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)), opVal, readVal);
}
OP_IMPLEMENT_FMT(lhu)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(lwr)
{
const uint32_t readAddr = reg_rs(pCpu, opVal) + op_imm_s16(opVal);
const uint32_t readVal = pCpu->ReadMemory32((readAddr & ~3));
const uint32_t unalignedShift = ((readAddr & 3) << 3);
const uint32_t rtMask = (((1 << unalignedShift) - 1) << (32 - unalignedShift));
uint32_t &rt = reg_rt(pCpu, opVal);
const uint32_t newRegVal = (rt & rtMask) | (readVal >> unalignedShift);
pCpu->LoadGPR(CNoeR3000A::EGPR(CNoeR3000A::GetInstructionRT(opVal)), opVal, newRegVal);
}
OP_IMPLEMENT_FMT(lwr)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sb)
{
pCpu->WriteMemory8(reg_rs(pCpu, opVal) + op_imm_s16(opVal), reinterpret_cast<uint8_t &>(reg_rt(pCpu, opVal)));
}
OP_IMPLEMENT_FMT(sb)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sh)
{
pCpu->WriteMemory16(reg_rs(pCpu, opVal) + op_imm_s16(opVal), reinterpret_cast<uint16_t &>(reg_rt(pCpu, opVal)));
}
OP_IMPLEMENT_FMT(sh)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(swl)
{
const uint32_t addr = reg_rs(pCpu, opVal) + op_imm_s16(opVal);
const uint32_t unalignedShift = ((3 - (addr & 3)) << 3);
const uint32_t memMask = (((1 << unalignedShift) - 1) << (32 - unalignedShift));
const uint32_t memVal = pCpu->ReadMemory32((addr & ~3));
pCpu->WriteMemory32((addr & ~3), (reg_rt(pCpu, opVal) >> unalignedShift) | (memVal & memMask));
}
OP_IMPLEMENT_FMT(swl)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sw)
{
pCpu->WriteMemory32(reg_rs(pCpu, opVal) + op_imm_s16(opVal), reg_rt(pCpu, opVal));
}
OP_IMPLEMENT_FMT(sw)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(swr)
{
const uint32_t addr = reg_rs(pCpu, opVal) + op_imm_s16(opVal);
const uint32_t unalignedShift = ((addr & 3) << 3);
const uint32_t memMask = (1 << unalignedShift) - 1;
const uint32_t memVal = pCpu->ReadMemory32((addr & ~3));
pCpu->WriteMemory32((addr & ~3), (reg_rt(pCpu, opVal) << unalignedShift) | (memVal & memMask));
}
OP_IMPLEMENT_FMT(swr)
{
load_store_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sll)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = (reg_rt(pCpu, opVal) << CNoeR3000A::GetInstructionSA(opVal));
}
}
OP_IMPLEMENT_FMT(sll)
{
op_reg_dt_sa_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(srl)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = (reg_rt(pCpu, opVal) >> CNoeR3000A::GetInstructionSA(opVal));
}
}
OP_IMPLEMENT_FMT(srl)
{
op_reg_dt_sa_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sra)
{
if (!rd_is_r0(opVal))
{
reinterpret_cast<int32_t &>(reg_rd(pCpu, opVal)) = (int32_t(reg_rt(pCpu, opVal)) >> CNoeR3000A::GetInstructionSA(opVal));
}
}
OP_IMPLEMENT_FMT(sra)
{
op_reg_dt_sa_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sllv)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = (reg_rt(pCpu, opVal) << reg_rs(pCpu, opVal));
}
}
OP_IMPLEMENT_FMT(sllv)
{
op_reg_dts_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(srlv)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = (reg_rt(pCpu, opVal) >> reg_rs(pCpu, opVal));
}
}
OP_IMPLEMENT_FMT(srlv)
{
op_reg_dts_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(srav)
{
if (!rd_is_r0(opVal))
{
reinterpret_cast<int32_t &>(reg_rd(pCpu, opVal)) = (int32_t(reg_rt(pCpu, opVal)) >> reg_rs(pCpu, opVal));
}
}
OP_IMPLEMENT_FMT(srav)
{
op_reg_dts_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(mfhi)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = pCpu->mpIR[CNoeR3000A::kIR_Hi];
}
}
OP_IMPLEMENT_FMT(mfhi)
{
op_reg_d_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(mthi)
{
pCpu->mpIR[CNoeR3000A::kIR_Hi] = reg_rd(pCpu, opVal);
}
OP_IMPLEMENT_FMT(mthi)
{
op_reg_d_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(mflo)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = pCpu->mpIR[CNoeR3000A::kIR_Lo];
}
}
OP_IMPLEMENT_FMT(mflo)
{
op_reg_d_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(mtlo)
{
pCpu->mpIR[CNoeR3000A::kIR_Lo] = reg_rd(pCpu, opVal);
}
OP_IMPLEMENT_FMT(mtlo)
{
op_reg_d_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(mult)
{
const uint64_t result = uint64_t(int64_t(reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal))) *
int64_t(reinterpret_cast<int32_t &>(reg_rt(pCpu, opVal))));
pCpu->mpIR[CNoeR3000A::kIR_Lo] = uint32_t(result);
pCpu->mpIR[CNoeR3000A::kIR_Hi] = uint32_t(result >> 32);
}
OP_IMPLEMENT_FMT(mult)
{
op_reg_st_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(multu)
{
const uint64_t result = uint64_t(reg_rs(pCpu, opVal)) * uint64_t(reg_rt(pCpu, opVal));
pCpu->mpIR[CNoeR3000A::kIR_Lo] = uint32_t(result);
pCpu->mpIR[CNoeR3000A::kIR_Hi] = uint32_t(result >> 32);
}
OP_IMPLEMENT_FMT(multu)
{
op_reg_st_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(div)
{
if (reg_rt(pCpu, opVal) != 0)
{
pCpu->mpIR[CNoeR3000A::kIR_Lo] = uint32_t(reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) / reinterpret_cast<int32_t &>(reg_rt(pCpu, opVal)));
pCpu->mpIR[CNoeR3000A::kIR_Hi] = uint32_t(reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) % reinterpret_cast<int32_t &>(reg_rt(pCpu, opVal)));
}
else
{
SetDivideByZeroResult(pCpu, reg_rs(pCpu, opVal));
}
}
OP_IMPLEMENT_FMT(div)
{
op_reg_st_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(divu)
{
if (reg_rt(pCpu, opVal) != 0)
{
pCpu->mpIR[CNoeR3000A::kIR_Lo] = reg_rs(pCpu, opVal) / reg_rt(pCpu, opVal);
pCpu->mpIR[CNoeR3000A::kIR_Hi] = reg_rs(pCpu, opVal) % reg_rt(pCpu, opVal);
}
else
{
SetDivideByZeroResult(pCpu, reg_rs(pCpu, opVal));
}
}
OP_IMPLEMENT_FMT(divu)
{
op_reg_st_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(add)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = reg_rs(pCpu, opVal) + reg_rt(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(add)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(addu)
{
add(pCpu, opVal, pHandlerObject);
}
OP_IMPLEMENT_FMT(addu)
{
add_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(sub)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = reg_rs(pCpu, opVal) - reg_rt(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(sub)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(subu)
{
sub(pCpu, opVal, pHandlerObject);
}
OP_IMPLEMENT_FMT(subu)
{
sub_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(and)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = reg_rs(pCpu, opVal) & reg_rt(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(and)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(or)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = reg_rs(pCpu, opVal) | reg_rt(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(or)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(xor)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = reg_rs(pCpu, opVal) ^ reg_rt(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(xor)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(nor)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = ~(reg_rs(pCpu, opVal) | reg_rt(pCpu, opVal));
}
}
OP_IMPLEMENT_FMT(nor)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(slt)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = (int32_t(reg_rs(pCpu, opVal)) < int32_t(reg_rt(pCpu, opVal))) ? 1 : 0;
}
}
OP_IMPLEMENT_FMT(slt)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(sltu)
{
if (!rd_is_r0(opVal))
{
reg_rd(pCpu, opVal) = (reg_rs(pCpu, opVal) < reg_rt(pCpu, opVal)) ? 1 : 0;
}
}
OP_IMPLEMENT_FMT(sltu)
{
op_reg_dst_string_format(pStringOut, pCpu, opVal, pHandlerObject);
} OP_IMPLEMENT(beq)
{
if (reg_rs(pCpu, opVal) == reg_rt(pCpu, opVal))
{
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(beq)
{
conditional_branch_reg_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(bne)
{
if (reg_rs(pCpu, opVal) != reg_rt(pCpu, opVal))
{
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(bne)
{
conditional_branch_reg_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(blez)
{
if (reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) <= 0)
{
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(blez)
{
conditional_branch_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(bgtz)
{
if (reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) > 0)
{
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(bgtz)
{
conditional_branch_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(bltz)
{
if (reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) < 0)
{
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(bltz)
{
conditional_branch_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(bgez)
{
if (reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) >= 0)
{
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(bgez)
{
conditional_branch_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(bltzal)
{
if (reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) < 0)
{
SetReturnAddress(pCpu);
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(bltzal)
{
conditional_branch_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(bgezal)
{
if (reinterpret_cast<int32_t &>(reg_rs(pCpu, opVal)) >= 0)
{
SetReturnAddress(pCpu);
TakeConditionalBranch(pCpu, opVal);
}
}
OP_IMPLEMENT_FMT(bgezal)
{
conditional_branch_string_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(mfc0)
{
if (!rt_is_r0(opVal))
{
reg_rt(pCpu, opVal) = pCpu->C0R()[CNoeR3000A::GetInstructionRD(opVal)];
}
}
OP_IMPLEMENT_FMT(mfc0)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s",
string_for_op(pHandlerObject), reg_string_rt(opVal), cop0_reg_string(CNoeR3000A::GetInstructionRD(opVal)));
} OP_IMPLEMENT(cfc0)
{
mfc0(pCpu, opVal, pHandlerObject);
}
OP_IMPLEMENT_FMT(cfc0)
{
mfc0_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(mtc0)
{
pCpu->mpWriteCOP0Reg(pCpu, CNoeR3000A::EC0R(CNoeR3000A::GetInstructionRD(opVal)), reg_rt(pCpu, opVal));
}
OP_IMPLEMENT_FMT(mtc0)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "%s%s, %s",
string_for_op(pHandlerObject), reg_string_rt(opVal), cop0_reg_string(CNoeR3000A::GetInstructionRD(opVal)));
} OP_IMPLEMENT(ctc0)
{
mtc0(pCpu, opVal, pHandlerObject);
}
OP_IMPLEMENT_FMT(ctc0)
{
mtc0_format(pStringOut, pCpu, opVal, opAddr, pHandlerObject);
} OP_IMPLEMENT(rfe)
{
const uint32_t kStatusMask = (1 << 6) - 1;
const uint32_t oldStatus = pCpu->C0R()[CNoeR3000A::kC0R_Status];
const uint32_t newStatus = (oldStatus & ~kStatusMask) | ((oldStatus & kStatusMask) >> 2);
pCpu->mpWriteCOP0Reg(pCpu, CNoeR3000A::kC0R_Status, newStatus);
}
OP_IMPLEMENT_FMT(rfe)
{
NoeSPrintF(pStringOut, CNoeR3000A::skMaximumOpStringLength, "rfe");
}
private:
static void TakeConditionalBranch(CNoeR3000A *pCpu, const uint32_t opVal)
{
pCpu->TakeBranch(pCpu->mpIR[CNoeR3000A::kIR_PC] + (op_imm_s16(opVal) << 2));
}
static void SetReturnAddress(CNoeR3000A *pCpu)
{
pCpu->mpGPR[CNoeR3000A::kGPR_RA] = pCpu->mpIR[CNoeR3000A::kIR_PC] + CNoeR3000A::skInstructionSize;
}
static void SetDivideByZeroResult(CNoeR3000A *pCpu, const uint32_t eVal)
{ pCpu->mpIR[CNoeR3000A::kIR_Lo] = UINT_MAX;
pCpu->mpIR[CNoeR3000A::kIR_Hi] = eVal;
}
CNoeR3000AOps();};
SR3000ADefaultOpHandler CNoeR3000A::mspDefaultOpHandlers[CNoeR3000A::skInstructionOpMaxCount] =
{
OP_OB(table2), OP_OB(cbranch), OP_OB(j), OP_OB(jal), OP_OB(beq), OP_OB(bne), OP_OB(blez), OP_OB(bgtz),
OP_OB(addi), OP_OB(addiu), OP_OB(slti), OP_OB(sltiu), OP_OB(andi), OP_OB(ori), OP_OB(xori), OP_OB(lui),
OP_OB(cop0), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(lb), OP_OB(lh), OP_OB(lwl), OP_OB(lw), OP_OB(lbu), OP_OB(lhu), OP_OB(lwr), OP_OB(invalid),
OP_OB(sb), OP_OB(sh), OP_OB(swl), OP_OB(sw), OP_OB(invalid), OP_OB(invalid), OP_OB(swr), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid)
};
SR3000ADefaultOpHandler CNoeR3000A::mspTable2OpHandlers[CNoeR3000A::skInstructionOpMaxCount] =
{
OP_OB(sll), OP_OB(invalid), OP_OB(srl), OP_OB(sra), OP_OB(sllv), OP_OB(invalid), OP_OB(srlv), OP_OB(srav),
OP_OB(jr), OP_OB(jalr), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(mfhi), OP_OB(mthi), OP_OB(mflo), OP_OB(mtlo), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(mult), OP_OB(multu), OP_OB(div), OP_OB(divu), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(add), OP_OB(addu), OP_OB(sub), OP_OB(subu), OP_OB(and), OP_OB(or), OP_OB(xor), OP_OB(nor),
OP_OB(invalid), OP_OB(invalid), OP_OB(slt), OP_OB(sltu), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid)
};
SR3000ADefaultOpHandler CNoeR3000A::mspCBranchOpHandlers[CNoeR3000A::skInstructionRegMaxCount] =
{
OP_OB(bltz), OP_OB(bgez), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(bltzal), OP_OB(bgezal), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid)
};
SR3000ADefaultOpHandler CNoeR3000A::mspCOP0OpHandlers[CNoeR3000A::skInstructionRegMaxCount] =
{
OP_OB(mfc0), OP_OB(invalid), OP_OB(cfc0), OP_OB(invalid), OP_OB(mtc0), OP_OB(invalid), OP_OB(ctc0), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(rfe), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid),
OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid), OP_OB(invalid)
};
CNoeR3000A::CNoeR3000A()
: mpUserData(NULL)
#if NOER3000A_DEBUGGER()
, mDebugger()
#endif
{
SetDefaults();
Reset();
#if NOER3000A_DEBUGGER()
mDebugger.SetUserData(this);
mDebugger.SetDebuggerReadData(debugger_read_data);
mDebugger.SetDebuggerWriteData(debugger_write_data);
mDebugger.SetDebuggerReadReg(debugger_read_reg);
mDebugger.SetDebuggerWriteReg(debugger_write_reg);
mDebugger.SetDebuggerDisassemble(debugger_disassemble);
const NNoeDebugProtocol::SContext debugContext("MIPS_R3000A", skInstructionSize, 0, NNoeDebugProtocol::skRegCountAll);
mDebugger.SetContexts(&debugContext, 1); NoeAssert(mDebugger.GetRegisterCount() == 0);
for (uint32_t gprIndex = 0; gprIndex < CNoeR3000A::kGPR_Count; ++gprIndex)
{
mDebugger.AddRegister(skGPRNameForIndex[gprIndex], sizeof(uint32_t));
}
for (uint32_t irIndex = 0; irIndex < CNoeR3000A::kIR_Count; ++irIndex)
{
mDebugger.AddRegister(skIRNameForIndex[irIndex], sizeof(uint32_t),
(irIndex == CNoeR3000A::kIR_PC) ? NNoeDebugProtocol::kRF_PC : NNoeDebugProtocol::kRF_None);
}
for (uint32_t c0rIndex = 0; c0rIndex < CNoeR3000A::kC0R_Count; ++c0rIndex)
{
mDebugger.AddRegister(cop0_reg_string(c0rIndex), sizeof(uint32_t));
}
#endif
}
void CNoeR3000A::ExecuteCycles(const uint64_t cycleCount)
{
const uint64_t targetCycleCount = mCyclesExecuted + cycleCount;
NoeAssert(targetCycleCount > mCyclesExecuted);
while (mCyclesExecuted < targetCycleCount)
{
ReadAndExecuteOp();
}
}
void CNoeR3000A::ConsumeCycles(const int64_t cycleCount)
{
mCyclesExecuted += cycleCount;
if (mpOnCyclesConsumed)
{
mpOnCyclesConsumed(this, cycleCount);
}
}
void CNoeR3000A::CheckDelayedOperations()
{ if (mDelayBranch.mTargetCycle && mDelayBranch.mTargetCycle <= mCyclesExecuted)
{
mpIR[kIR_PC] = mDelayBranch.mAddr;
mDelayBranch.mTargetCycle = 0;
if (mpOnBranchTaken)
{
mpOnBranchTaken(this, mDelayBranch.mAddr);
}
} if (mDelayGPRLoadMask)
{
uint32_t bitStart, bitEndPlusOne;
NoeGetFirstLastBitSet64(&bitStart, &bitEndPlusOne, mDelayGPRLoadMask);
for (uint32_t currentBitIndex = bitStart; currentBitIndex < bitEndPlusOne; ++currentBitIndex)
{
const uint64_t currentBit = (1ULL << uint64_t(currentBitIndex));
if (mDelayGPRLoadMask & currentBit)
{
const SDelayGPRLoad &delayLoad = mDelayGPRLoad[currentBitIndex];
if (delayLoad.mTargetCycle <= mCyclesExecuted)
{
mpGPR[currentBitIndex] = delayLoad.mRegVal;
mDelayGPRLoadMask &= ~currentBit;
}
}
}
}
}
void CNoeR3000A::AddOpHandler(const SOpHandler &opHandler)
{
const uint32_t op = GetInstructionOp(opHandler.mOpVal);
mOpHandlers[op].push_back(opHandler);
}
void CNoeR3000A::SetDefaults()
{
for (int32_t opIndex = 0; opIndex < skInstructionOpMaxCount; ++opIndex)
{
mOpHandlers[opIndex].clear();
}
SetReadMemory8(NULL);
SetReadMemory16(NULL);
SetReadMemory32(NULL);
SetReadInstruction(NULL);
SetWriteMemory8(NULL);
SetWriteMemory16(NULL);
SetWriteMemory32(NULL);
SetWriteCOP0Reg(NULL);
SetDelayLoadForOp(NULL);
SetOnCyclesConsumed(NULL);
SetOnOpExecuted(NULL);
SetOnBranchBegin(NULL);
SetOnBranchTaken(NULL);
SetGPRMemory(NULL);
SetIRMemory(NULL);
SetC0RMemory(NULL);
SetCyclesPerOp(skDefaultCyclesPerOp);
SetDelayBranchCycles(skDefaultDelayBranchCycles);
SetDelayLoadCycles(skDefaultDelayLoadCycles);
}
void CNoeR3000A::Reset()
{
mCyclesExecuted = 0;
mDelayBranch = SDelayBranch();
mDelayGPRLoadMask = 0;
#if NOER3000A_DEBUGGER()
mDebugger.OnReset();
#endif
}
void CNoeR3000A::SetReadMemory8(TReadMemory8 pReadMemory8)
{
mpReadMemory8 = (pReadMemory8) ? pReadMemory8 : default_read_memory<uint8_t>;
}
void CNoeR3000A::SetReadMemory16(TReadMemory16 pReadMemory16)
{
mpReadMemory16 = (pReadMemory16) ? pReadMemory16 : default_read_memory<uint16_t>;
}
void CNoeR3000A::SetReadMemory32(TReadMemory32 pReadMemory32)
{
mpReadMemory32 = (pReadMemory32) ? pReadMemory32 : default_read_memory<uint32_t>;
}
void CNoeR3000A::SetReadInstruction(TReadInstruction pReadInstruction)
{
mpReadInstruction = (pReadInstruction) ? pReadInstruction : default_read_memory<uint32_t>;
}
void CNoeR3000A::SetWriteMemory8(TWriteMemory8 pWriteMemory8)
{
mpWriteMemory8 = (pWriteMemory8) ? pWriteMemory8 : default_write_memory<uint8_t>;
}
void CNoeR3000A::SetWriteMemory16(TWriteMemory16 pWriteMemory16)
{
mpWriteMemory16 = (pWriteMemory16) ? pWriteMemory16 : default_write_memory<uint16_t>;
}
void CNoeR3000A::SetWriteMemory32(TWriteMemory32 pWriteMemory32)
{
mpWriteMemory32 = (pWriteMemory32) ? pWriteMemory32 : default_write_memory<uint32_t>;
}
void CNoeR3000A::SetWriteCOP0Reg(TWriteCOP0Reg pWriteCOP0Reg)
{
mpWriteCOP0Reg = (pWriteCOP0Reg) ? pWriteCOP0Reg : default_write_cop0_reg;
}
void CNoeR3000A::SetDelayLoadForOp(TDelayLoadForOp pDelayLoadForOp)
{
mpDelayLoadForOp = pDelayLoadForOp;
}
void CNoeR3000A::SetOnCyclesConsumed(TOnCyclesConsumed pOnCyclesConsumed)
{
mpOnCyclesConsumed = pOnCyclesConsumed;
}
void CNoeR3000A::SetOnOpExecuted(TOnOpExecuted pOnOpExecuted)
{
mpOnOpExecuted = pOnOpExecuted;
}
void CNoeR3000A::SetOnBranchBegin(TOnBranch pOnBranchBegin)
{
mpOnBranchBegin = pOnBranchBegin;
}
void CNoeR3000A::SetOnBranchTaken(TOnBranch pOnBranchTaken)
{
mpOnBranchTaken = pOnBranchTaken;
}
void CNoeR3000A::SetGPRMemory(uint32_t *pGPR)
{
mpGPR = (pGPR) ? pGPR : mDefaultGPR;
}
void CNoeR3000A::SetIRMemory(uint32_t *pIR)
{
mpIR = (pIR) ? pIR : mDefaultIR;
}
void CNoeR3000A::SetC0RMemory(uint32_t *pC0R)
{
mpC0R = (pC0R) ? pC0R : mDefaultC0R;
}
const char *CNoeR3000A::GetGPRName(const EGPR gprIndex)
{
return skGPRNameForIndex[gprIndex];
}
void CNoeR3000A::ReadAndExecuteOp()
{
const uint32_t opAddr = mpIR[kIR_PC];
mpIR[kIR_Op] = ReadInstruction(opAddr);
#if NOER3000A_DEBUGGER()
mDebugger.CheckInstructionBP(opAddr); do
{
mDebugger.Update();
} while (mDebugger.GetStatus() == NNoeDebugProtocol::kStatus_Halted);
#endif
mpIR[kIR_PC] += skInstructionSize; ConsumeCycles(mCyclesPerOp);
ExecuteOp(mpIR[kIR_Op], opAddr);
NoeAssert(mpGPR[kGPR_Zero] == 0);
}
void CNoeR3000A::ExecuteOp(const uint32_t opVal, const uint32_t opAddr)
{ if (opVal != 0)
{
const uint32_t op = GetInstructionOp(opVal); bool ranCustomHandler = false;
const TOpHandlerList &handlers = mOpHandlers[op];
for (TOpHandlerList::const_iterator it = handlers.begin(); it != handlers.end(); ++it)
{
const SOpHandler &handler = *it;
if (handler.mOpVal == (opVal & handler.mOpMask) &&
handler.mpOpHandler(this, opVal))
{
ranCustomHandler = true;
break;
}
} if (!ranCustomHandler)
{
const SR3000ADefaultOpHandler &opHandler = mspDefaultOpHandlers[op];
opHandler.mpOpHandler(this, opVal, &opHandler);
}
}
if (mpOnOpExecuted)
{
mpOnOpExecuted(this, opVal);
}
CheckDelayedOperations();
}
void CNoeR3000A::TakeBranch(const uint32_t addr)
{
if (mpOnBranchBegin)
{
mpOnBranchBegin(this, addr);
}
if (mDelayBranchCycles)
{
mDelayBranch.mAddr = addr;
mDelayBranch.mTargetCycle = mCyclesExecuted + mDelayBranchCycles;
}
else
{ ReadAndExecuteOp();
mpIR[kIR_PC] = addr;
if (mpOnBranchTaken)
{
mpOnBranchTaken(this, addr);
}
}
}
void CNoeR3000A::LoadGPR(const EGPR gprIndex, const uint32_t opVal, const uint32_t regVal)
{
if (gprIndex != kGPR_Zero)
{
const uint32_t delayLoadCycles = (mpDelayLoadForOp) ? mpDelayLoadForOp(this, opVal) : mDelayLoadCycles;
if (!delayLoadCycles)
{
mpGPR[gprIndex] = regVal;
}
else
{
mDelayGPRLoad[gprIndex].mRegVal = regVal;
mDelayGPRLoad[gprIndex].mTargetCycle = mCyclesExecuted + delayLoadCycles;
mDelayGPRLoadMask |= (1ULL << gprIndex);
}
}
}
#if NOER3000A_DEBUGGER()
#define DEBUGGER_CHECK_READ(addr, size, accessType) \
if (accessType == kAT_Default) \
{ \
mDebugger.CheckDataReadBP(addr, size); \
}
#define DEBUGGER_CHECK_WRITE(addr, size, accessType) \
if (accessType == kAT_Default) \
{ \
mDebugger.CheckDataWriteBP(addr, size); \
}
#else
#define DEBUGGER_CHECK_READ(addr, size, accessType)
#define DEBUGGER_CHECK_WRITE(addr, size, accessType)
#endif
uint8_t CNoeR3000A::ReadMemory8(const uint32_t addr, const EAccessType accessType)
{
DEBUGGER_CHECK_READ(addr, sizeof(uint8_t), accessType);
return mpReadMemory8(this, addr, accessType);
}
uint16_t CNoeR3000A::ReadMemory16(const uint32_t addr, const EAccessType accessType)
{
DEBUGGER_CHECK_READ(addr, sizeof(uint16_t), accessType);
return mpReadMemory16(this, addr, accessType);
}
uint32_t CNoeR3000A::ReadMemory32(const uint32_t addr, const EAccessType accessType)
{
DEBUGGER_CHECK_READ(addr, sizeof(uint32_t), accessType);
return mpReadMemory32(this, addr, accessType);
}
uint32_t CNoeR3000A::ReadInstruction(const uint32_t addr, const EAccessType accessType)
{
return mpReadInstruction(this, addr, accessType);
}
void CNoeR3000A::WriteMemory8(const uint32_t addr, const uint8_t memVal, const EAccessType accessType)
{
DEBUGGER_CHECK_WRITE(addr, sizeof(uint8_t), accessType);
mpWriteMemory8(this, addr, memVal, accessType);
}
void CNoeR3000A::WriteMemory16(const uint32_t addr, const uint16_t memVal, const EAccessType accessType)
{
DEBUGGER_CHECK_WRITE(addr, sizeof(uint16_t), accessType);
mpWriteMemory16(this, addr, memVal, accessType);
}
void CNoeR3000A::WriteMemory32(const uint32_t addr, const uint32_t memVal, const EAccessType accessType)
{
DEBUGGER_CHECK_WRITE(addr, sizeof(uint32_t), accessType);
mpWriteMemory32(this, addr, memVal, accessType);
}
void CNoeR3000A::FormatOpString(char *pStringOut, const uint32_t opVal, const uint32_t opAddr)
{
if (opVal != 0)
{
const uint32_t op = GetInstructionOp(opVal);
const TOpHandlerList &handlers = mOpHandlers[op];
for (TOpHandlerList::const_iterator it = handlers.begin(); it != handlers.end(); ++it)
{
const SOpHandler &handler = *it;
if (handler.mOpVal == (opVal & handler.mOpMask) &&
handler.mpOpStringFormat &&
handler.mpOpStringFormat(pStringOut, this, opVal))
{
return;
}
}
const SR3000ADefaultOpHandler &opHandler = mspDefaultOpHandlers[op];
opHandler.mpOpStringFormat(pStringOut, this, opVal, opAddr, &opHandler);
}
else
{
CNoeR3000AOps::nop_format(pStringOut, this, opVal, opAddr, NULL);
}
}