Play-/Source/MIPSInstructionFactory.cpp

194 lines
5 KiB
C++
Raw Normal View History

#include <assert.h>
#include <stddef.h>
#include "MIPSInstructionFactory.h"
#include "MIPS.h"
#include "offsetof_def.h"
#include "BitManip.h"
#include "COP_SCU.h"
CMIPSInstructionFactory::CMIPSInstructionFactory(MIPS_REGSIZE nRegSize)
2018-04-30 21:01:23 +01:00
: m_regSize(nRegSize)
{
}
void CMIPSInstructionFactory::SetupQuickVariables(uint32 nAddress, CMipsJitter* codeGen, CMIPS* pCtx, uint32 instrPosition)
{
2018-04-30 21:01:23 +01:00
m_pCtx = pCtx;
m_codeGen = codeGen;
m_nAddress = nAddress;
m_instrPosition = instrPosition;
2018-04-30 21:01:23 +01:00
m_nOpcode = m_pCtx->m_pMemoryMap->GetInstruction(m_nAddress);
}
static void HandleTLBException(CMIPS*)
{
//Will exit CPU execution loop with an exception pending
}
void CMIPSInstructionFactory::CheckTLBExceptions(bool isWrite)
{
if(m_pCtx->m_pAddrTranslator == &CMIPS::TranslateAddress64) return;
if(m_pCtx->m_TLBExceptionChecker == nullptr) return;
uint8 nRS = (uint8)((m_nOpcode >> 21) & 0x001F);
uint16 nImmediate = (uint16)((m_nOpcode >> 0) & 0xFFFF);
//Push context
m_codeGen->PushCtx();
//Push low part of address
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[nRS].nV[0]));
if(nImmediate != 0)
{
m_codeGen->PushCst((int16)nImmediate);
m_codeGen->Add();
}
//Push isWrite
m_codeGen->PushCst(isWrite ? 1 : 0);
//Call
m_codeGen->Call(reinterpret_cast<void*>(m_pCtx->m_TLBExceptionChecker), 3, true);
m_codeGen->PushCst(MIPS_EXCEPTION_NONE);
m_codeGen->BeginIf(Jitter::CONDITION_NE);
{
2022-10-18 20:01:36 +01:00
m_codeGen->PushRel(offsetof(CMIPS, m_State.nPC));
m_codeGen->PushCst(m_instrPosition);
m_codeGen->Add();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[CCOP_SCU::EPC]));
m_codeGen->JumpTo(reinterpret_cast<void*>(&HandleTLBException));
}
m_codeGen->EndIf();
}
void CMIPSInstructionFactory::ComputeMemAccessAddr()
{
2018-04-30 21:01:23 +01:00
uint8 nRS = (uint8)((m_nOpcode >> 21) & 0x001F);
uint16 nImmediate = (uint16)((m_nOpcode >> 0) & 0xFFFF);
if(m_pCtx->m_pAddrTranslator == &CMIPS::TranslateAddress64)
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[nRS].nV[0]));
if(nImmediate != 0)
{
m_codeGen->PushCst((int16)nImmediate);
m_codeGen->Add();
}
m_codeGen->PushCst(0x1FFFFFFF);
m_codeGen->And();
}
else
{
//TODO: Compute the complete 64-bit address
//Translate the address
//Push context
m_codeGen->PushCtx();
//Push low part of address
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[nRS].nV[0]));
if(nImmediate != 0)
{
m_codeGen->PushCst((int16)nImmediate);
m_codeGen->Add();
}
//Call
m_codeGen->Call(reinterpret_cast<void*>(m_pCtx->m_pAddrTranslator), 2, true);
}
}
2016-07-16 21:32:23 -04:00
void CMIPSInstructionFactory::ComputeMemAccessAddrNoXlat()
{
2018-08-27 08:50:35 -04:00
uint8 nRS = (uint8)((m_nOpcode >> 21) & 0x001F);
uint16 nImmediate = (uint16)((m_nOpcode >> 0) & 0xFFFF);
2016-07-16 21:32:23 -04:00
//Push low part of address
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[nRS].nV[0]));
if(nImmediate != 0)
{
m_codeGen->PushCst((int16)nImmediate);
m_codeGen->Add();
}
}
void CMIPSInstructionFactory::ComputeMemAccessRef(uint32 accessSize)
{
ComputeMemAccessPageRef();
2018-08-27 08:50:35 -04:00
auto rs = static_cast<uint8>((m_nOpcode >> 21) & 0x001F);
auto immediate = static_cast<uint16>((m_nOpcode >> 0) & 0xFFFF);
2016-07-16 21:32:23 -04:00
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[rs].nV[0]));
m_codeGen->PushCst(static_cast<int16>(immediate));
m_codeGen->Add();
2019-04-25 17:38:49 -04:00
m_codeGen->PushCst(MIPS_PAGE_SIZE - accessSize);
2016-07-16 21:32:23 -04:00
m_codeGen->And();
m_codeGen->AddRef();
}
void CMIPSInstructionFactory::ComputeMemAccessPageRef()
{
2018-08-27 08:50:35 -04:00
auto rs = static_cast<uint8>((m_nOpcode >> 21) & 0x001F);
auto immediate = static_cast<uint16>((m_nOpcode >> 0) & 0xFFFF);
uint32 pointerMultiplyShift = __builtin_ctz(m_codeGen->GetCodeGen()->GetPointerSize());
2016-07-16 21:32:23 -04:00
m_codeGen->PushRelRef(offsetof(CMIPS, m_pageLookup));
2016-07-16 21:32:23 -04:00
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[rs].nV[0]));
m_codeGen->PushCst(static_cast<int16>(immediate));
m_codeGen->Add();
2019-04-30 12:20:41 -04:00
m_codeGen->Srl(12); //Divide by MIPS_PAGE_SIZE
m_codeGen->Shl(pointerMultiplyShift); //Multiply by sizeof(void*)
2016-07-16 21:32:23 -04:00
m_codeGen->AddRef();
m_codeGen->LoadRefFromRef();
}
void CMIPSInstructionFactory::Branch(Jitter::CONDITION condition)
{
uint16 nImmediate = (uint16)(m_nOpcode & 0xFFFF);
m_codeGen->PushCst(MIPS_INVALID_PC);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
m_codeGen->BeginIf(condition);
{
2022-10-18 20:01:36 +01:00
m_codeGen->PushRel(offsetof(CMIPS, m_State.nPC));
m_codeGen->PushCst((m_instrPosition + 4) + CMIPS::GetBranch(nImmediate));
m_codeGen->Add();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
}
m_codeGen->EndIf();
}
void CMIPSInstructionFactory::BranchLikely(Jitter::CONDITION condition)
{
uint16 nImmediate = (uint16)(m_nOpcode & 0xFFFF);
m_codeGen->PushCst(MIPS_INVALID_PC);
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
m_codeGen->BeginIf(condition);
{
2022-10-18 20:01:36 +01:00
m_codeGen->PushRel(offsetof(CMIPS, m_State.nPC));
m_codeGen->PushCst((m_instrPosition + 4) + CMIPS::GetBranch(nImmediate));
m_codeGen->Add();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
}
m_codeGen->Else();
{
m_codeGen->Goto(m_codeGen->GetFinalBlockLabel());
}
m_codeGen->EndIf();
}
void CMIPSInstructionFactory::Illegal()
{
#ifdef _DEBUG
m_codeGen->Break();
#endif
}