From a5afb250ea2d73357a3b5d98bfb420fe56ec1dd1 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 11 Dec 2019 21:54:08 +1000 Subject: [PATCH] CPU/Recompiler: Don't require fallback for GTE instructions --- src/core/cpu_recompiler_code_generator.cpp | 60 ++++++++++++++++++++++ src/core/cpu_recompiler_code_generator.h | 1 + src/core/cpu_recompiler_thunks.cpp | 15 ++++++ src/core/cpu_recompiler_thunks.h | 3 ++ src/core/gte_types.h | 3 ++ 5 files changed, 82 insertions(+) diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp index 473c42647..c7e235a78 100644 --- a/src/core/cpu_recompiler_code_generator.cpp +++ b/src/core/cpu_recompiler_code_generator.cpp @@ -113,6 +113,10 @@ bool CodeGenerator::CompileInstruction(const CodeBlockInstruction& cbi) result = Compile_cop0(cbi); break; + case InstructionOp::cop2: + result = Compile_cop2(cbi); + break; + case InstructionOp::funct: { switch (cbi.instruction.r.funct) @@ -1500,4 +1504,60 @@ bool CodeGenerator::Compile_cop0(const CodeBlockInstruction& cbi) } } +bool CodeGenerator::Compile_cop2(const CodeBlockInstruction& cbi) +{ + if (cbi.instruction.cop.IsCommonInstruction()) + { + switch (cbi.instruction.cop.CommonOp()) + { + case CopCommonInstruction::mfcn: + case CopCommonInstruction::cfcn: + { + const u32 reg = static_cast(cbi.instruction.r.rd.GetValue()) + + ((cbi.instruction.cop.CommonOp() == CopCommonInstruction::cfcn) ? 32 : 0); + + InstructionPrologue(cbi, 1); + + Value value = m_register_cache.AllocateScratch(RegSize_32); + EmitFunctionCallPtr(&value, &Thunks::ReadGTERegister, m_register_cache.GetCPUPtr(), + Value::FromConstantU32(reg)); + m_register_cache.WriteGuestRegisterDelayed(cbi.instruction.r.rt, std::move(value)); + + InstructionEpilogue(cbi); + return true; + } + + case CopCommonInstruction::mtcn: + case CopCommonInstruction::ctcn: + { + const u32 reg = static_cast(cbi.instruction.r.rd.GetValue()) + + ((cbi.instruction.cop.CommonOp() == CopCommonInstruction::ctcn) ? 32 : 0); + + InstructionPrologue(cbi, 1); + + Value value = m_register_cache.ReadGuestRegister(cbi.instruction.r.rt); + EmitFunctionCallPtr(nullptr, &Thunks::WriteGTERegister, m_register_cache.GetCPUPtr(), + Value::FromConstantU32(reg), value); + + InstructionEpilogue(cbi); + return true; + } + + default: + return Compile_Fallback(cbi); + } + } + else + { + // forward everything to the GTE. + InstructionPrologue(cbi, 1); + + Value instruction_bits = Value::FromConstantU32(cbi.instruction.bits & GTE::Instruction::REQUIRED_BITS_MASK); + EmitFunctionCallPtr(nullptr, &Thunks::ExecuteGTEInstruction, m_register_cache.GetCPUPtr(), instruction_bits); + + InstructionEpilogue(cbi); + return true; + } +} + } // namespace CPU::Recompiler diff --git a/src/core/cpu_recompiler_code_generator.h b/src/core/cpu_recompiler_code_generator.h index 3f489c7cf..c3b6b93fc 100644 --- a/src/core/cpu_recompiler_code_generator.h +++ b/src/core/cpu_recompiler_code_generator.h @@ -192,6 +192,7 @@ private: bool Compile_Branch(const CodeBlockInstruction& cbi); bool Compile_lui(const CodeBlockInstruction& cbi); bool Compile_cop0(const CodeBlockInstruction& cbi); + bool Compile_cop2(const CodeBlockInstruction& cbi); Core* m_cpu; JitCodeBuffer* m_code_buffer; diff --git a/src/core/cpu_recompiler_thunks.cpp b/src/core/cpu_recompiler_thunks.cpp index 398e1c6c7..9c648ae19 100644 --- a/src/core/cpu_recompiler_thunks.cpp +++ b/src/core/cpu_recompiler_thunks.cpp @@ -92,4 +92,19 @@ void Thunks::RaiseAddressException(Core* cpu, u32 address, bool store, bool bran cpu->RaiseException(store ? Exception::AdES : Exception::AdEL); } +void Thunks::ExecuteGTEInstruction(Core* cpu, u32 instruction_bits) +{ + cpu->m_cop2.ExecuteInstruction(GTE::Instruction{instruction_bits}); +} + +u32 Thunks::ReadGTERegister(Core* cpu, u32 reg) +{ + return cpu->m_cop2.ReadRegister(reg); +} + +void Thunks::WriteGTERegister(Core* cpu, u32 reg, u32 value) +{ + cpu->m_cop2.WriteRegister(reg, value); +} + } // namespace CPU::Recompiler \ No newline at end of file diff --git a/src/core/cpu_recompiler_thunks.h b/src/core/cpu_recompiler_thunks.h index 9e858ceb1..1c657618c 100644 --- a/src/core/cpu_recompiler_thunks.h +++ b/src/core/cpu_recompiler_thunks.h @@ -23,6 +23,9 @@ public: static void UpdateLoadDelay(Core* cpu); static void RaiseException(Core* cpu, u8 excode); static void RaiseAddressException(Core* cpu, u32 address, bool store, bool branch); + static void ExecuteGTEInstruction(Core* cpu, u32 instruction_bits); + static u32 ReadGTERegister(Core* cpu, u32 reg); + static void WriteGTERegister(Core* cpu, u32 reg, u32 value); }; class ASMFunctions diff --git a/src/core/gte_types.h b/src/core/gte_types.h index 7c55138d4..ffba0a642 100644 --- a/src/core/gte_types.h +++ b/src/core/gte_types.h @@ -133,6 +133,9 @@ union Instruction BitField command; ALWAYS_INLINE u8 GetShift() const { return sf ? 12 : 0; } + + // only the first 20 bits are needed to execute + static constexpr u32 REQUIRED_BITS_MASK = ((1 << 20) - 1); }; } // namespace GTE \ No newline at end of file