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:
Jake.Stine 2009-01-30 16:01:50 +00:00 committed by Gregory Hainaut
parent 66733f5a6d
commit 2cba5081b3
6 changed files with 118 additions and 115 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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));
}
//------------------------------------------------------------------

View File

@ -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!

View File

@ -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 {
////////////////////////////////////////////////////

View File

@ -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)