microVU: Finally added proper pipeline state saving/resuming on early exits. Might fix some picky vu0 games...

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2627 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2010-02-23 04:59:28 +00:00
parent 8e18083dbf
commit 50a93750e7
4 changed files with 86 additions and 86 deletions

View File

@ -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(&microVU0); }
void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(&microVU1); }
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(&microVU0);
}
}
void recMicroVU0::Reset() {
if( !pxAssertDev( m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!" ) ) return;
mVUreset(&microVU0);
}
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(&microVU0, addr, size);
}
void recMicroVU0::Vsync() throw() {
mVUvsyncUpdate(&microVU0);
}
// --------------------------------------------------------------------------------------
// 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(&microVU1);
}
}
void recMicroVU0::Reset() {
if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return;
mVUreset(&microVU0);
}
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(&microVU1);
}
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(&microVU0, addr, size);
}
void recMicroVU1::Clear(u32 addr, u32 size) {
pxAssert( m_AllocCount ); // please allocate me first! :|
pxAssert(mvu1_allocated); // please allocate me first! :|
mVUclear(&microVU1, addr, size);
}
void recMicroVU1::Vsync() throw() {
mVUvsyncUpdate(&microVU1);
}

View File

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

View File

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

View File

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