Play-/Source/MA_MIPSIV.cpp

1234 lines
30 KiB
C++
Raw Normal View History

#include <stddef.h>
#include "MA_MIPSIV.h"
#include "MIPS.h"
#include "CodeGen.h"
#include "MemoryUtils.h"
#include "COP_SCU.h"
#include "offsetof_def.h"
#include "Integer64.h"
#include "placeholder_def.h"
using namespace std::tr1;
uint32 g_LWMaskRight[4] =
{
0x00FFFFFF,
0x0000FFFF,
0x000000FF,
0x00000000,
};
uint32 g_LWMaskLeft[4] =
{
0xFFFFFF00,
0xFFFF0000,
0xFF000000,
0x00000000,
};
uint64 g_LDMaskRight[8] =
{
0x00FFFFFFFFFFFFFFULL,
0x0000FFFFFFFFFFFFULL,
0x000000FFFFFFFFFFULL,
0x00000000FFFFFFFFULL,
0x0000000000FFFFFFULL,
0x000000000000FFFFULL,
0x00000000000000FFULL,
0x0000000000000000ULL,
};
uint64 g_LDMaskLeft[8] =
{
0xFFFFFFFFFFFFFF00ULL,
0xFFFFFFFFFFFF0000ULL,
0xFFFFFFFFFF000000ULL,
0xFFFFFFFF00000000ULL,
0xFFFFFF0000000000ULL,
0xFFFF000000000000ULL,
0xFF00000000000000ULL,
0x0000000000000000ULL,
};
void LWL_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x03;
uint32 byteOffset = address & 0x03;
uint32 accessType = 3 - byteOffset;
uint32 memory = CMemoryUtils::GetWordProxy(context, alignedAddress);
memory <<= accessType * 8;
context->m_State.nGPR[rt].nV0 &= g_LWMaskRight[byteOffset];
context->m_State.nGPR[rt].nV0 |= memory;
context->m_State.nGPR[rt].nV1 = context->m_State.nGPR[rt].nV0 & 0x80000000 ? 0xFFFFFFFF : 0x00000000;
}
void LWR_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x03;
uint32 byteOffset = address & 0x03;
uint32 accessType = 3 - byteOffset;
uint32 memory = CMemoryUtils::GetWordProxy(context, alignedAddress);
memory >>= byteOffset * 8;
context->m_State.nGPR[rt].nV0 &= g_LWMaskLeft[accessType];
context->m_State.nGPR[rt].nV0 |= memory;
context->m_State.nGPR[rt].nV1 = context->m_State.nGPR[rt].nV0 & 0x80000000 ? 0xFFFFFFFF : 0x00000000;
}
void LDL_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x07;
uint32 byteOffset = address & 0x07;
uint32 accessType = 7 - byteOffset;
INTEGER64 memory;
memory.d0 = CMemoryUtils::GetWordProxy(context, alignedAddress + 0);
memory.d1 = CMemoryUtils::GetWordProxy(context, alignedAddress + 4);
memory.q <<= accessType * 8;
context->m_State.nGPR[rt].nD0 &= g_LDMaskRight[byteOffset];
context->m_State.nGPR[rt].nD0 |= memory.q;
}
void LDR_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x07;
uint32 byteOffset = address & 0x07;
uint32 accessType = 7 - byteOffset;
INTEGER64 memory;
memory.d0 = CMemoryUtils::GetWordProxy(context, alignedAddress + 0);
memory.d1 = CMemoryUtils::GetWordProxy(context, alignedAddress + 4);
memory.q >>= byteOffset * 8;
context->m_State.nGPR[rt].nD0 &= g_LDMaskLeft[accessType];
context->m_State.nGPR[rt].nD0 |= memory.q;
}
void SWL_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x03;
uint32 byteOffset = address & 0x03;
uint32 accessType = 3 - byteOffset;
uint32 reg = context->m_State.nGPR[rt].nV0;
reg >>= accessType * 8;
uint32 memory = CMemoryUtils::GetWordProxy(context, alignedAddress);
memory &= g_LWMaskLeft[byteOffset];
memory |= reg;
CMemoryUtils::SetWordProxy(context, memory, alignedAddress);
}
void SWR_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x03;
uint32 byteOffset = address & 0x03;
uint32 accessType = 3 - byteOffset;
uint32 reg = context->m_State.nGPR[rt].nV0;
reg <<= byteOffset * 8;
uint32 memory = CMemoryUtils::GetWordProxy(context, alignedAddress);
memory &= g_LWMaskRight[accessType];
memory |= reg;
CMemoryUtils::SetWordProxy(context, memory, alignedAddress);
}
void SDL_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x07;
uint32 byteOffset = address & 0x07;
uint32 accessType = 7 - byteOffset;
uint64 reg = context->m_State.nGPR[rt].nD0;
reg >>= accessType * 8;
INTEGER64 memory;
memory.d0 = CMemoryUtils::GetWordProxy(context, alignedAddress + 0);
memory.d1 = CMemoryUtils::GetWordProxy(context, alignedAddress + 4);
memory.q &= g_LDMaskLeft[byteOffset];
memory.q |= reg;
CMemoryUtils::SetWordProxy(context, memory.d0, alignedAddress + 0);
CMemoryUtils::SetWordProxy(context, memory.d1, alignedAddress + 4);
}
void SDR_Proxy(uint32 address, uint32 rt, CMIPS* context)
{
uint32 alignedAddress = address & ~0x07;
uint32 byteOffset = address & 0x07;
uint32 accessType = 7 - byteOffset;
uint64 reg = context->m_State.nGPR[rt].nD0;
reg <<= byteOffset * 8;
INTEGER64 memory;
memory.d0 = CMemoryUtils::GetWordProxy(context, alignedAddress + 0);
memory.d1 = CMemoryUtils::GetWordProxy(context, alignedAddress + 4);
memory.q &= g_LDMaskRight[accessType];
memory.q |= reg;
CMemoryUtils::SetWordProxy(context, memory.d0, alignedAddress + 0);
CMemoryUtils::SetWordProxy(context, memory.d1, alignedAddress + 4);
}
CMA_MIPSIV::CMA_MIPSIV(MIPS_REGSIZE nRegSize) :
CMIPSArchitecture(nRegSize)
{
SetupInstructionTables();
SetupReflectionTables();
}
CMA_MIPSIV::~CMA_MIPSIV()
{
}
void CMA_MIPSIV::SetupInstructionTables()
{
for(unsigned int i = 0; i < MAX_GENERAL_OPS; i++)
{
m_pOpGeneral[i] = bind(m_cOpGeneral[i], this);
}
for(unsigned int i = 0; i < MAX_SPECIAL_OPS; i++)
{
m_pOpSpecial[i] = bind(m_cOpSpecial[i], this);
}
for(unsigned int i = 0; i < MAX_SPECIAL2_OPS; i++)
{
m_pOpSpecial2[i] = bind(&CMA_MIPSIV::Illegal, this);
}
for(unsigned int i = 0; i < MAX_REGIMM_OPS; i++)
{
m_pOpRegImm[i] = bind(m_cOpRegImm[i], this);
}
}
void CMA_MIPSIV::CompileInstruction(uint32 nAddress, CCodeGen* codeGen, CMIPS* pCtx)
{
SetupQuickVariables(nAddress, codeGen, pCtx);
m_nRS = (uint8)((m_nOpcode >> 21) & 0x1F);
m_nRT = (uint8)((m_nOpcode >> 16) & 0x1F);
m_nRD = (uint8)((m_nOpcode >> 11) & 0x1F);
m_nSA = (uint8)((m_nOpcode >> 6) & 0x1F);
m_nImmediate = (uint16)(m_nOpcode & 0xFFFF);
if(m_nOpcode)
{
m_pOpGeneral[(m_nOpcode >> 26)]();
}
}
void CMA_MIPSIV::SPECIAL()
{
m_pOpSpecial[m_nImmediate & 0x3F]();
}
void CMA_MIPSIV::SPECIAL2()
{
m_pOpSpecial2[m_nImmediate & 0x3F]();
}
void CMA_MIPSIV::REGIMM()
{
m_pOpRegImm[m_nRT]();
}
//////////////////////////////////////////////////
//General Opcodes
//////////////////////////////////////////////////
//02
void CMA_MIPSIV::J()
{
m_codeGen->PushCst((m_nAddress & 0xF0000000) | ((m_nOpcode & 0x03FFFFFF) << 2));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
}
//03
void CMA_MIPSIV::JAL()
{
//64-bit addresses?
//Save the address in RA
m_codeGen->PushCst(m_nAddress + 8);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[31].nV[0]));
//Update jump address
m_codeGen->PushCst((m_nAddress & 0xF0000000) | ((m_nOpcode & 0x03FFFFFF) << 2));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
}
//04
void CMA_MIPSIV::BEQ()
{
Template_BranchEq(true, false);
}
//05
void CMA_MIPSIV::BNE()
{
Template_BranchEq(false, false);
}
//06
void CMA_MIPSIV::BLEZ()
{
//Less/Equal & Not Likely
Template_BranchLez(true, false);
}
//07
void CMA_MIPSIV::BGTZ()
{
//Not Less/Equal & Not Likely
Template_BranchLez(false, false);
}
//08
void CMA_MIPSIV::ADDI()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushCst(static_cast<int16>(m_nImmediate));
m_codeGen->Add();
m_codeGen->SeX();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
}
//09
void CMA_MIPSIV::ADDIU()
{
if(m_nRT == 0 && m_nRS == 0)
{
//Hack: PS2 IOP uses ADDIU R0, R0, $x for dynamic linking
m_codeGen->PushCst(m_nAddress);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[CCOP_SCU::EPC]));
m_codeGen->PushCst(1);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nHasException));
}
else
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushCst(static_cast<int16>(m_nImmediate));
m_codeGen->Add();
if(m_regSize == MIPS_REGSIZE_64)
{
m_codeGen->SeX();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
}
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
}
}
//0A
void CMA_MIPSIV::SLTI()
{
Template_SetLessThanImm(true);
}
//0B
void CMA_MIPSIV::SLTIU()
{
Template_SetLessThanImm(false);
}
//0C
void CMA_MIPSIV::ANDI()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushCst(m_nImmediate);
m_codeGen->And();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushCst(0);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
}
//0D
void CMA_MIPSIV::ORI()
{
//Lower 32-bits
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushCst(m_nImmediate);
m_codeGen->Or();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
//Higher 32-bits (only if registers are different)
if(m_nRS != m_nRT)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
}
}
//0E
void CMA_MIPSIV::XORI()
{
//Lower 32-bits
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushCst(m_nImmediate);
m_codeGen->Xor();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
//Higher 32-bits
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
}
//0F
void CMA_MIPSIV::LUI()
{
m_codeGen->PushCst(m_nImmediate << 16);
if(m_regSize == MIPS_REGSIZE_64)
{
m_codeGen->PushCst((m_nImmediate & 0x8000) ? 0xFFFFFFFF : 0x00000000);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
}
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
}
//10
void CMA_MIPSIV::COP0()
{
if(m_pCtx->m_pCOP[0] != NULL)
{
m_pCtx->m_pCOP[0]->CompileInstruction(m_nAddress, m_codeGen, m_pCtx);
}
else
{
Illegal();
}
}
//11
void CMA_MIPSIV::COP1()
{
if(m_pCtx->m_pCOP[1] != NULL)
{
m_pCtx->m_pCOP[1]->CompileInstruction(m_nAddress, m_codeGen, m_pCtx);
}
else
{
Illegal();
}
}
//12
void CMA_MIPSIV::COP2()
{
if(m_pCtx->m_pCOP[2] != NULL)
{
m_pCtx->m_pCOP[2]->CompileInstruction(m_nAddress, m_codeGen, m_pCtx);
}
else
{
Illegal();
}
}
//14
void CMA_MIPSIV::BEQL()
{
Template_BranchEq(true, true);
}
//15
void CMA_MIPSIV::BNEL()
{
Template_BranchEq(false, true);
}
//16
void CMA_MIPSIV::BLEZL()
{
//Less/Equal & Likely
Template_BranchLez(true, true);
}
//17
void CMA_MIPSIV::BGTZL()
{
//Not Less/Equal & Likely
Template_BranchLez(false, true);
}
//19
void CMA_MIPSIV::DADDIU()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1]));
m_codeGen->PushCst(static_cast<int16>(m_nImmediate));
m_codeGen->PushCst((m_nImmediate & 0x8000) == 0 ? 0x00000000 : 0xFFFFFFFF);
m_codeGen->Add64();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
}
//1A
void CMA_MIPSIV::LDL()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&LDL_Proxy), 3, false);
}
//1B
void CMA_MIPSIV::LDR()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&LDR_Proxy), 3, false);
}
//20
void CMA_MIPSIV::LB()
{
ComputeMemAccessAddr();
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushIdx(1);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::GetByteProxy), 2, true);
m_codeGen->SeX8();
if(m_regSize == MIPS_REGSIZE_64)
{
m_codeGen->SeX();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
}
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PullTop();
}
//21
void CMA_MIPSIV::LH()
{
ComputeMemAccessAddr();
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushIdx(1);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::GetHalfProxy), 2, true);
m_codeGen->SeX16();
if(m_regSize == MIPS_REGSIZE_64)
{
m_codeGen->SeX();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
}
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PullTop();
}
//22
void CMA_MIPSIV::LWL()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&LWL_Proxy), 3, false);
}
//23
void CMA_MIPSIV::LW()
{
Template_LoadUnsigned32(reinterpret_cast<void*>(&CMemoryUtils::GetWordProxy));
}
//24
void CMA_MIPSIV::LBU()
{
Template_LoadUnsigned32(reinterpret_cast<void*>(&CMemoryUtils::GetByteProxy));
}
//25
void CMA_MIPSIV::LHU()
{
Template_LoadUnsigned32(reinterpret_cast<void*>(&CMemoryUtils::GetHalfProxy));
}
//26
void CMA_MIPSIV::LWR()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&LWR_Proxy), 3, false);
}
//27
void CMA_MIPSIV::LWU()
{
ComputeMemAccessAddr();
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushIdx(1);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::GetWordProxy), 2, true);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushCst(0);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->PullTop();
}
//28
void CMA_MIPSIV::SB()
{
ComputeMemAccessAddr();
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushIdx(2);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::SetByteProxy), 3, false);
m_codeGen->PullTop();
}
//29
void CMA_MIPSIV::SH()
{
ComputeMemAccessAddr();
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushIdx(2);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::SetHalfProxy), 3, false);
m_codeGen->PullTop();
}
//2A
void CMA_MIPSIV::SWL()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&SWL_Proxy), 3, false);
}
//2B
void CMA_MIPSIV::SW()
{
ComputeMemAccessAddr();
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushIdx(2);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::SetWordProxy), 3, false);
m_codeGen->PullTop();
}
//2C
void CMA_MIPSIV::SDL()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&SDL_Proxy), 3, false);
}
//2D
void CMA_MIPSIV::SDR()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&SDR_Proxy), 3, false);
}
//2E
void CMA_MIPSIV::SWR()
{
ComputeMemAccessAddr();
m_codeGen->PushCst(m_nRT);
m_codeGen->PushRef(m_pCtx);
m_codeGen->Call(reinterpret_cast<void*>(&SWR_Proxy), 3, false);
}
//2F
void CMA_MIPSIV::CACHE()
{
//No cache in our system. Nothing to do.
}
//31
void CMA_MIPSIV::LWC1()
{
if(m_pCtx->m_pCOP[1] != NULL)
{
m_pCtx->m_pCOP[1]->CompileInstruction(m_nAddress, m_codeGen, m_pCtx);
}
else
{
Illegal();
}
}
//36
void CMA_MIPSIV::LDC2()
{
if(m_pCtx->m_pCOP[2] != NULL)
{
m_pCtx->m_pCOP[2]->CompileInstruction(m_nAddress, m_codeGen, m_pCtx);
}
else
{
Illegal();
}
}
//37
void CMA_MIPSIV::LD()
{
ComputeMemAccessAddr();
for(unsigned int i = 0; i < 2; i++)
{
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushIdx(1);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::GetWordProxy), 2, true);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i]));
if(i != 1)
{
m_codeGen->PushCst(4);
m_codeGen->Add();
}
}
m_codeGen->PullTop();
}
//39
void CMA_MIPSIV::SWC1()
{
if(m_pCtx->m_pCOP[1] != NULL)
{
m_pCtx->m_pCOP[1]->CompileInstruction(m_nAddress, m_codeGen, m_pCtx);
}
else
{
Illegal();
}
}
//3E
void CMA_MIPSIV::SDC2()
{
if(m_pCtx->m_pCOP[2] != NULL)
{
m_pCtx->m_pCOP[2]->CompileInstruction(m_nAddress, m_codeGen, m_pCtx);
}
else
{
Illegal();
}
}
//3F
void CMA_MIPSIV::SD()
{
ComputeMemAccessAddr();
for(unsigned int i = 0; i < 2; i++)
{
m_codeGen->PushRef(m_pCtx);
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i]));
m_codeGen->PushIdx(2);
m_codeGen->Call(reinterpret_cast<void*>(&CMemoryUtils::SetWordProxy), 3, false);
if(i != 1)
{
m_codeGen->PushCst(4);
m_codeGen->Add();
}
}
m_codeGen->PullTop();
}
//////////////////////////////////////////////////
//Special Opcodes
//////////////////////////////////////////////////
//00
void CMA_MIPSIV::SLL()
{
Template_ShiftCst32(bind(&CCodeGen::Shl, m_codeGen, PLACEHOLDER_1));
}
//02
void CMA_MIPSIV::SRL()
{
Template_ShiftCst32(bind(&CCodeGen::Srl, m_codeGen, PLACEHOLDER_1));
}
//03
void CMA_MIPSIV::SRA()
{
Template_ShiftCst32(bind(&CCodeGen::Sra, m_codeGen, PLACEHOLDER_1));
}
//04
void CMA_MIPSIV::SLLV()
{
Template_ShiftVar32(bind(&CCodeGen::Shl, m_codeGen));
}
//06
void CMA_MIPSIV::SRLV()
{
Template_ShiftVar32(bind(&CCodeGen::Srl, m_codeGen));
}
//07
void CMA_MIPSIV::SRAV()
{
Template_ShiftVar32(bind(&CCodeGen::Sra, m_codeGen));
}
//08
void CMA_MIPSIV::JR()
{
//TODO: 64-bits addresses
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
}
//09
void CMA_MIPSIV::JALR()
{
//TODO: 64-bits addresses
//Set the jump address
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
//Save address in register
m_codeGen->PushCst(m_nAddress + 8);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//0A
void CMA_MIPSIV::MOVZ()
{
Template_MovEqual(true);
}
//0B
void CMA_MIPSIV::MOVN()
{
Template_MovEqual(false);
}
//0C
void CMA_MIPSIV::SYSCALL()
{
//Save current EPC
m_codeGen->PushCst(m_nAddress);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[CCOP_SCU::EPC]));
m_codeGen->PushCst(1);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nHasException));
}
//0D
void CMA_MIPSIV::BREAK()
{
//NOP
}
//0F
void CMA_MIPSIV::SYNC()
{
//NOP
}
//10
void CMA_MIPSIV::MFHI()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
}
//11
void CMA_MIPSIV::MTHI()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nHI[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nHI[1]));
}
//12
void CMA_MIPSIV::MFLO()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
}
//13
void CMA_MIPSIV::MTLO()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nLO[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nLO[1]));
}
//14
void CMA_MIPSIV::DSLLV()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->Shl64();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//16
void CMA_MIPSIV::DSRLV()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->Srl64();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//18
void CMA_MIPSIV::MULT()
{
Template_Mult32(bind(&CCodeGen::MultS, m_codeGen), 0);
}
//19
void CMA_MIPSIV::MULTU()
{
Template_Mult32(bind(&CCodeGen::Mult, m_codeGen), 0);
}
//1A
void CMA_MIPSIV::DIV()
{
Template_Div32(bind(&CCodeGen::DivS, m_codeGen), 0);
}
//1B
void CMA_MIPSIV::DIVU()
{
Template_Div32(bind(&CCodeGen::Div, m_codeGen), 0);
}
//20
void CMA_MIPSIV::ADD()
{
Template_Add32(true);
}
//21
void CMA_MIPSIV::ADDU()
{
Template_Add32(false);
}
//22
void CMA_MIPSIV::SUB()
{
Template_Sub32(true);
}
//23
void CMA_MIPSIV::SUBU()
{
Template_Sub32(false);
}
//24
void CMA_MIPSIV::AND()
{
if(m_regSize == MIPS_REGSIZE_32)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->And();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
else
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->And64();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
}
//25
void CMA_MIPSIV::OR()
{
//TODO: Use a 64-bits op
for(unsigned int i = 0; i < 2; i++)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i]));
m_codeGen->Or();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i]));
}
}
//26
void CMA_MIPSIV::XOR()
{
for(unsigned int i = 0; i < 2; i++)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i]));
m_codeGen->Xor();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i]));
}
}
//27
void CMA_MIPSIV::NOR()
{
for(unsigned int i = 0; i < 2; i++)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i]));
m_codeGen->Or();
m_codeGen->Not();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i]));
}
}
//2A
void CMA_MIPSIV::SLT()
{
Template_SetLessThanReg(true);
}
//2B
void CMA_MIPSIV::SLTU()
{
Template_SetLessThanReg(false);
}
//2C
void CMA_MIPSIV::DADD()
{
Template_Add64(true);
}
//2D
void CMA_MIPSIV::DADDU()
{
Template_Add64(false);
}
//2F
void CMA_MIPSIV::DSUBU()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->Sub64();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//38
void CMA_MIPSIV::DSLL()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->Shl64(m_nSA);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//3A
void CMA_MIPSIV::DSRL()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->Srl64(m_nSA);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//3B
void CMA_MIPSIV::DSRA()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->Sra64(m_nSA);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//3C
void CMA_MIPSIV::DSLL32()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->Shl64(m_nSA + 0x20);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//3E
void CMA_MIPSIV::DSRL32()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->Srl64(m_nSA + 32);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//3F
void CMA_MIPSIV::DSRA32()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
m_codeGen->Sra64(m_nSA + 32);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0]));
}
//////////////////////////////////////////////////
//Special2 Opcodes
//////////////////////////////////////////////////
//////////////////////////////////////////////////
//RegImm Opcodes
//////////////////////////////////////////////////
//00
void CMA_MIPSIV::BLTZ()
{
//Not greater/equal & not likely
Template_BranchGez(false, false);
}
//01
void CMA_MIPSIV::BGEZ()
{
//Greater/equal & not likely
Template_BranchGez(true, false);
}
//02
void CMA_MIPSIV::BLTZL()
{
//Not greater/equal & likely
Template_BranchGez(false, true);
}
//03
void CMA_MIPSIV::BGEZL()
{
//Greater/equal & likely
Template_BranchGez(true, true);
}
//////////////////////////////////////////////////
//Opcode Tables
//////////////////////////////////////////////////
CMA_MIPSIV::InstructionFuncConstant CMA_MIPSIV::m_cOpGeneral[MAX_GENERAL_OPS] =
{
//0x00
&CMA_MIPSIV::SPECIAL, &CMA_MIPSIV::REGIMM, &CMA_MIPSIV::J, &CMA_MIPSIV::JAL, &CMA_MIPSIV::BEQ, &CMA_MIPSIV::BNE, &CMA_MIPSIV::BLEZ, &CMA_MIPSIV::BGTZ,
//0x08
&CMA_MIPSIV::ADDI, &CMA_MIPSIV::ADDIU, &CMA_MIPSIV::SLTI, &CMA_MIPSIV::SLTIU, &CMA_MIPSIV::ANDI, &CMA_MIPSIV::ORI, &CMA_MIPSIV::XORI, &CMA_MIPSIV::LUI,
//0x10
&CMA_MIPSIV::COP0, &CMA_MIPSIV::COP1, &CMA_MIPSIV::COP2, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::BEQL, &CMA_MIPSIV::BNEL, &CMA_MIPSIV::BLEZL, &CMA_MIPSIV::BGTZL,
//0x18
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::DADDIU, &CMA_MIPSIV::LDL, &CMA_MIPSIV::LDR, &CMA_MIPSIV::SPECIAL2, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal,
//0x20
&CMA_MIPSIV::LB, &CMA_MIPSIV::LH, &CMA_MIPSIV::LWL, &CMA_MIPSIV::LW, &CMA_MIPSIV::LBU, &CMA_MIPSIV::LHU, &CMA_MIPSIV::LWR, &CMA_MIPSIV::LWU,
//0x28
&CMA_MIPSIV::SB, &CMA_MIPSIV::SH, &CMA_MIPSIV::SWL, &CMA_MIPSIV::SW, &CMA_MIPSIV::SDL, &CMA_MIPSIV::SDR, &CMA_MIPSIV::SWR, &CMA_MIPSIV::CACHE,
//0x30
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::LWC1, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::LDC2, &CMA_MIPSIV::LD,
//0x38
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::SWC1, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::SDC2, &CMA_MIPSIV::SD,
};
CMA_MIPSIV::InstructionFuncConstant CMA_MIPSIV::m_cOpSpecial[MAX_SPECIAL_OPS] =
{
//0x00
&CMA_MIPSIV::SLL, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::SRL, &CMA_MIPSIV::SRA, &CMA_MIPSIV::SLLV, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::SRLV, &CMA_MIPSIV::SRAV,
//0x08
&CMA_MIPSIV::JR, &CMA_MIPSIV::JALR, &CMA_MIPSIV::MOVZ, &CMA_MIPSIV::MOVN, &CMA_MIPSIV::SYSCALL, &CMA_MIPSIV::BREAK, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::SYNC,
//0x10
&CMA_MIPSIV::MFHI, &CMA_MIPSIV::MTHI, &CMA_MIPSIV::MFLO, &CMA_MIPSIV::MTLO, &CMA_MIPSIV::DSLLV, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::DSRLV, &CMA_MIPSIV::Illegal,
//0x18
&CMA_MIPSIV::MULT, &CMA_MIPSIV::MULTU, &CMA_MIPSIV::DIV, &CMA_MIPSIV::DIVU, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal,
//0x20
&CMA_MIPSIV::ADD, &CMA_MIPSIV::ADDU, &CMA_MIPSIV::SUB, &CMA_MIPSIV::SUBU, &CMA_MIPSIV::AND, &CMA_MIPSIV::OR, &CMA_MIPSIV::XOR, &CMA_MIPSIV::NOR,
//0x28
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::SLT, &CMA_MIPSIV::SLTU, &CMA_MIPSIV::DADD, &CMA_MIPSIV::DADDU, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::DSUBU,
//0x30
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal,
//0x38
&CMA_MIPSIV::DSLL, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::DSRL, &CMA_MIPSIV::DSRA, &CMA_MIPSIV::DSLL32, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::DSRL32, &CMA_MIPSIV::DSRA32,
};
CMA_MIPSIV::InstructionFuncConstant CMA_MIPSIV::m_cOpRegImm[MAX_REGIMM_OPS] =
{
//0x00
&CMA_MIPSIV::BLTZ, &CMA_MIPSIV::BGEZ, &CMA_MIPSIV::BLTZL, &CMA_MIPSIV::BGEZL, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal,
//0x08
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal,
//0x10
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal,
//0x18
&CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal, &CMA_MIPSIV::Illegal,
};