From b438fddf2ed5d35a3dc1384afa073d89a4319efb Mon Sep 17 00:00:00 2001 From: zilmar Date: Thu, 18 May 2023 18:04:41 +0930 Subject: [PATCH] Core: Add CP2 handling --- .../N64System/Interpreter/InterpreterOps.cpp | 120 ++++++++++++++++-- .../N64System/Interpreter/InterpreterOps.h | 10 ++ .../N64System/Mips/R4300iInstruction.cpp | 37 +++++- .../N64System/Mips/R4300iInstruction.h | 1 + .../N64System/Mips/R4300iOpcode.h | 10 ++ .../N64System/Mips/Register.cpp | 13 +- .../Project64-core/N64System/Mips/Register.h | 5 +- .../N64System/Mips/SystemEvents.cpp | 14 +- 8 files changed, 191 insertions(+), 19 deletions(-) diff --git a/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp b/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp index f8200aa7a..81ec96777 100644 --- a/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp +++ b/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp @@ -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() { diff --git a/Source/Project64-core/N64System/Interpreter/InterpreterOps.h b/Source/Project64-core/N64System/Interpreter/InterpreterOps.h index 47e23a5e7..8e2a03a41 100644 --- a/Source/Project64-core/N64System/Interpreter/InterpreterOps.h +++ b/Source/Project64-core/N64System/Interpreter/InterpreterOps.h @@ -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); diff --git a/Source/Project64-core/N64System/Mips/R4300iInstruction.cpp b/Source/Project64-core/N64System/Mips/R4300iInstruction.cpp index 161478ba3..05b627cbf 100644 --- a/Source/Project64-core/N64System/Mips/R4300iInstruction.cpp +++ b/Source/Project64-core/N64System/Mips/R4300iInstruction.cpp @@ -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, ""); + } +} diff --git a/Source/Project64-core/N64System/Mips/R4300iInstruction.h b/Source/Project64-core/N64System/Mips/R4300iInstruction.h index d7e546e2d..4c439430c 100644 --- a/Source/Project64-core/N64System/Mips/R4300iInstruction.h +++ b/Source/Project64-core/N64System/Mips/R4300iInstruction.h @@ -31,6 +31,7 @@ private: void DecodeSpecialName(void); void DecodeRegImmName(void); void DecodeCop1Name(void); + void DecodeCop2Name(void); uint32_t m_Address; R4300iOpcode m_Instruction; diff --git a/Source/Project64-core/N64System/Mips/R4300iOpcode.h b/Source/Project64-core/N64System/Mips/R4300iOpcode.h index f73f51c99..45ad324a5 100644 --- a/Source/Project64-core/N64System/Mips/R4300iOpcode.h +++ b/Source/Project64-core/N64System/Mips/R4300iOpcode.h @@ -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, +}; diff --git a/Source/Project64-core/N64System/Mips/Register.cpp b/Source/Project64-core/N64System/Mips/Register.cpp index 99787a6f3..9ea656044 100644 --- a/Source/Project64-core/N64System/Mips/Register.cpp +++ b/Source/Project64-core/N64System/Mips/Register.cpp @@ -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) { diff --git a/Source/Project64-core/N64System/Mips/Register.h b/Source/Project64-core/N64System/Mips/Register.h index ce71cefc9..4c1c3c5d7 100644 --- a/Source/Project64-core/N64System/Mips/Register.h +++ b/Source/Project64-core/N64System/Mips/Register.h @@ -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; diff --git a/Source/Project64-core/N64System/Mips/SystemEvents.cpp b/Source/Project64-core/N64System/Mips/SystemEvents.cpp index 51ea4e0f0..70b9ff1aa 100644 --- a/Source/Project64-core/N64System/Mips/SystemEvents.cpp +++ b/Source/Project64-core/N64System/Mips/SystemEvents.cpp @@ -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())