Play-/Source/COP_SCU.cpp

255 lines
5.8 KiB
C++
Raw Normal View History

#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include "COP_SCU.h"
#include "MIPS.h"
#include "CodeGen.h"
#include "offsetof_def.h"
uint8 CCOP_SCU::m_nRT;
uint8 CCOP_SCU::m_nRD;
char* CCOP_SCU::m_sRegName[] =
{
"Index",
"Random",
"EntryLo0",
"EntryLo1",
"Context",
"PageMask",
"Wired",
"*RESERVED*",
"BadVAddr",
"Count",
"EntryHi",
"Compare",
"Status",
"Cause",
"EPC",
"PrevID",
"Config",
"LLAddr",
"WatchLo",
"WatchHi",
"XContext",
"*RESERVED*",
"*RESERVED*",
"*RESERVED*",
"*RESERVED*",
"*RESERVED*",
"PErr",
"CacheErr",
"TagLo",
"TagHi",
"ErrorEPC",
"*RESERVED*"
};
CCOP_SCU g_COPSCU(MIPS_REGSIZE_64);
CCOP_SCU::CCOP_SCU(MIPS_REGSIZE nRegSize) :
CMIPSCoprocessor(nRegSize)
{
}
void CCOP_SCU::CompileInstruction(uint32 nAddress, CCodeGen* codeGen, CMIPS* pCtx, bool nParent)
{
if(nParent)
{
SetupQuickVariables(nAddress, codeGen, pCtx);
}
m_nRT = (uint8)((m_nOpcode >> 16) & 0x1F);
m_nRD = (uint8)((m_nOpcode >> 11) & 0x1F);
m_pOpGeneral[(m_nOpcode >> 21) & 0x1F]();
}
//////////////////////////////////////////////////
//General Opcodes
//////////////////////////////////////////////////
//00
void CCOP_SCU::MFC0()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[m_nRD]));
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]));
}
//04
void CCOP_SCU::MTC0()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[m_nRD]));
}
//10
void CCOP_SCU::CO()
{
m_pOpCO[(m_nOpcode & 0x3F)]();
}
//////////////////////////////////////////////////
//Coprocessor Specific Opcodes
//////////////////////////////////////////////////
//18
void CCOP_SCU::ERET()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
m_codeGen->PushCst(0x04);
m_codeGen->And();
m_codeGen->PushCst(0x00);
m_codeGen->Cmp(CCodeGen::CONDITION_EQ);
m_codeGen->BeginIfElse(false);
{
//ERL bit was set
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[ERROREPC]));
// m_codeGen->PullRel(offsetof(CMIPS, m_State.nPC));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
//Clear ERL bit
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
m_codeGen->PushCst(~0x04);
m_codeGen->And();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
}
m_codeGen->BeginIfElseAlt();
{
//EXL bit wasn't set, we assume ERL was (unsafe)
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[EPC]));
// m_codeGen->PullRel(offsetof(CMIPS, m_State.nPC));
m_codeGen->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
//Clear EXL bit
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
m_codeGen->PushCst(~0x02);
m_codeGen->And();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
}
m_codeGen->EndIf();
}
//38
void CCOP_SCU::EI()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
//Should check for pending interrupts here
m_codeGen->PushCst(0x00010001);
m_codeGen->Or();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
}
//39
void CCOP_SCU::DI()
{
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
m_codeGen->PushCst(~0x00010001);
m_codeGen->And();
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[STATUS]));
}
//////////////////////////////////////////////////
//Opcode Tables
//////////////////////////////////////////////////
void (*CCOP_SCU::m_pOpGeneral[0x20])() =
{
//0x00
MFC0, Illegal, Illegal, Illegal, MTC0, Illegal, Illegal, Illegal,
//0x08
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x10
CO, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x18
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
};
void (*CCOP_SCU::m_pOpCO[0x40])() =
{
//0x00
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x08
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x10
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x18
ERET, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x20
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x28
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x30
Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
//0x38
EI, DI, Illegal, Illegal, Illegal, Illegal, Illegal, Illegal,
};
void CCOP_SCU::GetInstruction(uint32 nOpcode, char* sText)
{
switch((nOpcode >> 21) & 0x1F)
{
case 0x00:
strcpy(sText, "MFC0");
break;
case 0x04:
strcpy(sText, "MTC0");
break;
case 0x10:
switch(nOpcode & 0x3F)
{
case 0x02:
strcpy(sText, "TLBWI");
break;
case 0x18:
strcpy(sText, "ERET");
break;
case 0x38:
strcpy(sText, "EI");
break;
case 0x39:
strcpy(sText, "DI");
break;
default:
strcpy(sText, "???");
break;
}
break;
default:
strcpy(sText, "???");
break;
}
}
void CCOP_SCU::GetArguments(uint32 nAddress, uint32 nOpcode, char* sText)
{
unsigned char nRD, nRT;
nRT = (unsigned char)((nOpcode >> 16) & 0x1F);
nRD = (unsigned char)((nOpcode >> 11) & 0x1F);
switch((nOpcode >> 21) & 0x1F)
{
case 0x00:
case 0x04:
sprintf(sText, "%s, %s", CMIPS::m_sGPRName[nRT], m_sRegName[nRD]);
break;
default:
strcpy(sText, "");
break;
}
}
uint32 CCOP_SCU::GetEffectiveAddress(uint32 nAddress, uint32 nData)
{
return false;
}
bool CCOP_SCU::IsBranch(uint32 nData)
{
return 0;
}