diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index f46d5d3a6c..59a0ea433d 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -90,8 +90,11 @@ microVUt(void) mVUreset(mV) { mVU->prog.prog[i].x86ptr = z; z += (mVU->cacheSize / (mVU->prog.max + 1)); mVU->prog.prog[i].x86end = z; - mVU->prog.prog[i].range[0] = -1; // Set range to - mVU->prog.prog[i].range[1] = -1; // indeterminable status + for (int j = 0; j <= mVU->prog.prog[i].ranges.max; j++) { + mVU->prog.prog[i].ranges.range[j][0] = -1; // Set range to + mVU->prog.prog[i].ranges.range[j][1] = -1; // indeterminable status + mVU->prog.prog[i].ranges.total = -1; + } } } @@ -128,14 +131,16 @@ microVUt(void) mVUclear(mV, u32 addr, u32 size) { // Clears program data (Sets used to 1 because calling this function implies the program will be used at least once) microVUf(void) mVUclearProg(int progIndex) { microVU* mVU = mVUx; - mVU->prog.prog[progIndex].used = 1; - mVU->prog.prog[progIndex].last_used = 3; - mVU->prog.prog[progIndex].range[0] = -1; - mVU->prog.prog[progIndex].range[1] = -1; - mVU->prog.prog[progIndex].x86ptr = mVU->prog.prog[progIndex].x86start; + mVUprogI.used = 1; + mVUprogI.last_used = 3; + mVUprogI.x86ptr = mVUprogI.x86start; + for (int j = 0; j <= mVUprogI.ranges.max; j++) { + mVUprogI.ranges.range[j][0] = -1; // Set range to + mVUprogI.ranges.range[j][1] = -1; // indeterminable status + mVUprogI.ranges.total = -1; + } for (u32 i = 0; i < (mVU->progSize / 2); i++) { - if (mVU->prog.prog[progIndex].block[i]) - mVU->prog.prog[progIndex].block[i]->reset(); + if (mVUprogI.block[i]) mVUprogI.block[i]->reset(); } } @@ -161,7 +166,7 @@ microVUf(int) mVUfindLeastUsedProg() { const int pMax = mVU->prog.max; int smallidx = (mVU->prog.cur+1)&pMax; - u32 smallval = mVU->prog.prog[smallidx].used; + u64 smallval = mVU->prog.prog[smallidx].used; for (int i = 1, j = (smallidx+1)&pMax; i <= pMax; i++, j=(j+1)&pMax) { if (smallval > mVU->prog.prog[j].used) { @@ -192,9 +197,7 @@ microVUt(void) mVUvsyncUpdate(mV) { for (int i = 0; i <= mVU->prog.max; i++) { 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].used += 0x200; // give 'weighted' bonus } mVU->prog.prog[i].last_used--; } @@ -202,20 +205,27 @@ microVUt(void) mVUvsyncUpdate(mV) { } } -// Compare Cached microProgram to mVU->regs->Micro -microVUf(int) mVUcmpProg(int progIndex, bool progUsed, bool needOverflowCheck, bool cmpWholeProg) { +microVUf(bool) mVUcmpPartial(int progIndex) { + microVU* mVU = mVUx; + for (int i = 0; i <= mVUprogI.ranges.total; i++) { + if (memcmp_mmx(cmpOffset(mVUprogI.data), cmpOffset(mVU->regs->Micro), ((mVUprogI.ranges.range[i][1] + 8) - mVUprogI.ranges.range[i][0]))) { + return 0; + } + } + return 1; +} + +// Compare Cached microProgram to mVU->regs->Micro +microVUf(bool) mVUcmpProg(int progIndex, bool progUsed, const bool cmpWholeProg) { microVU* mVU = mVUx; - if (progUsed) { - if (cmpWholeProg && (!memcmp_mmx((u8*)mVUprogI.data, mVU->regs->Micro, mVU->microMemSize)) || - (!cmpWholeProg && (!memcmp_mmx(cmpOffset(mVUprogI.data), cmpOffset(mVU->regs->Micro), ((mVUprogI.range[1] + 8) - mVUprogI.range[0]))))) { + if (cmpWholeProg && (!memcmp_mmx((u8*)mVUprogI.data, mVU->regs->Micro, mVU->microMemSize)) + ||(!cmpWholeProg && mVUcmpPartial(progIndex))) { mVU->prog.cur = progIndex; mVU->prog.cleared = 0; mVU->prog.isSame = cmpWholeProg ? 1 : -1; 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) - } + mVU->prog.prog[progIndex].used++; // increment 'used' return 1; } } @@ -228,11 +238,11 @@ microVUf(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 (mVUcmpProg(i, !!mVU->prog.prog[i].used, 1, 0)) + if (mVUcmpProg(i, !!mVU->prog.prog[i].used, 0)) return 1; // Check Recently Used Programs } for (int i = 0; i <= mVU->prog.total; i++) { - if (mVUcmpProg(i, !mVU->prog.prog[i].used, 0, 0)) + 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 diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index 100dbfd7b6..3bd48c21b6 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -84,14 +84,21 @@ public: } }; +#define mMaxRanges 128 +struct microRange { + static const int max = mMaxRanges - 1; + int total; + s32 range[mMaxRanges][2]; +}; + #define mProgSize 0x4000/4 struct microProgram { - u32 data [mProgSize]; - microBlockManager* block[mProgSize/2]; - microIR allocInfo; - u32 used; // Number of times its been used + u32 data [mProgSize]; // Holds a copy of the VU microProgram + microBlockManager* block[mProgSize/2]; // Array of Block Managers + microIR allocInfo; // IR information + microRange ranges; // The ranges of the microProgram that have already been recompiled + u64 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) - 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 diff --git a/pcsx2/x86/microVU_Compile.inl b/pcsx2/x86/microVU_Compile.inl index a67fb55217..b05ddbd5bf 100644 --- a/pcsx2/x86/microVU_Compile.inl +++ b/pcsx2/x86/microVU_Compile.inl @@ -79,7 +79,7 @@ microVUt(void) mVUcheckIsSame(mV) { if (mVU->prog.isSame == -1) { - mVU->prog.isSame = !memcmp_mmx(mVU->prog.prog[mVU->prog.cur].data, mVU->regs->Micro, mVU->microMemSize); + mVU->prog.isSame = !memcmp_mmx(mVUcurProg.data, mVU->regs->Micro, mVU->microMemSize); } if (mVU->prog.isSame == 0) { if (!isVU1) mVUcacheProg<0>(mVU->prog.cur); @@ -89,19 +89,56 @@ microVUt(void) mVUcheckIsSame(mV) { } // Sets up microProgram PC ranges based on whats been recompiled -microVUt(void) mVUsetupRange(mV, u32 pc) { +microVUt(void) mVUsetupRange(mV, s32 pc, bool isStartPC) { - if (mVUcurProg.range[0] == -1) { - mVUcurProg.range[0] = (s32)pc; - mVUcurProg.range[1] = (s32)pc; + for (int i = 0; i <= mVUcurProg.ranges.total; i++) { + if ((pc >= mVUcurProg.ranges.range[i][0]) + && (pc <= mVUcurProg.ranges.range[i][1])) { return; } } - else if (mVUcurProg.range[0] > (s32)pc) { - mVUcurProg.range[0] = (s32)pc; - mVUcheckIsSame(mVU); + + mVUcheckIsSame(mVU); + + if (isStartPC) { + if (mVUcurProg.ranges.total < mVUcurProg.ranges.max) { + mVUcurProg.ranges.total++; + mVUrange[0] = pc; + } + else { + mVUcurProg.ranges.total = 0; + mVUrange[0] = 0; + mVUrange[1] = mVU->microMemSize - 8; + DevCon::Status("microVU%d: Prog Range List Full", params mVU->index); + } } - else if (mVUcurProg.range[1] < (s32)pc) { - mVUcurProg.range[1] = (s32)pc; - mVUcheckIsSame(mVU); + else { + if (mVUrange[1] != -1) return; + if (mVUrange[0] <= pc) { + mVUrange[1] = pc; + for (int i = 0; i <= (mVUcurProg.ranges.total-1); i++) { + if ((mVUrange[0]-8) == mVUcurProg.ranges.range[i][1]) { + mVUcurProg.ranges.range[i][1] = pc; + mVUrange[0] = -1; + mVUrange[1] = -1; + mVUcurProg.ranges.total--; + //DevCon::Status("microVU%d: Prog Range Merging", params mVU->index); + } + } + } + else { + DevCon::Status("microVU%d: Prog Range Wrap", params mVU->index); + mVUrange[1] = mVU->microMemSize - 8; + if (mVUcurProg.ranges.total < mVUcurProg.ranges.max) { + mVUcurProg.ranges.total++; + mVUrange[0] = 0; + mVUrange[1] = pc; + } + else { + mVUcurProg.ranges.total = 0; + mVUrange[0] = 0; + mVUrange[1] = mVU->microMemSize - 8; + DevCon::Status("microVU%d: Prog Range List Full", params mVU->index); + } + } } } @@ -236,7 +273,6 @@ microVUt(void) mVUendProgram(mV, int isEbit, int* xStatus, int* xMac, int* xClip } if (isEbit != 2) { // Save PC, and Jump to Exit Point - mVUsetupRange(mVU, xPC); MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC].UL, xPC); JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5)); } @@ -298,7 +334,7 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) { const u32 endCount = (mVU->microMemSize / 8) - 1; // Setup Program Bounds/Range - mVUsetupRange(mVU, startPC); + mVUsetupRange(mVU, startPC, 1); // First Pass iPC = startPC / 4; @@ -360,7 +396,7 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) { else { microBlock* bBlock = NULL; s32* ajmp = 0; - mVUsetupRange(mVU, xPC); + mVUsetupRange(mVU, xPC, 0); mVUdebugNOW(1); switch (mVUbranch) { @@ -441,6 +477,7 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) { if (x == endCount) { Console::Error("microVU%d: Possible infinite compiling loop!", params mVU->index); } // E-bit End + mVUsetupRange(mVU, xPC, 0); mVUendProgram(mVU, 1, xStatus, xMac, xClip); return thisPtr; } diff --git a/pcsx2/x86/microVU_Misc.h b/pcsx2/x86/microVU_Misc.h index aa9c991eb6..cb252591a6 100644 --- a/pcsx2/x86/microVU_Misc.h +++ b/pcsx2/x86/microVU_Misc.h @@ -206,6 +206,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*); #define cFLAG mVUinfo.cFlag #define mVUstartPC mVUallocInfo.startPC #define mVUflagInfo mVUregs.needExactMatch +#define mVUrange mVUcurProg.ranges.range[mVUcurProg.ranges.total] #define xPC ((iPC / 2) * 8) #define curI ((u32*)mVU->regs->Micro)[iPC] //mVUcurProg.data[iPC] #define setCode() { mVU->code = curI; } @@ -214,7 +215,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*); #define bSaveAddr (((xPC + (2 * 8)) & ((isVU1) ? 0x3ff8:0xff8)) / 8) #define branchAddr ((xPC + 8 + (_Imm11_ * 8)) & (mVU->microMemSize-8)) #define shufflePQ (((mVU->p) ? 0xb0 : 0xe0) | ((mVU->q) ? 0x01 : 0x04)) -#define cmpOffset(x) (&(((u8*)x)[mVUprogI.range[0]])) +#define cmpOffset(x) (&(((u8*)x)[mVUprogI.ranges.range[i][0]])) #define Rmem (uptr)&mVU->regs->VI[REG_R].UL #define Roffset (uptr)&mVU->regs->VI[9].UL