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