2026-01-12 05:18:12 -05:00
|
|
|
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
2024-07-30 13:42:36 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0+
|
2009-09-08 12:08:10 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
// Important Note to Future Developers:
|
|
|
|
|
// None of the COP0 instructions are really critical performance items,
|
|
|
|
|
// so don't waste time converting any more them into recompiled code
|
|
|
|
|
// unless it can make them nicely compact. Calling the C versions will
|
|
|
|
|
// suffice.
|
|
|
|
|
|
|
|
|
|
#include "Common.h"
|
|
|
|
|
#include "R5900OpcodeTables.h"
|
|
|
|
|
#include "iR5900.h"
|
|
|
|
|
#include "iCOP0.h"
|
|
|
|
|
|
|
|
|
|
namespace Interp = R5900::Interpreter::OpcodeImpl::COP0;
|
2009-10-20 20:02:07 +00:00
|
|
|
using namespace x86Emitter;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
|
namespace R5900 {
|
|
|
|
|
namespace Dynarec {
|
|
|
|
|
namespace OpcodeImpl {
|
|
|
|
|
namespace COP0 {
|
|
|
|
|
|
|
|
|
|
/*********************************************************
|
|
|
|
|
* COP0 opcodes *
|
|
|
|
|
* *
|
|
|
|
|
*********************************************************/
|
|
|
|
|
|
|
|
|
|
// emits "setup" code for a COP0 branch test. The instruction immediately following
|
|
|
|
|
// this should be a conditional Jump -- JZ or JNZ normally.
|
|
|
|
|
static void _setupBranchTest()
|
|
|
|
|
{
|
2022-10-29 13:39:19 +10:00
|
|
|
_eeFlushAllDirty();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
|
// COP0 branch conditionals are based on the following equation:
|
2009-02-15 12:31:49 +00:00
|
|
|
// (((psHu16(DMAC_STAT) | ~psHu16(DMAC_PCR)) & 0x3ff) == 0x3ff)
|
2009-02-09 21:15:56 +00:00
|
|
|
// BC0F checks if the statement is false, BC0T checks if the statement is true.
|
|
|
|
|
|
|
|
|
|
// note: We only want to compare the 16 bit values of DMAC_STAT and PCR.
|
|
|
|
|
// But using 32-bit loads here is ok (and faster), because we mask off
|
|
|
|
|
// everything except the lower 10 bits away.
|
|
|
|
|
|
2021-08-30 01:38:13 -05:00
|
|
|
xMOV(eax, ptr[(&psHu32(DMAC_PCR))]);
|
|
|
|
|
xMOV(ecx, 0x3ff); // ECX is our 10-bit mask var
|
2015-11-26 18:44:40 +01:00
|
|
|
xNOT(eax);
|
2021-08-30 01:38:13 -05:00
|
|
|
xOR(eax, ptr[(&psHu32(DMAC_STAT))]);
|
2015-11-26 18:44:40 +01:00
|
|
|
xAND(eax, ecx);
|
|
|
|
|
xCMP(eax, ecx);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recBC0F()
|
|
|
|
|
{
|
2022-10-29 13:39:19 +10:00
|
|
|
const u32 branchTo = ((s32)_Imm_ * 4) + pc;
|
2022-11-20 13:37:42 +10:00
|
|
|
const bool swap = TrySwapDelaySlot(0, 0, 0, false);
|
2009-02-09 21:15:56 +00:00
|
|
|
_setupBranchTest();
|
2022-10-29 13:39:19 +10:00
|
|
|
recDoBranchImm(branchTo, JE32(0), false, swap);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recBC0T()
|
|
|
|
|
{
|
2022-10-29 13:39:19 +10:00
|
|
|
const u32 branchTo = ((s32)_Imm_ * 4) + pc;
|
2022-11-20 13:37:42 +10:00
|
|
|
const bool swap = TrySwapDelaySlot(0, 0, 0, false);
|
2009-02-09 21:15:56 +00:00
|
|
|
_setupBranchTest();
|
2022-10-29 13:39:19 +10:00
|
|
|
recDoBranchImm(branchTo, JNE32(0), false, swap);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recBC0FL()
|
|
|
|
|
{
|
2022-10-29 13:39:19 +10:00
|
|
|
const u32 branchTo = ((s32)_Imm_ * 4) + pc;
|
2009-02-09 21:15:56 +00:00
|
|
|
_setupBranchTest();
|
2022-10-29 13:39:19 +10:00
|
|
|
recDoBranchImm(branchTo, JE32(0), true, false);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recBC0TL()
|
|
|
|
|
{
|
2022-10-29 13:39:19 +10:00
|
|
|
const u32 branchTo = ((s32)_Imm_ * 4) + pc;
|
2009-02-09 21:15:56 +00:00
|
|
|
_setupBranchTest();
|
2022-10-29 13:39:19 +10:00
|
|
|
recDoBranchImm(branchTo, JNE32(0), true, false);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 00:33:41 +00:00
|
|
|
void recTLBR() { recCall(Interp::TLBR); }
|
|
|
|
|
void recTLBP() { recCall(Interp::TLBP); }
|
|
|
|
|
void recTLBWI() { recCall(Interp::TLBWI); }
|
|
|
|
|
void recTLBWR() { recCall(Interp::TLBWR); }
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
|
void recERET()
|
|
|
|
|
{
|
2021-08-30 01:38:13 -05:00
|
|
|
recBranchCall(Interp::ERET);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recEI()
|
|
|
|
|
{
|
|
|
|
|
// must branch after enabling interrupts, so that anything
|
|
|
|
|
// pending gets triggered properly.
|
2021-08-30 01:38:13 -05:00
|
|
|
recBranchCall(Interp::EI);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recDI()
|
|
|
|
|
{
|
2009-11-10 17:28:15 +00:00
|
|
|
//// No need to branch after disabling interrupts...
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-11-10 17:28:15 +00:00
|
|
|
//iFlushCall(0);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2015-11-26 18:44:40 +01:00
|
|
|
//xMOV(eax, ptr[&cpuRegs.cycle ]);
|
|
|
|
|
//xMOV(ptr[&g_nextBranchCycle], eax);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2016-01-11 08:26:00 +01:00
|
|
|
//xFastCall((void*)(uptr)Interp::DI );
|
2009-11-10 17:28:15 +00:00
|
|
|
|
2019-12-18 22:38:36 +01:00
|
|
|
// Fixes booting issues in the following games:
|
|
|
|
|
// Jak X, Namco 50th anniversary, Spongebob the Movie, Spongebob Battle for Bikini Bottom,
|
|
|
|
|
// The Incredibles, The Incredibles rize of the underminer, Soukou kihei armodyne, Garfield Saving Arlene, Tales of Fandom Vol. 2.
|
2021-08-30 01:38:13 -05:00
|
|
|
if (!g_recompilingDelaySlot)
|
2022-10-29 13:39:19 +10:00
|
|
|
recompileNextInstruction(false, false); // DI execution is delayed by one instruction
|
2019-12-18 22:38:36 +01:00
|
|
|
|
2010-06-04 22:27:06 +00:00
|
|
|
xMOV(eax, ptr[&cpuRegs.CP0.n.Status]);
|
2009-11-10 17:28:15 +00:00
|
|
|
xTEST(eax, 0x20006); // EXL | ERL | EDI
|
|
|
|
|
xForwardJNZ8 iHaveNoIdea;
|
|
|
|
|
xTEST(eax, 0x18); // KSU
|
|
|
|
|
xForwardJNZ8 inUserMode;
|
|
|
|
|
iHaveNoIdea.SetTarget();
|
|
|
|
|
xAND(eax, ~(u32)0x10000); // EIE
|
2010-06-04 22:27:06 +00:00
|
|
|
xMOV(ptr[&cpuRegs.CP0.n.Status], eax);
|
2009-11-10 17:28:15 +00:00
|
|
|
inUserMode.SetTarget();
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef CP0_RECOMPILE
|
|
|
|
|
|
2021-08-30 01:38:13 -05:00
|
|
|
REC_SYS(MFC0);
|
|
|
|
|
REC_SYS(MTC0);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
2014-08-14 03:21:09 -04:00
|
|
|
void recMFC0()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2021-08-30 01:38:13 -05:00
|
|
|
if (_Rd_ == 9)
|
2009-03-10 19:21:54 +00:00
|
|
|
{
|
|
|
|
|
// This case needs to be handled even if the write-back is ignored (_Rt_ == 0 )
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rcx, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rcx, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
|
|
|
|
|
xMOV(rax, rcx);
|
|
|
|
|
xSUB(rax, ptr[&cpuRegs.lastCOP0Cycle]);
|
|
|
|
|
xADD(ptr[&cpuRegs.CP0.n.Count], rax);
|
|
|
|
|
xMOV(ptr[&cpuRegs.lastCOP0Cycle], rcx);
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2021-08-30 01:38:13 -05:00
|
|
|
if (!_Rt_)
|
|
|
|
|
return;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2022-10-29 13:39:19 +10:00
|
|
|
const int regt = _Rt_ ? _allocX86reg(X86TYPE_GPR, _Rt_, MODE_WRITE) : -1;
|
|
|
|
|
xMOVSX(xRegister64(regt), ptr32[&cpuRegs.CP0.r[_Rd_]]);
|
2009-02-09 21:15:56 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2021-08-30 01:38:13 -05:00
|
|
|
if (!_Rt_)
|
|
|
|
|
return;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2021-08-30 01:38:13 -05:00
|
|
|
if (_Rd_ == 25)
|
2009-03-10 19:21:54 +00:00
|
|
|
{
|
2016-06-23 20:57:43 +01:00
|
|
|
if (0 == (_Imm_ & 1)) // MFPS, register value ignored
|
2009-03-10 19:21:54 +00:00
|
|
|
{
|
2022-10-29 13:39:19 +10:00
|
|
|
const int regt = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_WRITE);
|
|
|
|
|
xMOVSX(xRegister64(regt), ptr32[&cpuRegs.PERF.n.pccr]);
|
2016-06-23 20:57:43 +01:00
|
|
|
}
|
|
|
|
|
else if (0 == (_Imm_ & 2)) // MFPC 0, only LSB of register matters
|
|
|
|
|
{
|
|
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2016-08-14 14:01:04 +02:00
|
|
|
xFastCall((void*)COP0_UpdatePCCR);
|
2022-10-29 13:39:19 +10:00
|
|
|
|
|
|
|
|
const int regt = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_WRITE);
|
|
|
|
|
xMOVSX(xRegister64(regt), ptr32[&cpuRegs.PERF.n.pcr0]);
|
2016-06-23 20:57:43 +01:00
|
|
|
}
|
|
|
|
|
else // MFPC 1
|
|
|
|
|
{
|
|
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2016-08-14 14:01:04 +02:00
|
|
|
xFastCall((void*)COP0_UpdatePCCR);
|
2022-10-29 13:39:19 +10:00
|
|
|
|
|
|
|
|
const int regt = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_WRITE);
|
|
|
|
|
xMOVSX(xRegister64(regt), ptr32[&cpuRegs.PERF.n.pcr1]);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-08-30 01:38:13 -05:00
|
|
|
else if (_Rd_ == 24)
|
|
|
|
|
{
|
2010-08-06 05:46:09 +00:00
|
|
|
COP0_LOG("MFC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF);
|
2021-08-30 01:38:13 -05:00
|
|
|
return;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2022-10-29 13:39:19 +10:00
|
|
|
|
|
|
|
|
const int regt = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_WRITE);
|
|
|
|
|
xMOVSX(xRegister64(regt), ptr32[&cpuRegs.CP0.r[_Rd_]]);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void recMTC0()
|
|
|
|
|
{
|
2021-08-30 01:38:13 -05:00
|
|
|
if (GPR_IS_CONST1(_Rt_))
|
2009-03-10 19:21:54 +00:00
|
|
|
{
|
|
|
|
|
switch (_Rd_)
|
|
|
|
|
{
|
2010-04-25 00:31:27 +00:00
|
|
|
case 12:
|
2010-07-02 22:14:35 +00:00
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2021-02-24 11:38:57 -05:00
|
|
|
xFastCall((void*)WriteCP0Status, g_cpuConstRegs[_Rt_].UL[0]);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2021-02-24 11:38:57 -05:00
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
|
|
|
|
xFastCall((void*)WriteCP0Config, g_cpuConstRegs[_Rt_].UL[0]);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
case 9:
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rcx, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rcx, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
|
|
|
|
|
xMOV(ptr64[&cpuRegs.lastCOP0Cycle], rcx);
|
2015-11-26 18:44:40 +01:00
|
|
|
xMOV(ptr32[&cpuRegs.CP0.r[9]], g_cpuConstRegs[_Rt_].UL[0]);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
case 25:
|
2016-06-23 20:57:43 +01:00
|
|
|
if (0 == (_Imm_ & 1)) // MTPS
|
2009-03-10 19:21:54 +00:00
|
|
|
{
|
2016-06-23 20:57:43 +01:00
|
|
|
if (0 != (_Imm_ & 0x3E)) // only effective when the register is 0
|
|
|
|
|
break;
|
|
|
|
|
// Updates PCRs and sets the PCCR.
|
|
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2016-08-14 14:01:04 +02:00
|
|
|
xFastCall((void*)COP0_UpdatePCCR);
|
2016-06-23 20:57:43 +01:00
|
|
|
xMOV(ptr32[&cpuRegs.PERF.n.pccr], g_cpuConstRegs[_Rt_].UL[0]);
|
2016-08-14 14:01:04 +02:00
|
|
|
xFastCall((void*)COP0_DiagnosticPCCR);
|
2016-06-23 20:57:43 +01:00
|
|
|
}
|
|
|
|
|
else if (0 == (_Imm_ & 2)) // MTPC 0, only LSB of register matters
|
|
|
|
|
{
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2016-06-23 20:57:43 +01:00
|
|
|
xMOV(ptr32[&cpuRegs.PERF.n.pcr0], g_cpuConstRegs[_Rt_].UL[0]);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(ptr64[&cpuRegs.lastPERFCycle[0]], rax);
|
2016-06-23 20:57:43 +01:00
|
|
|
}
|
|
|
|
|
else // MTPC 1
|
|
|
|
|
{
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2016-06-23 20:57:43 +01:00
|
|
|
xMOV(ptr32[&cpuRegs.PERF.n.pcr1], g_cpuConstRegs[_Rt_].UL[0]);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(ptr64[&cpuRegs.lastPERFCycle[1]], rax);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2010-04-25 00:31:27 +00:00
|
|
|
case 24:
|
2010-08-06 05:46:09 +00:00
|
|
|
COP0_LOG("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
default:
|
2015-11-26 18:44:40 +01:00
|
|
|
xMOV(ptr32[&cpuRegs.CP0.r[_Rd_]], g_cpuConstRegs[_Rt_].UL[0]);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-03-10 19:21:54 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (_Rd_)
|
|
|
|
|
{
|
2010-04-25 00:31:27 +00:00
|
|
|
case 12:
|
2022-10-29 13:39:19 +10:00
|
|
|
_eeMoveGPRtoR(arg1reg, _Rt_);
|
2010-07-02 22:14:35 +00:00
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2022-10-29 13:39:19 +10:00
|
|
|
xFastCall((void*)WriteCP0Status);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2021-02-24 11:38:57 -05:00
|
|
|
case 16:
|
2022-10-29 13:39:19 +10:00
|
|
|
_eeMoveGPRtoR(arg1reg, _Rt_);
|
2021-02-24 11:38:57 -05:00
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
2022-10-29 13:39:19 +10:00
|
|
|
xFastCall((void*)WriteCP0Config);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2021-02-24 11:38:57 -05:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
case 9:
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rcx, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rcx, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
|
2009-02-09 21:15:56 +00:00
|
|
|
_eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[9], _Rt_);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(ptr64[&cpuRegs.lastCOP0Cycle], rcx);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-03-10 19:21:54 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
case 25:
|
2016-06-23 20:57:43 +01:00
|
|
|
if (0 == (_Imm_ & 1)) // MTPS
|
2009-03-10 19:21:54 +00:00
|
|
|
{
|
2016-06-23 20:57:43 +01:00
|
|
|
if (0 != (_Imm_ & 0x3E)) // only effective when the register is 0
|
|
|
|
|
break;
|
|
|
|
|
iFlushCall(FLUSH_INTERPRETER);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rax, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rax, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
|
2016-08-14 14:01:04 +02:00
|
|
|
xFastCall((void*)COP0_UpdatePCCR);
|
2016-06-23 20:57:43 +01:00
|
|
|
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pccr, _Rt_);
|
2016-08-14 14:01:04 +02:00
|
|
|
xFastCall((void*)COP0_DiagnosticPCCR);
|
2016-06-23 20:57:43 +01:00
|
|
|
}
|
|
|
|
|
else if (0 == (_Imm_ & 2)) // MTPC 0, only LSB of register matters
|
|
|
|
|
{
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rcx, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rcx, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
|
2016-06-23 20:57:43 +01:00
|
|
|
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr0, _Rt_);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(ptr64[&cpuRegs.lastPERFCycle[0]], rcx);
|
2016-06-23 20:57:43 +01:00
|
|
|
}
|
|
|
|
|
else // MTPC 1
|
|
|
|
|
{
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(rcx, ptr64[&cpuRegs.cycle]);
|
|
|
|
|
xADD(rcx, scaleblockcycles_clear());
|
|
|
|
|
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
|
2016-06-23 20:57:43 +01:00
|
|
|
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr1, _Rt_);
|
2026-03-06 21:55:35 +01:00
|
|
|
xMOV(ptr64[&cpuRegs.lastPERFCycle[1]], rcx);
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2010-04-25 00:31:27 +00:00
|
|
|
|
|
|
|
|
case 24:
|
2010-08-06 05:46:09 +00:00
|
|
|
COP0_LOG("MTC0 Breakpoint debug Registers code = %x\n", cpuRegs.code & 0x3FF);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
default:
|
|
|
|
|
_eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[_Rd_], _Rt_);
|
2021-08-30 01:38:13 -05:00
|
|
|
break;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*void rec(COP0) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(BC0F) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(BC0T) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(BC0FL) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(BC0TL) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(TLBR) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(TLBWI) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(TLBWR) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rec(TLBP) {
|
|
|
|
|
}*/
|
|
|
|
|
|
2021-08-30 01:38:13 -05:00
|
|
|
} // namespace COP0
|
|
|
|
|
} // namespace OpcodeImpl
|
|
|
|
|
} // namespace Dynarec
|
|
|
|
|
} // namespace R5900
|