Core: Add CP2 handling
This commit is contained in:
parent
3b8dfce64a
commit
b438fddf2e
|
@ -40,6 +40,7 @@ R4300iOp::Func R4300iOp::Jump_CoP1_S[64];
|
|||
R4300iOp::Func R4300iOp::Jump_CoP1_D[64];
|
||||
R4300iOp::Func R4300iOp::Jump_CoP1_W[64];
|
||||
R4300iOp::Func R4300iOp::Jump_CoP1_L[64];
|
||||
R4300iOp::Func R4300iOp::Jump_CoP2[32];
|
||||
|
||||
const uint32_t R4300iOp::SWL_MASK[4] = {0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00};
|
||||
const uint32_t R4300iOp::SWR_MASK[4] = {0x00FFFFFF, 0x0000FFFF, 0x000000FF, 0x00000000};
|
||||
|
@ -78,14 +79,7 @@ void R4300iOp::COP1()
|
|||
|
||||
void R4300iOp::COP2()
|
||||
{
|
||||
if ((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0)
|
||||
{
|
||||
g_Reg->TriggerException(EXC_CPU, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnknownOpcode();
|
||||
}
|
||||
Jump_CoP2[m_Opcode.fmt]();
|
||||
}
|
||||
|
||||
void R4300iOp::COP3()
|
||||
|
@ -707,6 +701,38 @@ R4300iOp::Func * R4300iOp::BuildInterpreter()
|
|||
Jump_CoP1_L[62] = UnknownOpcode;
|
||||
Jump_CoP1_L[63] = UnknownOpcode;
|
||||
|
||||
Jump_CoP2[0] = COP2_MF;
|
||||
Jump_CoP2[1] = COP2_DMF;
|
||||
Jump_CoP2[2] = COP2_CF;
|
||||
Jump_CoP2[3] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[4] = COP2_MT;
|
||||
Jump_CoP2[5] = COP2_DMT;
|
||||
Jump_CoP2[6] = COP2_CT;
|
||||
Jump_CoP2[7] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[8] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[10] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[11] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[12] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[13] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[14] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[15] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[16] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[17] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[18] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[19] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[20] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[21] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[22] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[23] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[24] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[25] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[26] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[27] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[28] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[29] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[30] = CPO2_INVALID_OP;
|
||||
Jump_CoP2[31] = CPO2_INVALID_OP;
|
||||
|
||||
return Jump_Opcode;
|
||||
}
|
||||
|
||||
|
@ -3030,6 +3056,84 @@ void R4300iOp::COP1_L_CVT_D()
|
|||
*(uint64_t *)_FPR_D[m_Opcode.fd] = *(uint64_t *)&Result;
|
||||
}
|
||||
|
||||
// COP2 functions
|
||||
void R4300iOp::CPO2_INVALID_OP(void)
|
||||
{
|
||||
g_Reg->TriggerException((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0 ? EXC_CPU : EXC_II, 2);
|
||||
}
|
||||
|
||||
void R4300iOp::COP2_MF()
|
||||
{
|
||||
if ((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0)
|
||||
{
|
||||
g_Reg->TriggerException(EXC_CPU, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
_GPR[m_Opcode.rt].DW = (int32_t)g_Reg->Cop2_MF(m_Opcode.rd);
|
||||
}
|
||||
}
|
||||
|
||||
void R4300iOp::COP2_DMF()
|
||||
{
|
||||
if ((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0)
|
||||
{
|
||||
g_Reg->TriggerException(EXC_CPU, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
_GPR[m_Opcode.rt].DW = g_Reg->Cop2_MF(m_Opcode.rd);
|
||||
}
|
||||
}
|
||||
|
||||
void R4300iOp::COP2_CF()
|
||||
{
|
||||
if ((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0)
|
||||
{
|
||||
g_Reg->TriggerException(EXC_CPU, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
_GPR[m_Opcode.rt].DW = (int32_t)g_Reg->Cop2_MF(m_Opcode.rd);
|
||||
}
|
||||
}
|
||||
|
||||
void R4300iOp::COP2_MT()
|
||||
{
|
||||
if ((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0)
|
||||
{
|
||||
g_Reg->TriggerException(EXC_CPU, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Reg->Cop2_MT((CRegisters::COP0Reg)m_Opcode.rd, _GPR[m_Opcode.rt].DW);
|
||||
}
|
||||
}
|
||||
|
||||
void R4300iOp::COP2_DMT()
|
||||
{
|
||||
if ((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0)
|
||||
{
|
||||
g_Reg->TriggerException(EXC_CPU, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Reg->Cop2_MT((CRegisters::COP0Reg)m_Opcode.rd, _GPR[m_Opcode.rt].DW);
|
||||
}
|
||||
}
|
||||
|
||||
void R4300iOp::COP2_CT()
|
||||
{
|
||||
if ((g_Reg->STATUS_REGISTER & STATUS_CU2) == 0)
|
||||
{
|
||||
g_Reg->TriggerException(EXC_CPU, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Reg->Cop2_MT((CRegisters::COP0Reg)m_Opcode.rd, _GPR[m_Opcode.rt].DW);
|
||||
}
|
||||
}
|
||||
|
||||
// Other functions
|
||||
void R4300iOp::ReservedInstruction()
|
||||
{
|
||||
|
|
|
@ -213,6 +213,15 @@ public:
|
|||
static void COP1_L_CVT_S();
|
||||
static void COP1_L_CVT_D();
|
||||
|
||||
// COP2 functions
|
||||
static void CPO2_INVALID_OP(void);
|
||||
static void COP2_MF();
|
||||
static void COP2_DMF();
|
||||
static void COP2_CF();
|
||||
static void COP2_MT();
|
||||
static void COP2_DMT();
|
||||
static void COP2_CT();
|
||||
|
||||
// Other functions
|
||||
static void ReservedInstruction();
|
||||
static void UnknownOpcode();
|
||||
|
@ -249,6 +258,7 @@ protected:
|
|||
static Func Jump_CoP1_D[64];
|
||||
static Func Jump_CoP1_W[64];
|
||||
static Func Jump_CoP1_L[64];
|
||||
static Func Jump_CoP2[32];
|
||||
|
||||
static void GenerateAddressErrorException(uint64_t VAddr, bool FromRead);
|
||||
static void GenerateTLBReadException(uint64_t VAddr, const char * function);
|
||||
|
|
|
@ -407,8 +407,7 @@ void R4300iInstruction::DecodeName(void)
|
|||
DecodeCop1Name();
|
||||
break;
|
||||
case R4300i_CP2:
|
||||
strcpy(m_Name, "Reserved(CP2)");
|
||||
sprintf(m_Param, "");
|
||||
DecodeCop2Name();
|
||||
break;
|
||||
case R4300i_CP3:
|
||||
strcpy(m_Name, "Reserved(CP3)");
|
||||
|
@ -1092,3 +1091,37 @@ void R4300iInstruction::DecodeCop1Name(void)
|
|||
sprintf(m_Param, "0x%08X", m_Instruction.Value);
|
||||
}
|
||||
}
|
||||
|
||||
void R4300iInstruction::DecodeCop2Name(void)
|
||||
{
|
||||
switch (m_Instruction.fmt)
|
||||
{
|
||||
case R4300i_COP2_MF:
|
||||
strcpy(m_Name, "MFC2");
|
||||
sprintf(m_Param, "%s, R%d", CRegName::GPR[m_Instruction.rt], m_Instruction.fs);
|
||||
break;
|
||||
case R4300i_COP2_DMF:
|
||||
strcpy(m_Name, "DMFC2");
|
||||
sprintf(m_Param, "%s, R%d", CRegName::GPR[m_Instruction.rt], m_Instruction.fs);
|
||||
break;
|
||||
case R4300i_COP2_CF:
|
||||
strcpy(m_Name, "CFC2");
|
||||
sprintf(m_Param, "%s, R%d", CRegName::GPR[m_Instruction.rt], m_Instruction.fs);
|
||||
break;
|
||||
case R4300i_COP2_MT:
|
||||
strcpy(m_Name, "MTC2");
|
||||
sprintf(m_Param, "%s, R%d", CRegName::GPR[m_Instruction.rt], m_Instruction.fs);
|
||||
break;
|
||||
case R4300i_COP2_DMT:
|
||||
strcpy(m_Name, "DMTC2");
|
||||
sprintf(m_Param, "%s, R%d", CRegName::GPR[m_Instruction.rt], m_Instruction.fs);
|
||||
break;
|
||||
case R4300i_COP2_CT:
|
||||
strcpy(m_Name, "CTC2");
|
||||
sprintf(m_Param, "%s, R%d", CRegName::GPR[m_Instruction.rt], m_Instruction.fs);
|
||||
break;
|
||||
default:
|
||||
strcpy(m_Name, "Reserved(CP2)");
|
||||
strcpy(m_Param, "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ private:
|
|||
void DecodeSpecialName(void);
|
||||
void DecodeRegImmName(void);
|
||||
void DecodeCop1Name(void);
|
||||
void DecodeCop2Name(void);
|
||||
|
||||
uint32_t m_Address;
|
||||
R4300iOpcode m_Instruction;
|
||||
|
|
|
@ -270,3 +270,13 @@ enum R4300iCOP1FuntOpCodes
|
|||
R4300i_COP1_FUNCT_C_LE = 62,
|
||||
R4300i_COP1_FUNCT_C_NGT = 63,
|
||||
};
|
||||
|
||||
enum R4300iCOP2OpCodes
|
||||
{
|
||||
R4300i_COP2_MF = 0,
|
||||
R4300i_COP2_DMF = 1,
|
||||
R4300i_COP2_CF = 2,
|
||||
R4300i_COP2_MT = 4,
|
||||
R4300i_COP2_DMT = 5,
|
||||
R4300i_COP2_CT = 6,
|
||||
};
|
||||
|
|
|
@ -292,6 +292,7 @@ void CRegisters::Reset()
|
|||
memset(m_FPCR, 0, sizeof(m_FPCR));
|
||||
m_FPCR[0] = 0xA00;
|
||||
m_CP0Latch = 0;
|
||||
m_CP2Latch = 0;
|
||||
m_HI.DW = 0;
|
||||
m_LO.DW = 0;
|
||||
m_RoundingModel = FE_TONEAREST;
|
||||
|
@ -488,6 +489,16 @@ void CRegisters::Cop1_CT(uint32_t Reg, uint32_t Value)
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t CRegisters::Cop2_MF(uint32_t /*Reg*/)
|
||||
{
|
||||
return m_CP2Latch;
|
||||
}
|
||||
|
||||
void CRegisters::Cop2_MT(uint32_t /*Reg*/, uint64_t Value)
|
||||
{
|
||||
m_CP2Latch = Value;
|
||||
}
|
||||
|
||||
void CRegisters::CheckInterrupts()
|
||||
{
|
||||
uint32_t mi_intr_reg = MI_INTR_REG, status_register;
|
||||
|
@ -591,7 +602,7 @@ void CRegisters::FixFpuLocations()
|
|||
}
|
||||
}
|
||||
|
||||
bool CRegisters::DoIntrException(bool DelaySlot)
|
||||
bool CRegisters::DoIntrException()
|
||||
{
|
||||
if ((STATUS_REGISTER & STATUS_IE) == 0 || (STATUS_REGISTER & STATUS_EXL) != 0 || (STATUS_REGISTER & STATUS_ERL) != 0)
|
||||
{
|
||||
|
|
|
@ -404,7 +404,7 @@ public:
|
|||
|
||||
void CheckInterrupts();
|
||||
void DoAddressError(bool DelaySlot, uint64_t BadVaddr, bool FromRead);
|
||||
bool DoIntrException(bool DelaySlot);
|
||||
bool DoIntrException();
|
||||
void DoTLBReadMiss(bool DelaySlot, uint64_t BadVaddr);
|
||||
void DoTLBWriteMiss(bool DelaySlot, uint64_t BadVaddr);
|
||||
void FixFpuLocations();
|
||||
|
@ -415,12 +415,15 @@ public:
|
|||
uint64_t Cop0_MF(COP0Reg Reg);
|
||||
void Cop0_MT(COP0Reg Reg, uint64_t Value);
|
||||
void Cop1_CT(uint32_t Reg, uint32_t Value);
|
||||
uint64_t Cop2_MF(uint32_t Reg);
|
||||
void Cop2_MT(uint32_t Reg, uint64_t Value);
|
||||
|
||||
// General registers
|
||||
uint32_t m_PROGRAM_COUNTER;
|
||||
MIPS_DWORD m_GPR[32];
|
||||
uint64_t m_CP0[32];
|
||||
uint64_t m_CP0Latch;
|
||||
uint64_t m_CP2Latch;
|
||||
MIPS_DWORD m_HI;
|
||||
MIPS_DWORD m_LO;
|
||||
uint32_t m_LLBit;
|
||||
|
|
|
@ -114,32 +114,32 @@ void CSystemEvents::ExecuteEvents()
|
|||
m_System->Reset(true, true);
|
||||
break;
|
||||
case SysEvent_ExecuteInterrupt:
|
||||
g_Reg->DoIntrException(false);
|
||||
g_Reg->DoIntrException();
|
||||
break;
|
||||
case SysEvent_Interrupt_SP:
|
||||
g_Reg->MI_INTR_REG |= MI_INTR_SP;
|
||||
g_Reg->DoIntrException(false);
|
||||
g_Reg->DoIntrException();
|
||||
break;
|
||||
case SysEvent_Interrupt_SI:
|
||||
g_Reg->MI_INTR_REG |= MI_INTR_SI;
|
||||
g_Reg->DoIntrException(false);
|
||||
g_Reg->DoIntrException();
|
||||
break;
|
||||
case SysEvent_Interrupt_AI:
|
||||
g_Reg->MI_INTR_REG |= MI_INTR_AI;
|
||||
g_Reg->DoIntrException(false);
|
||||
g_Reg->DoIntrException();
|
||||
break;
|
||||
case SysEvent_Interrupt_VI:
|
||||
g_Reg->MI_INTR_REG |= MI_INTR_VI;
|
||||
g_Reg->DoIntrException(false);
|
||||
g_Reg->DoIntrException();
|
||||
break;
|
||||
case SysEvent_Interrupt_PI:
|
||||
g_Reg->PI_STATUS_REG |= PI_STATUS_INTERRUPT;
|
||||
g_Reg->MI_INTR_REG |= MI_INTR_PI;
|
||||
g_Reg->DoIntrException(false);
|
||||
g_Reg->DoIntrException();
|
||||
break;
|
||||
case SysEvent_Interrupt_DP:
|
||||
g_Reg->MI_INTR_REG |= MI_INTR_DP;
|
||||
g_Reg->DoIntrException(false);
|
||||
g_Reg->DoIntrException();
|
||||
break;
|
||||
case SysEvent_SaveMachineState:
|
||||
if (!m_System->SaveState())
|
||||
|
|
Loading…
Reference in New Issue