diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 4bca992f1e..53ae3b48c3 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -168,10 +168,10 @@ _f void mVUclose(mV) { // Clears Block Data in specified range _f void mVUclear(mV, u32 addr, u32 size) { - //if (!mVU->prog.cleared) { - //memset(&mVU->prog.lpState, 0, sizeof(mVU->prog.lpState)); - mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram - //} + if (!mVU->prog.cleared) { + memzero(mVU->prog.lpState); // Clear pipeline state + mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram + } } //------------------------------------------------------------------ @@ -324,108 +324,84 @@ _mVUt _f int mVUsearchProg() { return 1; // If !cleared, then we're still on the same program as last-time ;) } +//------------------------------------------------------------------ +// recMicroVU0 / recMicroVU1 +//------------------------------------------------------------------ + static u32 mvu0_allocated = 0; static u32 mvu1_allocated = 0; -// -------------------------------------------------------------------------------------- -// recMicroVU0 -// -------------------------------------------------------------------------------------- - -recMicroVU0::recMicroVU0() { - IsInterpreter = false; -} +recMicroVU0::recMicroVU0() { IsInterpreter = false; } +recMicroVU1::recMicroVU1() { IsInterpreter = false; } +void recMicroVU0::Vsync() throw() { mVUvsyncUpdate(µVU0); } +void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(µVU1); } void recMicroVU0::Allocate() { - if( m_AllocCount == 0 ) - { - ++m_AllocCount; - if( AtomicExchange( mvu0_allocated, 1 ) == 0 ) - mVUinit( &VU0, 0 ); + if(!m_AllocCount) { + m_AllocCount++; + if (AtomicExchange(mvu0_allocated, 1) == 0) + mVUinit(&VU0, 0); + } +} +void recMicroVU1::Allocate() { + if(!m_AllocCount) { + m_AllocCount++; + if (AtomicExchange(mvu1_allocated, 1) == 0) + mVUinit(&VU1, 1); } } void recMicroVU0::Shutdown() throw() { - if( m_AllocCount > 0 ) - { - --m_AllocCount; - if( AtomicExchange( mvu0_allocated, 0 ) == 1 ) + if (m_AllocCount > 0) { + m_AllocCount--; + if (AtomicExchange(mvu0_allocated, 0) == 1) mVUclose(µVU0); } } - -void recMicroVU0::Reset() { - if( !pxAssertDev( m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!" ) ) return; - mVUreset(µVU0); -} - -void recMicroVU0::ExecuteBlock() { - pxAssert( m_AllocCount ); // please allocate me first! :| - - if ((VU0.VI[REG_VPU_STAT].UL & 1) == 0) return; - - XMMRegisters::Freeze(); - // sometimes games spin on vu0, so be careful with this value - // woody hangs if too high - // Edit: Need to test this again, if anyone ever has a "Woody" game :p - ((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, 512*12); - XMMRegisters::Thaw(); -} - -void recMicroVU0::Clear(u32 addr, u32 size) { - pxAssert( mvu0_allocated ); // please allocate me first! :| - mVUclear(µVU0, addr, size); -} - -void recMicroVU0::Vsync() throw() { - mVUvsyncUpdate(µVU0); -} - -// -------------------------------------------------------------------------------------- -// recMicroVU1 -// -------------------------------------------------------------------------------------- -recMicroVU1::recMicroVU1() { - IsInterpreter = false; -} - -void recMicroVU1::Allocate() { - if( m_AllocCount == 0 ) - { - ++m_AllocCount; - if( AtomicExchange( mvu1_allocated, 1 ) == 0 ) - mVUinit( &VU1, 1 ); - } -} - void recMicroVU1::Shutdown() throw() { - if( m_AllocCount > 0 ) - { - --m_AllocCount; - if( AtomicExchange( mvu1_allocated, 0 ) == 1 ) + if (m_AllocCount > 0) { + m_AllocCount--; + if (AtomicExchange(mvu1_allocated, 0) == 1) mVUclose(µVU1); } } +void recMicroVU0::Reset() { + if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return; + mVUreset(µVU0); +} void recMicroVU1::Reset() { - if( !pxAssertDev( m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!" ) ) return; + if(!pxAssertDev(m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!")) return; mVUreset(µVU1); } -void recMicroVU1::ExecuteBlock() { - pxAssert( mvu1_allocated ); // please allocate me first! :| +void recMicroVU0::ExecuteBlock() { + pxAssert(mvu0_allocated); // please allocate me first! :| - if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0) return; - pxAssert( (VU1.VI[REG_TPC].UL&7) == 0 ); + if(!(VU0.VI[REG_VPU_STAT].UL & 1)) return; + + XMMRegisters::Freeze(); + // sometimes games spin on vu0, so be careful with this value + // woody hangs if too high on sVU (untested on mVU) + // Edit: Need to test this again, if anyone ever has a "Woody" game :p + ((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, 512*12); + XMMRegisters::Thaw(); +} +void recMicroVU1::ExecuteBlock() { + pxAssert(mvu1_allocated); // please allocate me first! :| + + if(!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return; XMMRegisters::Freeze(); ((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, 3000000); XMMRegisters::Thaw(); } +void recMicroVU0::Clear(u32 addr, u32 size) { + pxAssert(mvu0_allocated); // please allocate me first! :| + mVUclear(µVU0, addr, size); +} void recMicroVU1::Clear(u32 addr, u32 size) { - pxAssert( m_AllocCount ); // please allocate me first! :| + pxAssert(mvu1_allocated); // please allocate me first! :| mVUclear(µVU1, addr, size); } - -void recMicroVU1::Vsync() throw() { - mVUvsyncUpdate(µVU1); -} diff --git a/pcsx2/x86/microVU_Branch.inl b/pcsx2/x86/microVU_Branch.inl index c54dbdbdc1..5b65e75e81 100644 --- a/pcsx2/x86/microVU_Branch.inl +++ b/pcsx2/x86/microVU_Branch.inl @@ -15,13 +15,17 @@ #pragma once -_f void mVUincCycles(mV, int x); -_r void* mVUcompile(microVU* mVU, u32 startPC, uptr pState); +_f bool doEarlyExit (microVU* mVU); +_f void mVUincCycles(microVU* mVU, int x); +_r void* mVUcompile (microVU* mVU, u32 startPC, uptr pState); #define blockCreate(addr) { if (!mVUblocks[addr]) mVUblocks[addr] = new microBlockManager(); } #define sI ((mVUpBlock->pState.needExactMatch & 1) ? 3 : ((mVUpBlock->pState.flags >> 0) & 3)) #define cI ((mVUpBlock->pState.needExactMatch & 4) ? 3 : ((mVUpBlock->pState.flags >> 2) & 3)) +void mVU0clearlpStateJIT() { if (!microVU0.prog.cleared) memzero(microVU0.prog.lpState); } +void mVU1clearlpStateJIT() { if (!microVU1.prog.cleared) memzero(microVU1.prog.lpState); } + _f void mVUendProgram(mV, microFlagCycles* mFC, int isEbit) { int fStatus = (isEbit) ? findFlagInst(mFC->xStatus, 0x7fffffff) : sI; @@ -33,8 +37,8 @@ _f void mVUendProgram(mV, microFlagCycles* mFC, int isEbit) { if (isEbit) { mVUprint("mVUcompile ebit"); - memset(&mVUinfo, 0, sizeof(mVUinfo)); - memset(&mVUregsTemp, 0, sizeof(mVUregsTemp)); + memzero(mVUinfo); + memzero(mVUregsTemp); mVUincCycles(mVU, 100); // Ensures Valid P/Q instances (And sets all cycle data to 0) mVUcycles -= 100; qInst = mVU->q; @@ -45,6 +49,10 @@ _f void mVUendProgram(mV, microFlagCycles* mFC, int isEbit) { mVUdivSet(mVU); } if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); } + if (doEarlyExit(mVU)) { + if (!isVU1) xCALL(mVU0clearlpStateJIT); + else xCALL(mVU1clearlpStateJIT); + } } // Save P/Q Regs diff --git a/pcsx2/x86/microVU_Compile.inl b/pcsx2/x86/microVU_Compile.inl index e0025f0387..975f18d90f 100644 --- a/pcsx2/x86/microVU_Compile.inl +++ b/pcsx2/x86/microVU_Compile.inl @@ -281,17 +281,31 @@ void __fastcall mVUwarning1(mV) { Console.Error("microVU1 Warning: Exiting from void __fastcall mVUprintPC1(u32 PC) { Console.Write("Block PC [%04x] ", PC); } void __fastcall mVUprintPC2(u32 PC) { Console.Write("[%04x]\n", PC); } -_f void mVUtestCycles(mV) { +// vu0 is allowed to exit early, so are dev builds (for inf loops) +_f bool doEarlyExit(microVU* mVU) { + return IsDevBuild || !isVU1; +} + +// Saves Pipeline State for resuming from early exits +_f void mVUsavePipelineState(microVU* mVU) { + u32* lpS = (u32*)&mVU->prog.lpState.vi15; + for (int i = 0; i < (sizeof(microRegInfo)-4)/4; i++, lpS++) { + MOV32ItoM((uptr)lpS, lpS[0]); + } +} + +_f void mVUtestCycles(microVU* mVU) { //u32* vu0jmp; iPC = mVUstartPC; mVUdebugNOW(0); SUB32ItoM((uptr)&mVU->cycles, mVUcycles); - if (IsDevBuild || !isVU1) { + if (doEarlyExit(mVU)) { u32* jmp32 = JG32(0); //if (!isVU1) { TEST32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET); vu0jmp = JZ32(0); } MOV32ItoR(gprT2, (uptr)mVU); if (isVU1) CALLFunc((uptr)mVUwarning1); //else CALLFunc((uptr)mVUwarning0); // VU0 is allowed early exit for COP2 Interlock Simulation + mVUsavePipelineState(mVU); mVUendProgram(mVU, NULL, 0); //if (!isVU1) x86SetJ32(vu0jmp); x86SetJ32(jmp32); @@ -317,7 +331,10 @@ _f void mVUinitFirstPass(microVU* mVU, uptr pState, u8* thisPtr) { mVU->p = 0; // All blocks start at p index #0 mVU->q = 0; // All blocks start at q index #0 if ((uptr)&mVUregs != pState) { // Loads up Pipeline State Info - memcpy_const(&mVUregs, (microRegInfo*)pState, sizeof(microRegInfo)); + memcpy_const((u8*)&mVUregs, (u8*)pState, sizeof(microRegInfo)); + } + if (doEarlyExit(mVU) && ((uptr)&mVU->prog.lpState != pState)) { + memcpy_const((u8*)&mVU->prog.lpState, (u8*)pState, sizeof(microRegInfo)); } mVUblock.x86ptrStart = thisPtr; mVUpBlock = mVUblocks[mVUstartPC/2]->add(&mVUblock); // Add this block to block manager diff --git a/pcsx2/x86/microVU_IR.h b/pcsx2/x86/microVU_IR.h index 7f27848dbe..5b898bec13 100644 --- a/pcsx2/x86/microVU_IR.h +++ b/pcsx2/x86/microVU_IR.h @@ -27,7 +27,6 @@ union regInfo { #ifdef _MSC_VER # pragma pack(1) -# pragma warning(disable:4996) // 'function': was declared deprecated #endif struct __aligned16 microRegInfo { // Ordered for Faster Compares