pcsx2/pcsx2/x86/iR5900Misc.cpp

270 lines
6.3 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Common.h"
#include "iR5900.h"
#include "R5900OpcodeTables.h"
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).
void recDoBranchImm( u32* jmpSkip, bool isLikely )
{
// All R5900 branches use this format:
const u32 branchTo = ((s32)_Imm_ * 4) + pc;
// 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).
SaveBranchState();
recompileNextInstruction(1);
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.
LoadBranchState();
if( !isLikely )
{
pc -= 4; // instruction rewinder for delay slot, if non-likely.
recompileNextInstruction(1);
}
SetBranchImm(pc); // start a new recompiled block.
}
void recDoBranchImm_Likely( u32* jmpSkip )
{
recDoBranchImm( jmpSkip, true );
}
namespace OpcodeImpl {
////////////////////////////////////////////////////
//static void recCACHE() {
// MOV32ItoM( (uptr)&cpuRegs.code, cpuRegs.code );
// MOV32ItoM( (uptr)&cpuRegs.pc, pc );
// iFlushCall(FLUSH_EVERYTHING);
// CALLFunc( (uptr)CACHE );
// //branch = 2;
//
// CMP32ItoM((int)&cpuRegs.pc, pc);
// j8Ptr[0] = JE8(0);
// RET();
// x86SetJ8(j8Ptr[0]);
//}
void recPREF()
{
}
void recSYNC()
{
}
void recMFSA()
{
int mmreg;
if (!_Rd_) return;
mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rd_, MODE_WRITE);
if( mmreg >= 0 ) {
SSE_MOVLPS_M64_to_XMM(mmreg, (uptr)&cpuRegs.sa);
}
else if( (mmreg = _checkMMXreg(MMX_GPR+_Rd_, MODE_WRITE)) >= 0 ) {
MOVDMtoMMX(mmreg, (uptr)&cpuRegs.sa);
SetMMXstate();
}
else {
MOV32MtoR(EAX, (uptr)&cpuRegs.sa);
_deleteEEreg(_Rd_, 0);
MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[0], EAX);
MOV32ItoM((uptr)&cpuRegs.GPR.r[_Rd_].UL[1], 0);
}
}
// SA is 4-bit and contains the amount of bytes to shift
void recMTSA()
{
if( GPR_IS_CONST1(_Rs_) ) {
MOV32ItoM((uptr)&cpuRegs.sa, g_cpuConstRegs[_Rs_].UL[0] & 0xf );
}
else {
int mmreg;
if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) {
SSE_MOVSS_XMM_to_M32((uptr)&cpuRegs.sa, mmreg);
}
else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) {
MOVDMMXtoM((uptr)&cpuRegs.sa, mmreg);
SetMMXstate();
}
else {
MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]);
MOV32RtoM((uptr)&cpuRegs.sa, EAX);
}
AND32ItoM((uptr)&cpuRegs.sa, 0xf);
}
}
void recMTSAB()
{
if( GPR_IS_CONST1(_Rs_) ) {
MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) );
}
else {
_eeMoveGPRtoR(EAX, _Rs_);
AND32ItoR(EAX, 0xF);
XOR32ItoR(EAX, _Imm_&0xf);
MOV32RtoM((uptr)&cpuRegs.sa, EAX);
}
}
void recMTSAH()
{
if( GPR_IS_CONST1(_Rs_) ) {
MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 1);
}
else {
_eeMoveGPRtoR(EAX, _Rs_);
AND32ItoR(EAX, 0x7);
XOR32ItoR(EAX, _Imm_&0x7);
SHL32ItoR(EAX, 1);
MOV32RtoM((uptr)&cpuRegs.sa, EAX);
}
}
////////////////////////////////////////////////////
void recNULL()
{
Console.Error("EE: Unimplemented op %x", cpuRegs.code);
}
////////////////////////////////////////////////////
void recUnknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized op %x", cpuRegs.code);
}
void recMMI_Unknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized MMI op %x", cpuRegs.code);
}
void recCOP0_Unknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized COP0 op %x", cpuRegs.code);
}
void recCOP1_Unknown()
{
// TODO : Unknown ops should throw an exception.
Console.Error("EE: Unrecognized FPU/COP1 op %x", cpuRegs.code);
}
/**********************************************************
* UNHANDLED YET OPCODES
*
**********************************************************/
// Suikoden 3 uses it a lot
void recCACHE() //Interpreter only!
{
//MOV32ItoM( (uptr)&cpuRegs.code, (u32)cpuRegs.code );
//MOV32ItoM( (uptr)&cpuRegs.pc, (u32)pc );
//iFlushCall(FLUSH_EVERYTHING);
//CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::CACHE );
//branch = 2;
}
void recTGE()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TGE );
}
void recTGEU()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TGEU );
}
void recTLT()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TLT );
}
void recTLTU()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TLTU );
}
void recTEQ()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TEQ );
}
void recTNE()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TNE );
}
void recTGEI()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TGEI );
}
void recTGEIU()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TGEIU );
}
void recTLTI()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TLTI );
}
void recTLTIU()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TLTIU );
}
void recTEQI()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TEQI );
}
void recTNEI()
{
recBranchCall( R5900::Interpreter::OpcodeImpl::TNEI );
}
} }} // end Namespace R5900::Dynarec::OpcodeImpl