mirror of https://github.com/PCSX2/pcsx2.git
Implemented COP2's branching instructions in the recompiler (BC2F, BC2T, BC2FL, BC2TL), and fixed a bug where Branch-Likely instructions were not recompiled correctly for COP1 and COP0 branches.
git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@660 a6443dda-0b58-4228-96e9-037be469359c
This commit is contained in:
parent
66733f5a6d
commit
2cba5081b3
|
@ -34,45 +34,6 @@ namespace Interp = R5900::Interpreter::OpcodeImpl::COP0;
|
|||
|
||||
namespace R5900 {
|
||||
namespace Dynarec {
|
||||
|
||||
// R5900 branch hepler!
|
||||
// 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).
|
||||
static void recDoBranchImm( u32* jmpSkip, bool isLikely = false )
|
||||
{
|
||||
// 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.
|
||||
if( !isLikely ) pc -= 4; // instruction rewinde for delay slot ,if non-likely.
|
||||
LoadBranchState();
|
||||
recompileNextInstruction(1);
|
||||
|
||||
SetBranchImm(pc);
|
||||
}
|
||||
|
||||
static void recDoBranchImm_Likely( u32* jmpSkip )
|
||||
{
|
||||
recDoBranchImm( jmpSkip, true );
|
||||
}
|
||||
|
||||
namespace OpcodeImpl {
|
||||
namespace COP0 {
|
||||
|
||||
|
|
|
@ -379,10 +379,49 @@ static void recQMTC2(s32 info)
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
// BC2: Instructions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
REC_COP2_FUNC(BC2F);
|
||||
REC_COP2_FUNC(BC2T);
|
||||
REC_COP2_FUNC(BC2FL);
|
||||
REC_COP2_FUNC(BC2TL);
|
||||
//REC_COP2_FUNC(BC2F);
|
||||
//REC_COP2_FUNC(BC2T);
|
||||
//REC_COP2_FUNC(BC2FL);
|
||||
//REC_COP2_FUNC(BC2TL);
|
||||
|
||||
using namespace R5900::Dynarec;
|
||||
|
||||
static void _setupBranchTest()
|
||||
{
|
||||
_eeFlushAllUnused();
|
||||
|
||||
// COP2 branch conditionals are based on the following equation:
|
||||
// ((VU0.VI[REG_VPU_STAT].US[0] >> 8) & 1)
|
||||
// BC2F checks if the statement is false, BC2T checks if the statement is true.
|
||||
|
||||
MOV32MtoR( EAX, (uptr)&VU0.VI[REG_VPU_STAT].UL );
|
||||
TEST32ItoR( EAX, 0x100 );
|
||||
}
|
||||
|
||||
void recBC2F( s32 info )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm(JNZ32(0));
|
||||
}
|
||||
|
||||
void recBC2T( s32 info )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm(JZ32(0));
|
||||
}
|
||||
|
||||
void recBC2FL( s32 info )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm_Likely(JNZ32(0));
|
||||
}
|
||||
|
||||
void recBC2TL( s32 info )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm_Likely(JZ32(0));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Special1 instructions
|
||||
|
|
|
@ -644,87 +644,44 @@ void recADDA_S_xmm(int info)
|
|||
FPURECOMPILE_CONSTCODE(ADDA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT);
|
||||
//------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// BC1x XMM
|
||||
//------------------------------------------------------------------
|
||||
void recBC1F( void ) {
|
||||
u32 branchTo = (s32)_Imm_ * 4 + pc;
|
||||
|
||||
|
||||
static void _setupBranchTest()
|
||||
{
|
||||
_eeFlushAllUnused();
|
||||
|
||||
// COP1 branch conditionals are based on the following equation:
|
||||
// (fpuRegs.fprc[31] & 0x00800000)
|
||||
// BC2F checks if the statement is false, BC2T checks if the statement is true.
|
||||
|
||||
MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]);
|
||||
TEST32ItoR(EAX, FPUflagC);
|
||||
j32Ptr[0] = JNZ32(0);
|
||||
|
||||
SaveBranchState();
|
||||
recompileNextInstruction(1);
|
||||
SetBranchImm(branchTo);
|
||||
|
||||
x86SetJ32(j32Ptr[0]);
|
||||
|
||||
// recopy the next inst
|
||||
pc -= 4;
|
||||
LoadBranchState();
|
||||
recompileNextInstruction(1);
|
||||
|
||||
SetBranchImm(pc);
|
||||
}
|
||||
|
||||
void recBC1T( void ) {
|
||||
u32 branchTo = (s32)_Imm_ * 4 + pc;
|
||||
|
||||
_eeFlushAllUnused();
|
||||
MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]);
|
||||
TEST32ItoR(EAX, FPUflagC);
|
||||
j32Ptr[0] = JZ32(0);
|
||||
|
||||
SaveBranchState();
|
||||
recompileNextInstruction(1);
|
||||
SetBranchImm(branchTo);
|
||||
|
||||
x86SetJ32(j32Ptr[0]);
|
||||
|
||||
// recopy the next inst
|
||||
pc -= 4;
|
||||
LoadBranchState();
|
||||
recompileNextInstruction(1);
|
||||
|
||||
SetBranchImm(pc);
|
||||
void recBC1F( void )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm(JNZ32(0));
|
||||
}
|
||||
|
||||
void recBC1FL( void ) {
|
||||
u32 branchTo = _Imm_ * 4 + pc;
|
||||
|
||||
_eeFlushAllUnused();
|
||||
MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]);
|
||||
TEST32ItoR(EAX, FPUflagC);
|
||||
j32Ptr[0] = JNZ32(0);
|
||||
|
||||
SaveBranchState();
|
||||
recompileNextInstruction(1);
|
||||
SetBranchImm(branchTo);
|
||||
|
||||
x86SetJ32(j32Ptr[0]);
|
||||
|
||||
LoadBranchState();
|
||||
SetBranchImm(pc);
|
||||
void recBC1T( void )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm(JZ32(0));
|
||||
}
|
||||
|
||||
void recBC1TL( void ) {
|
||||
u32 branchTo = _Imm_ * 4 + pc;
|
||||
void recBC1FL( void )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm_Likely(JNZ32(0));
|
||||
}
|
||||
|
||||
_eeFlushAllUnused();
|
||||
MOV32MtoR(EAX, (uptr)&fpuRegs.fprc[31]);
|
||||
TEST32ItoR(EAX, FPUflagC);
|
||||
j32Ptr[0] = JZ32(0);
|
||||
|
||||
SaveBranchState();
|
||||
recompileNextInstruction(1);
|
||||
SetBranchImm(branchTo);
|
||||
x86SetJ32(j32Ptr[0]);
|
||||
|
||||
LoadBranchState();
|
||||
SetBranchImm(pc);
|
||||
void recBC1TL( void )
|
||||
{
|
||||
_setupBranchTest();
|
||||
recDoBranchImm_Likely(JZ32(0));
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -111,6 +111,11 @@ void SaveCW(int type);
|
|||
|
||||
extern void recExecute(); // same as recCpu.Execute(), but faster (can be inline'd)
|
||||
|
||||
namespace R5900{
|
||||
namespace Dynarec {
|
||||
extern void recDoBranchImm( u32* jmpSkip, bool isLikely = false );
|
||||
extern void recDoBranchImm_Likely( u32* jmpSkip );
|
||||
} }
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Constant Propagation - From here to the end of the header!
|
||||
|
|
|
@ -7,6 +7,47 @@
|
|||
|
||||
namespace R5900 {
|
||||
namespace Dynarec {
|
||||
|
||||
// R5900 branch hepler!
|
||||
// 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);
|
||||
}
|
||||
|
||||
void recDoBranchImm_Likely( u32* jmpSkip )
|
||||
{
|
||||
recDoBranchImm( jmpSkip, true );
|
||||
}
|
||||
|
||||
namespace OpcodeImpl {
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
|
|
@ -1112,8 +1112,8 @@ void SaveBranchState()
|
|||
s_saveRegHasSignExt = g_cpuRegHasSignExt;
|
||||
|
||||
// save all mmx regs
|
||||
memcpy(s_saveMMXregs, mmxregs, sizeof(mmxregs));
|
||||
memcpy(s_saveXMMregs, xmmregs, sizeof(xmmregs));
|
||||
memcpy_fast(s_saveMMXregs, mmxregs, sizeof(mmxregs));
|
||||
memcpy_fast(s_saveXMMregs, xmmregs, sizeof(xmmregs));
|
||||
}
|
||||
|
||||
void LoadBranchState()
|
||||
|
@ -1142,8 +1142,8 @@ void LoadBranchState()
|
|||
g_cpuRegHasSignExt = g_cpuPrevRegHasSignExt = s_saveRegHasSignExt;
|
||||
|
||||
// restore all mmx regs
|
||||
memcpy(mmxregs, s_saveMMXregs, sizeof(mmxregs));
|
||||
memcpy(xmmregs, s_saveXMMregs, sizeof(xmmregs));
|
||||
memcpy_fast(mmxregs, s_saveMMXregs, sizeof(mmxregs));
|
||||
memcpy_fast(xmmregs, s_saveXMMregs, sizeof(xmmregs));
|
||||
}
|
||||
|
||||
void iFlushCall(int flushtype)
|
||||
|
|
Loading…
Reference in New Issue