2006-06-15 04:19:30 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
2006-06-26 09:31:14 +00:00
|
|
|
#include <stddef.h>
|
2006-06-15 04:19:30 +00:00
|
|
|
#include "COP_SCU.h"
|
|
|
|
#include "MIPS.h"
|
2006-06-26 09:31:14 +00:00
|
|
|
#include "CodeGen.h"
|
2007-12-07 00:26:56 +00:00
|
|
|
#include "offsetof_def.h"
|
2006-06-15 04:19:30 +00:00
|
|
|
|
|
|
|
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",
|
2009-05-30 14:10:45 +00:00
|
|
|
"CPCOND0",
|
2006-06-15 04:19:30 +00:00
|
|
|
"*RESERVED*",
|
|
|
|
"*RESERVED*",
|
|
|
|
"*RESERVED*",
|
|
|
|
"*RESERVED*",
|
|
|
|
"PErr",
|
|
|
|
"CacheErr",
|
|
|
|
"TagLo",
|
|
|
|
"TagHi",
|
|
|
|
"ErrorEPC",
|
|
|
|
"*RESERVED*"
|
|
|
|
};
|
|
|
|
|
|
|
|
CCOP_SCU::CCOP_SCU(MIPS_REGSIZE nRegSize) :
|
2009-03-30 04:57:52 +00:00
|
|
|
CMIPSCoprocessor(nRegSize),
|
|
|
|
m_nRT(0),
|
|
|
|
m_nRD(0)
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-03-30 04:57:52 +00:00
|
|
|
void CCOP_SCU::CompileInstruction(uint32 nAddress, CCodeGen* codeGen, CMIPS* pCtx)
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
2009-03-30 04:57:52 +00:00
|
|
|
SetupQuickVariables(nAddress, codeGen, pCtx);
|
2006-06-15 04:19:30 +00:00
|
|
|
|
|
|
|
m_nRT = (uint8)((m_nOpcode >> 16) & 0x1F);
|
|
|
|
m_nRD = (uint8)((m_nOpcode >> 11) & 0x1F);
|
|
|
|
|
2009-03-30 04:57:52 +00:00
|
|
|
((this)->*(m_pOpGeneral[(m_nOpcode >> 21) & 0x1F]))();
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//General Opcodes
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//00
|
|
|
|
void CCOP_SCU::MFC0()
|
|
|
|
{
|
2008-01-10 05:18:34 +00:00
|
|
|
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]));
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//04
|
|
|
|
void CCOP_SCU::MTC0()
|
|
|
|
{
|
2008-01-12 01:27:04 +00:00
|
|
|
m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
|
|
|
|
m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP0[m_nRD]));
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
2009-04-28 01:20:03 +00:00
|
|
|
//08
|
|
|
|
void CCOP_SCU::BC0()
|
|
|
|
{
|
|
|
|
((this)->*(m_pOpBC0[m_nRT]))();
|
|
|
|
}
|
|
|
|
|
2006-06-15 04:19:30 +00:00
|
|
|
//10
|
2009-04-28 01:20:03 +00:00
|
|
|
void CCOP_SCU::C0()
|
|
|
|
{
|
|
|
|
((this)->*(m_pOpC0[(m_nOpcode & 0x3F)]))();
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//Branches
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//00
|
|
|
|
void CCOP_SCU::BC0F()
|
|
|
|
{
|
2009-05-30 14:10:45 +00:00
|
|
|
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[CPCOND0]));
|
|
|
|
m_codeGen->PushCst(0);
|
|
|
|
m_codeGen->Cmp(CCodeGen::CONDITION_EQ);
|
|
|
|
Branch(true);
|
2009-04-28 01:20:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//01
|
|
|
|
void CCOP_SCU::BC0T()
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
2009-05-30 14:10:45 +00:00
|
|
|
m_codeGen->PushRel(offsetof(CMIPS, m_State.nCOP0[CPCOND0]));
|
|
|
|
m_codeGen->PushCst(0);
|
|
|
|
m_codeGen->Cmp(CCodeGen::CONDITION_EQ);
|
|
|
|
Branch(false);
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//Coprocessor Specific Opcodes
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//18
|
|
|
|
void CCOP_SCU::ERET()
|
|
|
|
{
|
2008-01-12 01:27:04 +00:00
|
|
|
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);
|
2006-06-26 09:31:14 +00:00
|
|
|
{
|
2008-01-12 01:27:04 +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]));
|
2006-06-26 09:31:14 +00:00
|
|
|
}
|
2008-01-12 01:27:04 +00:00
|
|
|
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();
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//38
|
|
|
|
void CCOP_SCU::EI()
|
|
|
|
{
|
2007-12-06 21:36:12 +00:00
|
|
|
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]));
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//39
|
|
|
|
void CCOP_SCU::DI()
|
|
|
|
{
|
2008-01-10 05:18:34 +00:00
|
|
|
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]));
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//Opcode Tables
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
2009-03-30 04:57:52 +00:00
|
|
|
CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpGeneral[0x20] =
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
|
|
|
//0x00
|
2009-03-30 04:57:52 +00:00
|
|
|
&MFC0, &Illegal, &Illegal, &Illegal, &MTC0, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x08
|
2009-04-28 01:20:03 +00:00
|
|
|
&BC0, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
|
|
|
//0x10
|
|
|
|
&C0, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
|
|
|
//0x18
|
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
|
|
|
};
|
|
|
|
|
|
|
|
CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpBC0[0x20] =
|
|
|
|
{
|
|
|
|
//0x00
|
|
|
|
&BC0F, &BC0T, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
|
|
|
//0x08
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x10
|
2009-04-28 01:20:03 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x18
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
};
|
|
|
|
|
2009-04-28 01:20:03 +00:00
|
|
|
CCOP_SCU::InstructionFuncConstant CCOP_SCU::m_pOpC0[0x40] =
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
|
|
|
//0x00
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x08
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x10
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x18
|
2009-03-30 04:57:52 +00:00
|
|
|
&ERET, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x20
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x28
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x30
|
2009-03-30 04:57:52 +00:00
|
|
|
&Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
//0x38
|
2009-03-30 04:57:52 +00:00
|
|
|
&EI, &DI, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal, &Illegal,
|
2006-06-15 04:19:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void CCOP_SCU::GetInstruction(uint32 nOpcode, char* sText)
|
|
|
|
{
|
|
|
|
switch((nOpcode >> 21) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
strcpy(sText, "MFC0");
|
|
|
|
break;
|
|
|
|
case 0x04:
|
|
|
|
strcpy(sText, "MTC0");
|
|
|
|
break;
|
2009-04-28 01:20:03 +00:00
|
|
|
case 0x08:
|
|
|
|
switch((nOpcode >> 16) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
strcpy(sText, "BC0F");
|
|
|
|
break;
|
|
|
|
case 0x01:
|
|
|
|
strcpy(sText, "BC0T");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strcpy(sText, "???");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2006-06-15 04:19:30 +00:00
|
|
|
case 0x10:
|
|
|
|
switch(nOpcode & 0x3F)
|
|
|
|
{
|
2007-01-24 03:40:35 +00:00
|
|
|
case 0x02:
|
|
|
|
strcpy(sText, "TLBWI");
|
|
|
|
break;
|
2006-06-15 04:19:30 +00:00
|
|
|
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)
|
|
|
|
{
|
2009-04-28 01:20:03 +00:00
|
|
|
uint8 nRT = static_cast<uint8>((nOpcode >> 16) & 0x1F);
|
|
|
|
uint8 nRD = static_cast<uint8>((nOpcode >> 11) & 0x1F);
|
|
|
|
uint16 nImm = static_cast<uint16>(nOpcode);
|
2006-06-15 04:19:30 +00:00
|
|
|
switch((nOpcode >> 21) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
case 0x04:
|
|
|
|
sprintf(sText, "%s, %s", CMIPS::m_sGPRName[nRT], m_sRegName[nRD]);
|
|
|
|
break;
|
2009-04-28 01:20:03 +00:00
|
|
|
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;
|
2006-06-15 04:19:30 +00:00
|
|
|
default:
|
|
|
|
strcpy(sText, "");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-28 01:20:03 +00:00
|
|
|
uint32 CCOP_SCU::GetEffectiveAddress(uint32 nAddress, uint32 nOpcode)
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
2009-04-28 01:20:03 +00:00
|
|
|
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;
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
2009-04-28 01:20:03 +00:00
|
|
|
bool CCOP_SCU::IsBranch(uint32 nOpcode)
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
2009-04-28 01:20:03 +00:00
|
|
|
if(((nOpcode >> 21) & 0x1F) == 0x08)
|
|
|
|
{
|
|
|
|
switch((nOpcode >> 16) & 0x1F)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
case 0x01:
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|