2009-09-07 19:23:46 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "COP_SCU.h"
|
|
|
|
#include "MIPS.h"
|
2010-08-11 03:47:19 +00:00
|
|
|
#include "Jitter.h"
|
2009-09-07 19:23:46 +00:00
|
|
|
#include "offsetof_def.h"
|
|
|
|
|
|
|
|
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",
|
|
|
|
"CPCOND0",
|
|
|
|
"*RESERVED*",
|
|
|
|
"*RESERVED*",
|
|
|
|
"*RESERVED*",
|
|
|
|
"*RESERVED*",
|
|
|
|
"PErr",
|
|
|
|
"CacheErr",
|
|
|
|
"TagLo",
|
|
|
|
"TagHi",
|
|
|
|
"ErrorEPC",
|
|
|
|
"*RESERVED*"
|
|
|
|
};
|
|
|
|
|
|
|
|
CCOP_SCU::CCOP_SCU(MIPS_REGSIZE nRegSize) :
|
|
|
|
CMIPSCoprocessor(nRegSize),
|
|
|
|
m_nRT(0),
|
|
|
|
m_nRD(0)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-08-11 03:47:19 +00:00
|
|
|
void CCOP_SCU::CompileInstruction(uint32 nAddress, CMipsJitter* codeGen, CMIPS* pCtx)
|
2009-09-07 19:23:46 +00:00
|
|
|
{
|
|
|
|
SetupQuickVariables(nAddress, codeGen, pCtx);
|
|
|
|
|
|
|
|
m_nRT = (uint8)((m_nOpcode >> 16) & 0x1F);
|
|
|
|
m_nRD = (uint8)((m_nOpcode >> 11) & 0x1F);
|
|
|
|
|
|
|
|
((this)->*(m_pOpGeneral[(m_nOpcode >> 21) & 0x1F]))();
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//General Opcodes
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//00
|
|
|
|
void CCOP_SCU::MFC0()
|
|
|
|
{
|
|
|
|
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[m_nRD]));
|
2010-08-11 03:47:19 +00:00
|
|
|
m_codeGen->SignExt();
|
2009-09-07 19:23:46 +00:00
|
|
|
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]));
|
|
|
|
}
|
|
|
|
|
|
|
|
//08
|
|
|
|
void CCOP_SCU::BC0()
|
|
|
|
{
|
|
|
|
((this)->*(m_pOpBC0[m_nRT]))();
|
|
|
|
}
|
|
|
|
|
|
|
|
//10
|
|
|
|
void CCOP_SCU::C0()
|
|
|
|
{
|
|
|
|
((this)->*(m_pOpC0[(m_nOpcode & 0x3F)]))();
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//Branches
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//00
|
|
|
|
void CCOP_SCU::BC0F()
|
|
|
|
{
|
|
|
|
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[CPCOND0]));
|
|
|
|
m_codeGen->PushCst(0);
|
2010-08-11 03:47:19 +00:00
|
|
|
Branch(Jitter::CONDITION_EQ);
|
2009-09-07 19:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//01
|
|
|
|
void CCOP_SCU::BC0T()
|
|
|
|
{
|
|
|
|
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[CPCOND0]));
|
|
|
|
m_codeGen->PushCst(0);
|
2010-08-11 03:47:19 +00:00
|
|
|
Branch(Jitter::CONDITION_NE);
|
2009-09-07 19:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//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);
|
2010-08-11 03:47:19 +00:00
|
|
|
m_codeGen->BeginIf(Jitter::CONDITION_EQ);
|
2009-09-07 19:23:46 +00:00
|
|
|
{
|
|
|
|
//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]));
|
|
|
|
}
|
2010-08-11 03:47:19 +00:00
|
|
|
m_codeGen->Else();
|
2009-09-07 19:23:46 +00:00
|
|
|
{
|
|
|
|
//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
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpGeneral[0x20] =
|
|
|
|
{
|
|
|
|
//0x00
|
|
|
|
&CCOP_SCU::MFC0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::MTC0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x08
|
|
|
|
&CCOP_SCU::BC0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x10
|
|
|
|
&CCOP_SCU::C0, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x18
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
};
|
|
|
|
|
|
|
|
CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpBC0[0x20] =
|
|
|
|
{
|
|
|
|
//0x00
|
|
|
|
&CCOP_SCU::BC0F, &CCOP_SCU::BC0T, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x08
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x10
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x18
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
};
|
|
|
|
|
|
|
|
CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpC0[0x40] =
|
|
|
|
{
|
|
|
|
//0x00
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x08
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x10
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x18
|
|
|
|
&CCOP_SCU::ERET, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x20
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x28
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x30
|
|
|
|
&CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal,
|
|
|
|
//0x38
|
|
|
|
&CCOP_SCU::EI, &CCOP_SCU::DI, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::Illegal, &CCOP_SCU::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 0x08:
|
|
|
|
switch((nOpcode >> 16) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
strcpy(sText, "BC0F");
|
|
|
|
break;
|
|
|
|
case 0x01:
|
|
|
|
strcpy(sText, "BC0T");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strcpy(sText, "???");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
uint8 nRT = static_cast<uint8>((nOpcode >> 16) & 0x1F);
|
|
|
|
uint8 nRD = static_cast<uint8>((nOpcode >> 11) & 0x1F);
|
|
|
|
uint16 nImm = static_cast<uint16>(nOpcode);
|
|
|
|
switch((nOpcode >> 21) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
case 0x04:
|
|
|
|
sprintf(sText, "%s, %s", CMIPS::m_sGPRName[nRT], m_sRegName[nRD]);
|
|
|
|
break;
|
|
|
|
case 0x08:
|
|
|
|
switch((nOpcode >> 16) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
case 0x01:
|
|
|
|
sprintf(sText, "0x%0.8X", nAddress + CMIPS::GetBranch(nImm) + 4);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strcpy(sText, "");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strcpy(sText, "");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CCOP_SCU::GetEffectiveAddress(uint32 nAddress, uint32 nOpcode)
|
|
|
|
{
|
|
|
|
if(((nOpcode >> 21) & 0x1F) == 0x08)
|
|
|
|
{
|
|
|
|
switch((nOpcode >> 16) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
case 0x01:
|
|
|
|
return (nAddress + CMIPS::GetBranch(static_cast<uint16>(nOpcode)) + 4);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCOP_SCU::IsBranch(uint32 nOpcode)
|
|
|
|
{
|
|
|
|
if(((nOpcode >> 21) & 0x1F) == 0x08)
|
|
|
|
{
|
|
|
|
switch((nOpcode >> 16) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
case 0x01:
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|