mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
8e18083dbf
commit
50a93750e7
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue