// 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 recJ() { // SET_FPUSTATE; u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); recompileNextInstruction(1); if (EmuConfig.Gamefixes.GoemonTlbHack) SetBranchImm(vtlb_V2P(newpc)); else SetBranchImm(newpc); }
void recJAL() { u32 newpc = (_Target_ << 2) + ( pc & 0xf0000000 ); _deleteEEreg(31, 0); if(EE_CONST_PROP) { GPR_SET_CONST(31); g_cpuConstRegs[31].UL[0] = pc + 4; g_cpuConstRegs[31].UL[1] = 0; } else { xMOV(ptr32[&cpuRegs.GPR.r[31].UL[0]], pc + 4); xMOV(ptr32[&cpuRegs.GPR.r[31].UL[1]], 0); } recompileNextInstruction(1); if (EmuConfig.Gamefixes.GoemonTlbHack) SetBranchImm(vtlb_V2P(newpc)); else SetBranchImm(newpc); }
void recJALR() { int newpc = pc + 4; _allocX86reg(esi, X86TYPE_PCWRITEBACK, 0, MODE_WRITE); _eeMoveGPRtoR(esi, _Rs_); if (EmuConfig.Gamefixes.GoemonTlbHack) { xMOV(ecx, esi); vtlb_DynV2P(); xMOV(esi, eax); } // uncomment when there are NO instructions that need to call interpreter // int mmreg; // if( GPR_IS_CONST1(_Rs_) ) // xMOV(ptr32[&cpuRegs.pc], g_cpuConstRegs[_Rs_].UL[0] ); // else { // int mmreg; // // if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rs_, MODE_READ)) >= 0 ) { // xMOVSS(ptr[&cpuRegs.pc], xRegisterSSE(mmreg)); // } // else if( (mmreg = _checkMMXreg(MMX_GPR+_Rs_, MODE_READ)) >= 0 ) { // xMOVD(ptr[&cpuRegs.pc], xRegisterMMX(mmreg)); // SetMMXstate(); // } // else { // xMOV(eax, ptr[(void*)((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] )]); // xMOV(ptr[&cpuRegs.pc], eax); // } // } if ( _Rd_ ) { _deleteEEreg(_Rd_, 0); if(EE_CONST_PROP) { GPR_SET_CONST(_Rd_); g_cpuConstRegs[_Rd_].UL[0] = newpc; g_cpuConstRegs[_Rd_].UL[1] = 0; } else { xMOV(ptr32[&cpuRegs.GPR.r[_Rd_].UL[0]], newpc); xMOV(ptr32[&cpuRegs.GPR.r[_Rd_].UL[1]], 0); } } _clearNeededMMXregs(); _clearNeededXMMregs(); recompileNextInstruction(1); if( x86regs[esi.GetId()].inuse ) { pxAssert( x86regs[esi.GetId()].type == X86TYPE_PCWRITEBACK ); xMOV(ptr[&cpuRegs.pc], esi); x86regs[esi.GetId()].inuse = 0; } else { xMOV(eax, ptr[&g_recWriteback]); xMOV(ptr[&cpuRegs.pc], eax); } SetBranchReg(0xffffffff); }