Core: Add CP2 handling

This commit is contained in:
zilmar 2023-05-18 18:04:41 +09:30
parent 3b8dfce64a
commit b438fddf2e
8 changed files with 191 additions and 19 deletions

View File

@ -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()
{

View File

@ -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);

View File

@ -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, "");
}
}

View File

@ -31,6 +31,7 @@ private:
void DecodeSpecialName(void);
void DecodeRegImmName(void);
void DecodeCop1Name(void);
void DecodeCop2Name(void);
uint32_t m_Address;
R4300iOpcode m_Instruction;

View File

@ -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,
};

View File

@ -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)
{

View File

@ -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;

View File

@ -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())