Files

272 lines
5.7 KiB
C++
Raw Permalink Normal View History

// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
2024-07-30 13:42:36 +02:00
// SPDX-License-Identifier: GPL-3.0+
#include "Common.h"
#include "iR5900.h"
#include "R5900OpcodeTables.h"
using namespace x86Emitter;
namespace R5900 {
namespace Dynarec {
// R5900 branch helper!
// Recompiles code for a branch test and/or skip, complete with delay slot
// handling. Note, for "likely" branches use iDoBranchImm_Likely instead, which
// handles delay slots differently.
// Parameters:
// jmpSkip - This parameter is the result of the appropriate J32 instruction
// (usually JZ32 or JNZ32).
2022-10-29 13:39:19 +10:00
void recDoBranchImm(u32 branchTo, u32* jmpSkip, bool isLikely, bool swappedDelaySlot)
{
// First up is the Branch Taken Path : Save the recompiler's state, compile the
// DelaySlot, and issue a BranchTest insertion. The state is reloaded below for
// the "did not branch" path (maintains consts, register allocations, and other optimizations).
2022-10-29 13:39:19 +10:00
if (!swappedDelaySlot)
{
SaveBranchState();
recompileNextInstruction(true, false);
}
SetBranchImm(branchTo);
// Jump target when the branch is *not* taken, skips the branchtest code
// insertion above.
x86SetJ32(jmpSkip);
// if it's a likely branch then we'll need to skip the delay slot here, since
// MIPS cancels the delay slot instruction when branches aren't taken.
2022-10-29 13:39:19 +10:00
if (!swappedDelaySlot)
{
2022-10-29 13:39:19 +10:00
LoadBranchState();
if (!isLikely)
{
pc -= 4; // instruction rewinder for delay slot, if non-likely.
recompileNextInstruction(true, false);
}
}
2022-10-29 13:39:19 +10:00
SetBranchImm(pc); // start a new recompiled block.
}
namespace OpcodeImpl {
////////////////////////////////////////////////////
//static void recCACHE() {
// xMOV(ptr32[&cpuRegs.code], cpuRegs.code );
// xMOV(ptr32[&cpuRegs.pc], pc );
// iFlushCall(FLUSH_EVERYTHING);
2016-01-11 08:26:00 +01:00
// xFastCall((void*)(uptr)CACHE );
// //branch = 2;
//
// xCMP(ptr32[(u32*)((int)&cpuRegs.pc)], pc);
// j8Ptr[0] = JE8(0);
// xRET();
// x86SetJ8(j8Ptr[0]);
//}
void recPREF()
{
}
void recSYNC()
{
}
void recMFSA()
{
2021-08-30 01:38:13 -05:00
if (!_Rd_)
return;
2022-12-29 02:14:37 +10:00
// zero-extended
if (const int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE); mmreg >= 0)
2021-08-30 01:38:13 -05:00
{
2022-12-29 02:14:37 +10:00
// have to zero out bits 63:32
const int temp = _allocTempXMMreg(XMMT_INT);
xMOVSSZX(xRegisterSSE(temp), ptr32[&cpuRegs.sa]);
2022-12-30 00:11:31 +10:00
xBLEND.PD(xRegisterSSE(mmreg), xRegisterSSE(temp), 1);
2022-12-29 02:14:37 +10:00
_freeXMMreg(temp);
}
else if (const int gprreg = _allocIfUsedGPRtoX86(_Rd_, MODE_WRITE); gprreg >= 0)
{
xMOV(xRegister32(gprreg), ptr32[&cpuRegs.sa]);
}
2021-08-30 01:38:13 -05:00
else
{
_deleteEEreg(_Rd_, 0);
2022-12-29 02:14:37 +10:00
xMOV(eax, ptr32[&cpuRegs.sa]);
2022-10-29 13:39:19 +10:00
xMOV(ptr64[&cpuRegs.GPR.r[_Rd_].UD[0]], rax);
}
}
// SA is 4-bit and contains the amount of bytes to shift
void recMTSA()
{
2021-08-30 01:38:13 -05:00
if (GPR_IS_CONST1(_Rs_))
{
xMOV(ptr32[&cpuRegs.sa], g_cpuConstRegs[_Rs_].UL[0] & 0xf);
}
2021-08-30 01:38:13 -05:00
else
{
int mmreg;
2021-08-30 01:38:13 -05:00
if ((mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0)
{
xMOVSS(ptr[&cpuRegs.sa], xRegisterSSE(mmreg));
}
2022-10-29 13:39:19 +10:00
else if ((mmreg = _checkX86reg(X86TYPE_GPR, _Rs_, MODE_READ)) >= 0)
{
xMOV(ptr[&cpuRegs.sa], xRegister32(mmreg));
}
2021-08-30 01:38:13 -05:00
else
{
xMOV(eax, ptr[&cpuRegs.GPR.r[_Rs_].UL[0]]);
xMOV(ptr[&cpuRegs.sa], eax);
}
xAND(ptr32[&cpuRegs.sa], 0xf);
}
}
void recMTSAB()
{
2021-08-30 01:38:13 -05:00
if (GPR_IS_CONST1(_Rs_))
{
xMOV(ptr32[&cpuRegs.sa], ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)));
}
2021-08-30 01:38:13 -05:00
else
{
_eeMoveGPRtoR(eax, _Rs_);
xAND(eax, 0xF);
2021-08-30 01:38:13 -05:00
xXOR(eax, _Imm_ & 0xf);
xMOV(ptr[&cpuRegs.sa], eax);
}
2021-08-30 01:38:13 -05:00
}
void recMTSAH()
{
2021-08-30 01:38:13 -05:00
if (GPR_IS_CONST1(_Rs_))
{
xMOV(ptr32[&cpuRegs.sa], ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 1);
}
2021-08-30 01:38:13 -05:00
else
{
_eeMoveGPRtoR(eax, _Rs_);
xAND(eax, 0x7);
2021-08-30 01:38:13 -05:00
xXOR(eax, _Imm_ & 0x7);
xSHL(eax, 1);
xMOV(ptr[&cpuRegs.sa], eax);
}
}
2021-08-30 01:38:13 -05:00
////////////////////////////////////////////////////
void recNULL()
{
Console.Error("EE: Unimplemented op %x", cpuRegs.code);
}
2021-08-30 01:38:13 -05:00
////////////////////////////////////////////////////
void recUnknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized op %x", cpuRegs.code);
}
2021-08-30 01:38:13 -05:00
void recMMI_Unknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized MMI op %x", cpuRegs.code);
}
2021-08-30 01:38:13 -05:00
void recCOP0_Unknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized COP0 op %x", cpuRegs.code);
}
2021-08-30 01:38:13 -05:00
void recCOP1_Unknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized FPU/COP1 op %x", cpuRegs.code);
}
2021-08-30 01:38:13 -05:00
/**********************************************************
* UNHANDLED YET OPCODES
*
**********************************************************/
2021-08-30 01:38:13 -05:00
// Suikoden 3 uses it a lot
void recCACHE() //Interpreter only!
{
//xMOV(ptr32[&cpuRegs.code], (u32)cpuRegs.code );
//xMOV(ptr32[&cpuRegs.pc], (u32)pc );
//iFlushCall(FLUSH_EVERYTHING);
//xFastCall((void*)(uptr)R5900::Interpreter::OpcodeImpl::CACHE );
//branch = 2;
}
2021-08-30 01:38:13 -05:00
void recTGE()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TGE);
}
2021-08-30 01:38:13 -05:00
void recTGEU()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TGEU);
}
2021-08-30 01:38:13 -05:00
void recTLT()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TLT);
}
2021-08-30 01:38:13 -05:00
void recTLTU()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TLTU);
}
2021-08-30 01:38:13 -05:00
void recTEQ()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TEQ);
}
2021-08-30 01:38:13 -05:00
void recTNE()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TNE);
}
2021-08-30 01:38:13 -05:00
void recTGEI()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TGEI);
}
2021-08-30 01:38:13 -05:00
void recTGEIU()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TGEIU);
}
2021-08-30 01:38:13 -05:00
void recTLTI()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TLTI);
}
2021-08-30 01:38:13 -05:00
void recTLTIU()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TLTIU);
}
2021-08-30 01:38:13 -05:00
void recTEQI()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TEQI);
}
2021-08-30 01:38:13 -05:00
void recTNEI()
{
recBranchCall(R5900::Interpreter::OpcodeImpl::TNEI);
}
2021-08-30 01:38:13 -05:00
} // namespace OpcodeImpl
} // namespace Dynarec
} // namespace R5900