diff --git a/pcsx2/R5900.c b/pcsx2/R5900.c index 5444b13503..651f0546c6 100644 --- a/pcsx2/R5900.c +++ b/pcsx2/R5900.c @@ -549,6 +549,11 @@ void cpuBranchTest() // We're in a BranchTest. All dynarec registers are flushed // so there is no need to freeze registers here. Cpu->ExecuteVU0Block(); + + // This might be needed to keep the EE and VU0 in sync. + // A better fix will require hefty changes to the VU recs. -_- + if(VU0.VI[REG_VPU_STAT].UL & 0x1) + cpuSetNextBranchDelta( 768 ); } assert( !g_globalXMMSaved X86_32CODE(&& !g_globalMMXSaved) ); diff --git a/pcsx2/VU0.c b/pcsx2/VU0.c index 30bec2b8db..0254568ddc 100644 --- a/pcsx2/VU0.c +++ b/pcsx2/VU0.c @@ -406,9 +406,9 @@ void vu0Finish() void VCALLMS() { vu0Finish(); vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF) * 8); -} +} void VCALLMSR() { vu0Finish(); vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0] * 8); -} +} diff --git a/pcsx2/VU0micro.c b/pcsx2/VU0micro.c index 1f93f5f1f1..49c1c7836a 100644 --- a/pcsx2/VU0micro.c +++ b/pcsx2/VU0micro.c @@ -206,13 +206,16 @@ void vu0ExecMicro(u32 addr) { VU0.VI[REG_VPU_STAT].UL|= 0x1; VU0.VI[REG_VPU_STAT].UL&= ~0xAE; - cpuSetNextBranchDelta( 64 ); - if (addr != -1) VU0.VI[REG_TPC].UL = addr; _vuExecMicroDebug(VU0); FreezeXMMRegs(1); Cpu->ExecuteVU0Block(); FreezeXMMRegs(0); + + // If the VU0 program didn't finish then we'll want to finish it up + // pretty soon. This fixes vmhacks in some games (Naruto Ultimate Ninja 2) + if(VU0.VI[REG_VPU_STAT].UL & 0x1) + cpuSetNextBranchDelta( 128 ); } void _vu0ExecUpper(VURegs* VU, u32 *ptr) { diff --git a/pcsx2/VU1micro.c b/pcsx2/VU1micro.c index b462073328..fda56f0e9b 100644 --- a/pcsx2/VU1micro.c +++ b/pcsx2/VU1micro.c @@ -146,11 +146,9 @@ void vu1ExecMicro(u32 addr) if(VU0.VI[REG_VPU_STAT].UL & 0x100) { SysPrintf("Previous Microprogram still running on VU1\n"); - if( VU0.VI[REG_VPU_STAT].UL & 0x100 ) { - do { - Cpu->ExecuteVU1Block(); - } while(VU0.VI[REG_VPU_STAT].UL & 0x100); - } + do { + Cpu->ExecuteVU1Block(); + } while(VU0.VI[REG_VPU_STAT].UL & 0x100); } VUM_LOG("vu1ExecMicro %x\n", addr); VUM_LOG("vu1ExecMicro %x (count=%d)\n", addr, count++); @@ -161,14 +159,19 @@ void vu1ExecMicro(u32 addr) if (addr != -1) VU1.VI[REG_TPC].UL = addr; _vuExecMicroDebug(VU1); - //do { FreezeXMMRegs(1); Cpu->ExecuteVU1Block(); FreezeXMMRegs(0); //} while(VU0.VI[REG_VPU_STAT].UL & 0x100); // rec can call vu1ExecMicro - + + // VU1 isn't handled by branch tests right now, so this isn't needed. + // although maybe it should be? VU1 is updated in the intBranchTest, but not the + // recompiler one. Why? No clue. (air) + + //if( VU1.VI[REG_VPU_STAT].UL & 0x1 ) + // cpuSetNextBranchDelta( 256 ); } void _vu1ExecUpper(VURegs* VU, u32 *ptr) { diff --git a/pcsx2/x86/iCOP2.c b/pcsx2/x86/iCOP2.c index 342f35b237..6852671145 100644 --- a/pcsx2/x86/iCOP2.c +++ b/pcsx2/x86/iCOP2.c @@ -55,19 +55,21 @@ _vuopinfo g_cop2info = {0, 0, 1, 1, 1, 0, 0}; #define _Ftf_ ((cpuRegs.code >> 23) & 0x03) #define _Cc_ (cpuRegs.code & 0x03) -#define REC_COP2_FUNC(f, delreg) \ - void f(); \ - void rec##f() { \ - SysPrintf("cop2 "#f" called\n"); \ - X86_32CODE(SetFPUstate()); \ - MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ - MOV32ItoM((uptr)&cpuRegs.pc, pc); \ - iFlushCall(FLUSH_NOCONST); \ - CALLFunc((uptr)f); \ - _freeX86regs(); \ - branch = 2; \ +void recCop2BranchCall( void (*func)() ) +{ + X86_32CODE(SetFPUstate()); + recBranchCall( func ); + _freeX86regs(); } +#define REC_COP2_FUNC( f ) \ + void f(); \ + void rec##f() \ + { \ + SysPrintf("Warning > cop2 "#f" called\n"); \ + recCop2BranchCall( f ); \ + } + #define INTERPRETATE_COP2_FUNC(f) \ void recV##f() { \ MOV32ItoM((uptr)&cpuRegs.code, cpuRegs.code); \ @@ -250,9 +252,6 @@ static void recCFC2() static void recCTC2() { -#ifdef __x86_64__ - int mmreg; -#endif if (cpuRegs.code & 1) { #ifdef __x86_64__ iFlushCall(FLUSH_FREE_VU0|FLUSH_FREE_TEMPX86); @@ -289,49 +288,37 @@ static void recCTC2() assert( _checkX86reg(X86TYPE_VI, REG_VPU_STAT, 0) < 0 && _checkX86reg(X86TYPE_VI, REG_TPC, 0) < 0 ); - - // Execute VU1 Micro SubRoutine - _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 1); - _callFunctionArg1((uptr)vu1ExecMicro, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]&0xffff); - _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 0); #else iFlushCall(FLUSH_NOCONST);// since CALLFunc - assert( _checkX86reg(X86TYPE_VI, REG_VPU_STAT, 0) < 0 && _checkX86reg(X86TYPE_VI, REG_TPC, 0) < 0 ); - +#endif // Execute VU1 Micro SubRoutine _callFunctionArg1((uptr)vu1ExecMicro, MEM_CONSTTAG, g_cpuConstRegs[_Rt_].UL[0]&0xffff); -#endif break; default: + { if( _Fs_ < 16 ) assert( (g_cpuConstRegs[_Rt_].UL[0]&0xffff0000)==0); -#ifdef __x86_64__ - mmreg = _checkX86reg(X86TYPE_VI, _Fs_, MODE_WRITE); - - if( mmreg >= 0 ) MOV32ItoR(mmreg, g_cpuConstRegs[_Rt_].UL[0]); - - // a lot of games have vu0 spinning on some integer - // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) - iFlushCall(FLUSH_FREE_TEMPX86|FLUSH_FREE_VU0); - - _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 1); - CALLFunc((uptr)Cpu->ExecuteVU0Block); - _callFunctionArg1((uptr)FreezeXMMRegs_, MEM_CONSTTAG, 0); -#else - MOV32ItoM((uptr)&VU0.VI[_Fs_].UL,g_cpuConstRegs[_Rt_].UL[0]); - - // fixme: this code should issue a BranchTest instead of calling the VU0Block directly. - // It would be a lot safter and would get rid of the 64 bit mess above too. // a lot of games have vu0 spinning on some integer // then they modify the register and expect vu0 to stop spinning within 10 cycles (donald duck) + +#ifdef __x86_64__ + int mmreg = _checkX86reg(X86TYPE_VI, _Fs_, MODE_WRITE); + if( mmreg >= 0 ) MOV32ItoR(mmreg, g_cpuConstRegs[_Rt_].UL[0]); + iFlushCall(FLUSH_FREE_TEMPX86|FLUSH_FREE_VU0); +#else + MOV32ItoM((uptr)&VU0.VI[_Fs_].UL,g_cpuConstRegs[_Rt_].UL[0]); iFlushCall(FLUSH_NOCONST); - CALLFunc((uptr)Cpu->ExecuteVU0Block); - //SysPrintf( "Recompiler Warning > Unstable VU0 opcode used." ); #endif + CALLFunc((uptr)Cpu->ExecuteVU0Block); + + // fixme: if the VU0 stat&1 is still enabled, then we should probably set a cpuBranchTest + // for 128 cycles from now. It would be the safest thing to do to make sure the VU0 + // responds in a timely matter to the game's register write. break; + } } } else @@ -613,10 +600,10 @@ void _cop2AnalyzeOp(EEINST* pinst, int dostalls) ////////////////////////////////////////////////////////////////////////// // BC2: Instructions ////////////////////////////////////////////////////////////////////////// -REC_COP2_FUNC(BC2F, 0); -REC_COP2_FUNC(BC2T, 0); -REC_COP2_FUNC(BC2FL, 0); -REC_COP2_FUNC(BC2TL, 0); +REC_COP2_FUNC(BC2F); +REC_COP2_FUNC(BC2T); +REC_COP2_FUNC(BC2FL); +REC_COP2_FUNC(BC2TL); ////////////////////////////////////////////////////////////////////////// // Special1 instructions