From 2c3043862d20dd823acb35461718981bf577367c Mon Sep 17 00:00:00 2001 From: cottonvibes Date: Sat, 16 May 2009 08:43:56 +0000 Subject: [PATCH] microVU: - Cached Program search is faster/smarter thanks to an idea Jake had to search recently used blocks first. - Fixed a problem with block searching. - Minor changes. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1203 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/x86/microVU.cpp | 65 ++++++++++++++++++++--------------- pcsx2/x86/microVU.h | 15 ++++---- pcsx2/x86/microVU_Execute.inl | 2 +- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index e69f1de53c..de7a4f7ccb 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -53,7 +53,7 @@ microVUt(void) mVUinit(VURegs* vuRegsPtr) { mVUreset(); } -// Will Optimize later +// Resets Rec Data microVUt(void) mVUreset() { microVU* mVU = mVUx; @@ -86,7 +86,6 @@ microVUt(void) mVUreset() { }*/ // Program Variables - mVU->prog.finished = 1; mVU->prog.cleared = 1; mVU->prog.cur = -1; mVU->prog.total = -1; @@ -125,8 +124,10 @@ microVUt(void) mVUclose() { microVUt(void) mVUclear(u32 addr, u32 size) { microVU* mVU = mVUx; - memset(&mVU->prog.lpState, 0, sizeof(mVU->prog.lpState)); - mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram + if (!mVU->prog.cleared) { + memset(&mVU->prog.lpState, 0, sizeof(mVU->prog.lpState)); + mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram + } } //------------------------------------------------------------------ @@ -198,30 +199,36 @@ microVUt(int) mVUfindLeastUsedProg() { microVUt(void) __mVUvsyncUpdate() { microVU* mVU = mVUx; - if (mVU->prog.total < mVU->prog.max) return; for (int i = 0; i <= mVU->prog.total; i++) { - if( mVU->prog.prog[i].last_used != 0 ) - { - if( mVU->prog.prog[i].last_used >= 3 ) - { - // program has been used recently. Give it's program execution counter a - // 'weighted' bonus signifying it's importance: - if( mVU->prog.prog[i].used < 0x4fffffff ) - mVU->prog.prog[i].used += 0x200; + if (mVU->prog.prog[i].last_used != 0) { + if (mVU->prog.prog[i].last_used >= 3) { + + if (mVU->prog.prog[i].used < 0x4fffffff) // program has been used recently. Give it a + mVU->prog.prog[i].used += 0x200; // 'weighted' bonus signifying it's importance } mVU->prog.prog[i].last_used--; } - else - mVU->prog.prog[i].used /= 2; // penalize unused programs. + else mVU->prog.prog[i].used /= 2; // penalize unused programs. } } -void mVUvsyncUpdate() -{ - __mVUvsyncUpdate<0>(); - __mVUvsyncUpdate<1>(); +microVUt(int) mVUcmpProg(int progIndex, bool progUsed, bool needOverflowCheck) { + microVU* mVU = mVUx; + + if (progUsed) { + if (!memcmp_mmx(mVU->prog.prog[progIndex].data, mVU->regs->Micro, mVU->microSize)) { + mVU->prog.cur = progIndex; + mVU->prog.cleared = 0; + mVU->prog.prog[progIndex].last_used = 3; + if (!needOverflowCheck || mVU->prog.prog[progIndex].used < 0x7fffffff) { + mVU->prog.prog[progIndex].used++; // increment 'used' (avoiding overflows if necessary) + } + return 1; + } + } + return 0; } // Searches for Cached Micro Program and sets prog.cur to it (returns 1 if program found, else returns 0) @@ -230,15 +237,12 @@ microVUt(int) mVUsearchProg() { if (mVU->prog.cleared) { // If cleared, we need to search for new program for (int i = 0; i <= mVU->prog.total; i++) { - if (!memcmp_mmx(mVU->prog.prog[i].data, mVU->regs->Micro, mVU->microSize)) { - mVU->prog.cur = i; - mVU->prog.cleared = 0; - if( mVU->prog.prog[i].used < 0x7fffffff ) // avoid overflows on well-used programs - mVU->prog.prog[i].used++; - - mVU->prog.prog[i].last_used = 3; // add me to the mVU structs - return 1; - } + if (mVUcmpProg(i, !!mVU->prog.prog[i].used, 1)) + return 1; // Check Recently Used Programs + } + for (int i = 0; i <= mVU->prog.total; i++) { + if (mVUcmpProg(i, !mVU->prog.prog[i].used, 0)) + return 1; // Check Older Programs } mVU->prog.cur = mVUfindLeastUsedProg(); // If cleared and program not found, make a new program instance mVU->prog.cleared = 0; @@ -297,4 +301,9 @@ void runVUrec(u32 startPC, u32 cycles, const int vuIndex) { else startVU1(startPC, cycles); } +void mVUvsyncUpdate() { + __mVUvsyncUpdate<0>(); + __mVUvsyncUpdate<1>(); +} + #endif // PCSX2_MICROVU diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index 774469f7c1..e55571221e 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -27,7 +27,7 @@ #include "microVU_Alloc.h" #include "microVU_Misc.h" -#define mMaxBlocks 32 // Max Blocks With Different Pipeline States (For n = 1, 2, 4, 8, 16, etc...) +#define mMaxBlocks 32 // Max Blocks With Different Pipeline States class microBlockManager { private: static const int MaxBlocks = mMaxBlocks - 1; @@ -42,7 +42,7 @@ public: microBlock* thisBlock = search(&pBlock->pState); if (!thisBlock) { listSize++; - if (listSize > MaxBlocks) { Console::Error("microVU Warning: Block List Overflow"); listSize &= MaxBlocks; } + if (listSize > MaxBlocks) { Console::Error("microVU Warning: Block List Overflow"); listSize = 0; } memcpy_fast(&blockList[listSize], pBlock, sizeof(microBlock)); thisBlock = &blockList[listSize]; } @@ -57,8 +57,10 @@ public: } else { // Can do Simple Search (Only Matches the Important Pipeline Stuff) for (int i = 0; i <= listSize; i++) { - if ((blockList[i].pState.q == pState->q) && (blockList[i].pState.p == pState->p) - && (blockList[i].pState.flags == pState->flags)) { return &blockList[i]; } + if ((blockList[i].pState.q == pState->q) + && (blockList[i].pState.p == pState->p) + && (blockList[i].pState.flags == pState->flags) + && !(blockList[i].pState.needExactMatch & 0xf0f)) { return &blockList[i]; } } } return NULL; @@ -69,8 +71,9 @@ template // progSize = VU program memory size / 4 struct microProgram { u32 data[progSize]; u32 used; // Number of times its been used - u32 last_used; // counters # of frames since last use (starts at 3 and counts backwards to 0 for each 30fps vsync) + u32 last_used; // Counters # of frames since last use (starts at 3 and counts backwards to 0 for each 30fps vSync) u32 sFlagHack; // Optimize out Status Flag Updates if Program doesn't use Status Flags + s32 range[2]; // The range of microMemory that has already been recompiled for the current program u8* x86ptr; // Pointer to program's recompilation code u8* x86start; // Start of program's rec-cache u8* x86end; // Limit of program's rec-cache @@ -85,8 +88,8 @@ struct microProgManager { static const int max = mMaxProg - 1; int cur; // Index to Current MicroProgram thats running (-1 = uncached) int total; // Total Number of valid MicroPrograms minus 1 + int isSame; // Current cached microProgram is Exact Same program as mVU->regs->Micro int cleared; // Micro Program is Indeterminate so must be searched for (and if no matches are found then recompile a new one) - int finished; // Completed MicroProgram by E-bit Termination microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution) }; diff --git a/pcsx2/x86/microVU_Execute.inl b/pcsx2/x86/microVU_Execute.inl index 85285c3c6b..37dd5dbea2 100644 --- a/pcsx2/x86/microVU_Execute.inl +++ b/pcsx2/x86/microVU_Execute.inl @@ -108,7 +108,7 @@ microVUt(void) mVUdispatcherB() { if (isMMX(1)) EMMS(); RET(); - mVUcacheCheck(x86Ptr, mVU->cache, 512); + mVUcacheCheck(x86Ptr, mVU->cache, 0x1000); } //------------------------------------------------------------------