- Smarter microProgram comparison. Games will now use less microProgram 'slots'. Speedup in games using a lot of microPrograms at once...

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1443 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2009-06-29 06:28:48 +00:00
parent 7c2e51157e
commit 8f74247b4f
4 changed files with 98 additions and 43 deletions

View File

@ -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<vuIndex>(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<vuIndex>(i, !!mVU->prog.prog[i].used, 1, 0))
if (mVUcmpProg<vuIndex>(i, !!mVU->prog.prog[i].used, 0))
return 1; // Check Recently Used Programs
}
for (int i = 0; i <= mVU->prog.total; i++) {
if (mVUcmpProg<vuIndex>(i, !mVU->prog.prog[i].used, 0, 0))
if (mVUcmpProg<vuIndex>(i, !mVU->prog.prog[i].used, 0))
return 1; // Check Older Programs
}
mVU->prog.cur = mVUfindLeastUsedProg<vuIndex>(); // If cleared and program not found, make a new program instance

View File

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

View File

@ -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);
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 (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);
}
}
else if (mVUcurProg.range[1] < (s32)pc) {
mVUcurProg.range[1] = (s32)pc;
mVUcheckIsSame(mVU);
}
}
@ -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;
}

View File

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