From c660f85320ef78d1cdab9b660e25b7f0f5146eb8 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 6 Jun 2026 16:14:09 +1000 Subject: [PATCH] CPU: Use table lookup for mfc0 --- src/core/cpu_core.cpp | 116 +++++++++++++++++++----------------- src/core/cpu_core_private.h | 3 + src/core/cpu_recompiler.cpp | 28 --------- src/core/cpu_recompiler.h | 3 - 4 files changed, 65 insertions(+), 85 deletions(-) diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index 7b1dd098a..8bc295c6e 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -590,6 +590,55 @@ ALWAYS_INLINE_RELEASE void CPU::Cop0DataBreakpointCheck(VirtualMemoryAddress add DispatchCop0Breakpoint(true); } +namespace CPU { +static constexpr const std::array, 32> s_cop0_table = {{ + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {&g_state.cop0_regs.BPC, 0xffffffffu}, + {nullptr, 0}, + {&g_state.cop0_regs.BDA, 0xffffffffu}, + {&g_state.cop0_regs.TAR, 0x00000000u}, + {&g_state.cop0_regs.dcic.bits, Cop0Registers::DCIC::WRITE_MASK}, + {&g_state.cop0_regs.BadVaddr, 0x00000000u}, + {&g_state.cop0_regs.BDAM, 0xffffffffu}, + {nullptr, 0x00000000u}, + {&g_state.cop0_regs.BPCM, 0xffffffffu}, + {&g_state.cop0_regs.sr.bits, Cop0Registers::SR::WRITE_MASK}, + {&g_state.cop0_regs.cause.bits, Cop0Registers::CAUSE::WRITE_MASK}, + {&g_state.cop0_regs.EPC, 0x00000000u}, + {&g_state.cop0_regs.PRID, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, + {nullptr, 0x00000000u}, +}}; +} // namespace CPU + +u32* CPU::GetCop0RegPtr(Cop0Reg reg) +{ + DebugAssert(static_cast(reg) < std::size(s_cop0_table)); + return s_cop0_table[static_cast(reg)].first; +} + +u32 CPU::GetCop0RegWriteMask(Cop0Reg reg) +{ + DebugAssert(static_cast(reg) < std::size(s_cop0_table)); + return s_cop0_table[static_cast(reg)].second; +} + #ifdef _DEBUG void CPU::TracePrintInstruction() @@ -1723,63 +1772,18 @@ restart_instruction: { case CopCommonInstruction::mfcn: { - u32 value; - - switch (static_cast(inst.r.rd.GetValue())) + if (const u32* value = GetCop0RegPtr(static_cast(inst.r.rd.GetValue()))) [[likely]] { - case Cop0Reg::BPC: - value = g_state.cop0_regs.BPC; - break; - - case Cop0Reg::BPCM: - value = g_state.cop0_regs.BPCM; - break; + WriteRegDelayed(inst.r.rt, *value); - case Cop0Reg::BDA: - value = g_state.cop0_regs.BDA; - break; - - case Cop0Reg::BDAM: - value = g_state.cop0_regs.BDAM; - break; - - case Cop0Reg::DCIC: - value = g_state.cop0_regs.dcic.bits; - break; - - case Cop0Reg::JUMPDEST: - value = g_state.cop0_regs.TAR; - break; - - case Cop0Reg::BadVaddr: - value = g_state.cop0_regs.BadVaddr; - break; - - case Cop0Reg::SR: - value = g_state.cop0_regs.sr.bits; - break; - - case Cop0Reg::CAUSE: - value = g_state.cop0_regs.cause.bits; - break; - - case Cop0Reg::EPC: - value = g_state.cop0_regs.EPC; - break; - - case Cop0Reg::PRID: - value = g_state.cop0_regs.PRID; - break; - - default: - RaiseException(Exception::RI); - return; + if constexpr (pgxp_mode == PGXPMode::CPU) + PGXP::CPU_MFC0(inst, *value); + } + else + { + RaiseException(Exception::RI); + return; } - - WriteRegDelayed(inst.r.rt, value); - - if constexpr (pgxp_mode == PGXPMode::CPU) - PGXP::CPU_MFC0(inst, value); } break; @@ -2103,6 +2107,10 @@ restart_instruction: } } +#undef END_INSTRUCTION +#undef BEGIN_FUNCT_INSTRUCTION +#undef BEGIN_INSTRUCTION + void CPU::DispatchInterrupt() { // The GTE is a co-processor, therefore it executes the instruction even if we're servicing an exception. diff --git a/src/core/cpu_core_private.h b/src/core/cpu_core_private.h index 1b094f95d..19613e9f2 100644 --- a/src/core/cpu_core_private.h +++ b/src/core/cpu_core_private.h @@ -24,6 +24,9 @@ void RaiseException(Exception excode); void RaiseException(u32 CAUSE_bits, u32 EPC); void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits); +u32* GetCop0RegPtr(Cop0Reg reg); +u32 GetCop0RegWriteMask(Cop0Reg reg); + ALWAYS_INLINE bool HasPendingInterrupt() { return g_state.cop0_regs.sr.IEc && diff --git a/src/core/cpu_recompiler.cpp b/src/core/cpu_recompiler.cpp index 34e7a459c..885cf9964 100644 --- a/src/core/cpu_recompiler.cpp +++ b/src/core/cpu_recompiler.cpp @@ -2183,34 +2183,6 @@ void CPU::Recompiler::Recompiler::Compile_lui() GeneratePGXPCallWithMIPSRegs(reinterpret_cast(&PGXP::CPU_LUI), inst->bits); } -static constexpr const std::array, 16> s_cop0_table = { - {{nullptr, 0x00000000u}, - {nullptr, 0x00000000u}, - {nullptr, 0x00000000u}, - {&CPU::g_state.cop0_regs.BPC, 0xffffffffu}, - {nullptr, 0}, - {&CPU::g_state.cop0_regs.BDA, 0xffffffffu}, - {&CPU::g_state.cop0_regs.TAR, 0x00000000u}, - {&CPU::g_state.cop0_regs.dcic.bits, CPU::Cop0Registers::DCIC::WRITE_MASK}, - {&CPU::g_state.cop0_regs.BadVaddr, 0x00000000u}, - {&CPU::g_state.cop0_regs.BDAM, 0xffffffffu}, - {nullptr, 0x00000000u}, - {&CPU::g_state.cop0_regs.BPCM, 0xffffffffu}, - {&CPU::g_state.cop0_regs.sr.bits, CPU::Cop0Registers::SR::WRITE_MASK}, - {&CPU::g_state.cop0_regs.cause.bits, CPU::Cop0Registers::CAUSE::WRITE_MASK}, - {&CPU::g_state.cop0_regs.EPC, 0x00000000u}, - {&CPU::g_state.cop0_regs.PRID, 0x00000000u}}}; - -u32* CPU::Recompiler::Recompiler::GetCop0RegPtr(Cop0Reg reg) -{ - return (static_cast(reg) < s_cop0_table.size()) ? s_cop0_table[static_cast(reg)].first : nullptr; -} - -u32 CPU::Recompiler::Recompiler::GetCop0RegWriteMask(Cop0Reg reg) -{ - return (static_cast(reg) < s_cop0_table.size()) ? s_cop0_table[static_cast(reg)].second : 0; -} - void CPU::Recompiler::Recompiler::Compile_mfc0(CompileFlags cf) { const Cop0Reg r = static_cast(MipsD()); diff --git a/src/core/cpu_recompiler.h b/src/core/cpu_recompiler.h index d4ba438b8..b832baaf5 100644 --- a/src/core/cpu_recompiler.h +++ b/src/core/cpu_recompiler.h @@ -443,9 +443,6 @@ protected: virtual void Compile_swc2(CompileFlags cf, MemoryAccessSize size, bool sign, bool use_fastmem, const std::optional& address) = 0; - static u32* GetCop0RegPtr(Cop0Reg reg); - static u32 GetCop0RegWriteMask(Cop0Reg reg); - static void MIPSSignedDivide(s32 num, s32 denom, u32* lo, u32* hi); static void MIPSUnsignedDivide(u32 num, u32 denom, u32* lo, u32* hi);