mirror of https://github.com/PCSX2/pcsx2.git
mVU: work-in-progress cache and memory model rewrite.
currently not 100% stable, this is mainly a backup before i do more big changes... git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2663 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
1461281f5f
commit
fe915cfa67
|
@ -94,7 +94,6 @@ _f void mVUinit(VURegs* vuRegsPtr, int vuIndex) {
|
||||||
mVU->cacheSize = mVUcacheSize;
|
mVU->cacheSize = mVUcacheSize;
|
||||||
mVU->prog.max = mMaxProg - 1;
|
mVU->prog.max = mMaxProg - 1;
|
||||||
mVU->prog.prog = (microProgram*)_aligned_malloc(sizeof(microProgram)*(mVU->prog.max+1), 64);
|
mVU->prog.prog = (microProgram*)_aligned_malloc(sizeof(microProgram)*(mVU->prog.max+1), 64);
|
||||||
mVU->prog.progList = new int[mMaxProg];
|
|
||||||
mVU->regAlloc = new microRegAlloc(mVU->regs);
|
mVU->regAlloc = new microRegAlloc(mVU->regs);
|
||||||
mVUprint((vuIndex) ? "microVU1: init" : "microVU0: init");
|
mVUprint((vuIndex) ? "microVU1: init" : "microVU0: init");
|
||||||
|
|
||||||
|
@ -108,6 +107,10 @@ _f void mVUinit(VURegs* vuRegsPtr, int vuIndex) {
|
||||||
memset(mVU->cache, 0xcc, mVU->cacheSize + 0x1000);
|
memset(mVU->cache, 0xcc, mVU->cacheSize + 0x1000);
|
||||||
memset(mVU->prog.prog, 0, sizeof(microProgram)*(mVU->prog.max+1));
|
memset(mVU->prog.prog, 0, sizeof(microProgram)*(mVU->prog.max+1));
|
||||||
|
|
||||||
|
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
|
||||||
|
mVU->prog.list[i].list = new deque<microProgram*>();
|
||||||
|
}
|
||||||
|
|
||||||
// Setup Entrance/Exit Points
|
// Setup Entrance/Exit Points
|
||||||
x86SetPtr(mVU->cache);
|
x86SetPtr(mVU->cache);
|
||||||
mVUdispatcherA(mVU);
|
mVUdispatcherA(mVU);
|
||||||
|
@ -139,10 +142,17 @@ _f void mVUreset(mV) {
|
||||||
mVU->prog.x86ptr = z;
|
mVU->prog.x86ptr = z;
|
||||||
mVU->prog.x86end = (u8*)((uptr)z + (uptr)(mVU->cacheSize - (_1mb * 3))); // 3mb "Safe Zone"
|
mVU->prog.x86end = (u8*)((uptr)z + (uptr)(mVU->cacheSize - (_1mb * 3))); // 3mb "Safe Zone"
|
||||||
|
|
||||||
|
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
|
||||||
|
mVU->prog.list[i].list->clear();
|
||||||
|
mVU->prog.list[i].size = 0;
|
||||||
|
mVU->prog.list[i].quick = NULL;
|
||||||
|
mVU->prog.list[i].quickIdx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i <= mVU->prog.max; i++) {
|
for (int i = 0; i <= mVU->prog.max; i++) {
|
||||||
if (!mVU->index) mVUclearProg<0>(i);
|
if (!mVU->index) mVUclearProg<0>(mVU->prog.prog[i]);
|
||||||
else mVUclearProg<1>(i);
|
else mVUclearProg<1>(mVU->prog.prog[i]);
|
||||||
mVU->prog.progList[i] = i;
|
mVU->prog.prog[i].idx = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +172,9 @@ _f void mVUclose(mV) {
|
||||||
}
|
}
|
||||||
safe_aligned_free(mVU->prog.prog);
|
safe_aligned_free(mVU->prog.prog);
|
||||||
}
|
}
|
||||||
safe_delete_array(mVU->prog.progList);
|
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
|
||||||
|
safe_delete(mVU->prog.list[i].list);
|
||||||
|
}
|
||||||
safe_delete(mVU->regAlloc);
|
safe_delete(mVU->regAlloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +183,10 @@ _f void mVUclear(mV, u32 addr, u32 size) {
|
||||||
if (!mVU->prog.cleared) {
|
if (!mVU->prog.cleared) {
|
||||||
memzero(mVU->prog.lpState); // Clear pipeline state
|
memzero(mVU->prog.lpState); // Clear pipeline state
|
||||||
mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram
|
mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram
|
||||||
|
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
|
||||||
|
mVU->prog.list[i].quick = NULL; // Clear current quick-reference prog list
|
||||||
|
mVU->prog.list[i].quickIdx = -1; // Set to 'invalid' index
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,13 +195,12 @@ _f void mVUclear(mV, u32 addr, u32 size) {
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
// Clears program data
|
// Clears program data
|
||||||
_mVUt _f void mVUclearProg(int progIndex) {
|
_mVUt _f void mVUclearProg(microProgram& program) {
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
microProgram& program = mVU->prog.prog[progIndex];
|
|
||||||
|
|
||||||
program.used = 0;
|
program.used = 0;
|
||||||
program.age = isDead;
|
program.age = isDead;
|
||||||
program.frame = mVU->prog.curFrame;
|
program.frame = mVU->prog.curFrame;
|
||||||
|
program.startPC = 0x7fffffff;
|
||||||
for (int j = 0; j <= program.ranges.max; j++) {
|
for (int j = 0; j <= program.ranges.max; j++) {
|
||||||
program.ranges.range[j][0] = -1; // Set range to
|
program.ranges.range[j][0] = -1; // Set range to
|
||||||
program.ranges.range[j][1] = -1; // indeterminable status
|
program.ranges.range[j][1] = -1; // indeterminable status
|
||||||
|
@ -196,25 +211,18 @@ _mVUt _f void mVUclearProg(int progIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caches Micro Program
|
/*
|
||||||
_mVUt _f void mVUcacheProg(int progIndex) {
|
microProgram* mVUcreateProg(int progIndex, int startPC) {
|
||||||
microVU* mVU = mVUx;
|
return (microProgram*)_aligned_malloc(sizeof(microProgram), 64);
|
||||||
if (!vuIndex) memcpy_const(mVU->prog.prog[progIndex].data, mVU->regs->Micro, 0x1000);
|
|
||||||
else memcpy_const(mVU->prog.prog[progIndex].data, mVU->regs->Micro, 0x4000);
|
|
||||||
mVUdumpProg(progIndex);
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Sorts the program list (Moves progIndex to Beginning of ProgList)
|
// Caches Micro Program
|
||||||
_f void mVUsortProg(mV, int progIndex) {
|
_mVUt _f void mVUcacheProg(microProgram& prog) {
|
||||||
int* temp = new int[mVU->prog.max+1];
|
microVU* mVU = mVUx;
|
||||||
int offset = 0;
|
if (!vuIndex) memcpy_const(prog.data, mVU->regs->Micro, 0x1000);
|
||||||
for (int i = 0; i <=(mVU->prog.max-1); i++) {
|
else memcpy_const(prog.data, mVU->regs->Micro, 0x4000);
|
||||||
if (progIndex == mVU->prog.progList[i]) offset = 1;
|
mVUdumpProg(prog.idx);
|
||||||
temp[i+1] = mVU->prog.progList[i+offset];
|
|
||||||
}
|
|
||||||
temp[0] = progIndex;
|
|
||||||
delete[] mVU->prog.progList;
|
|
||||||
mVU->prog.progList = temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finds the least used program, (if program list full clears and returns an old program; if not-full, returns free program)
|
// Finds the least used program, (if program list full clears and returns an old program; if not-full, returns free program)
|
||||||
|
@ -224,26 +232,37 @@ _mVUt _f int mVUfindLeastUsedProg() {
|
||||||
for (int i = 0; i <= mVU->prog.max; i++) {
|
for (int i = 0; i <= mVU->prog.max; i++) {
|
||||||
if (mVU->prog.prog[i].age == isDead) {
|
if (mVU->prog.prog[i].age == isDead) {
|
||||||
mVU->prog.total++;
|
mVU->prog.total++;
|
||||||
mVUcacheProg<vuIndex>(i); // Cache Micro Program
|
mVUcacheProg<vuIndex>(mVU->prog.prog[i]); // Cache Micro Program
|
||||||
mVU->prog.prog[i].age = isYoung;
|
mVU->prog.prog[i].age = isYoung;
|
||||||
mVU->prog.prog[i].used = 1;
|
mVU->prog.prog[i].used = 1;
|
||||||
mVUsortProg(mVU, i);
|
|
||||||
Console.WriteLn(Color_Orange, "microVU%d: Cached MicroPrograms = [%03d] [%03d]", vuIndex, i+1, mVU->prog.total+1);
|
Console.WriteLn(Color_Orange, "microVU%d: Cached MicroPrograms = [%03d] [%03d]", vuIndex, i+1, mVU->prog.total+1);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we reach this, it means all program slots are used, so delete old ones...
|
||||||
static int clearIdx = 0;
|
static int clearIdx = 0;
|
||||||
int pIdx = clearIdx;
|
int pIdx = clearIdx;
|
||||||
for (int i = 0; i < ((mVU->prog.max+1)/4); i++) {
|
for (int i = 0; i < ((mVU->prog.max+1)/4); i++) {
|
||||||
mVUclearProg<vuIndex>(clearIdx);
|
if (mVU->prog.prog[i].used) continue; // Don't delete currently executing program(s)
|
||||||
|
assert(mVU->prog.prog[i].startPC < (mVU->progSize / 2));
|
||||||
|
microProgramList& list = mVU->prog.list[mVU->prog.prog[i].startPC];
|
||||||
|
deque<microProgram*>::iterator it = list.list->begin();
|
||||||
|
for ( ; it != list.list->end(); it++) {
|
||||||
|
if (it[0] == &mVU->prog.prog[i]) {
|
||||||
|
list.list->erase(it);
|
||||||
|
list.quick = NULL;
|
||||||
|
DevCon.WriteLn("Deleting List Reference!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mVUclearProg<vuIndex>(mVU->prog.prog[clearIdx]);
|
||||||
clearIdx = aWrap(clearIdx+1, mVU->prog.max);
|
clearIdx = aWrap(clearIdx+1, mVU->prog.max);
|
||||||
}
|
}
|
||||||
mVU->prog.total -= ((mVU->prog.max+1)/4)-1;
|
mVU->prog.total -= ((mVU->prog.max+1)/4)-1;
|
||||||
mVUcacheProg<vuIndex>(pIdx); // Cache Micro Program
|
mVUcacheProg<vuIndex>(mVU->prog.prog[pIdx]); // Cache Micro Program
|
||||||
mVU->prog.prog[pIdx].age = isYoung;
|
mVU->prog.prog[pIdx].age = isYoung;
|
||||||
mVU->prog.prog[pIdx].used = 1;
|
mVU->prog.prog[pIdx].used = 1;
|
||||||
mVUsortProg(mVU, pIdx);
|
|
||||||
Console.WriteLn(Color_Orange, "microVU%d: Cached MicroPrograms = [%03d] [%03d]", vuIndex, pIdx+1, mVU->prog.total+1);
|
Console.WriteLn(Color_Orange, "microVU%d: Cached MicroPrograms = [%03d] [%03d]", vuIndex, pIdx+1, mVU->prog.total+1);
|
||||||
return pIdx;
|
return pIdx;
|
||||||
}
|
}
|
||||||
|
@ -256,28 +275,28 @@ _f void mVUvsyncUpdate(mV) {
|
||||||
mVU->prog.prog[i].used = 0;
|
mVU->prog.prog[i].used = 0;
|
||||||
mVU->prog.prog[i].frame = mVU->prog.curFrame;
|
mVU->prog.prog[i].frame = mVU->prog.curFrame;
|
||||||
}
|
}
|
||||||
else { // Age Micro Program that wasn't used
|
/*else { // Age Micro Program that wasn't used
|
||||||
s32 diff = mVU->prog.curFrame - mVU->prog.prog[i].frame;
|
s32 diff = mVU->prog.curFrame - mVU->prog.prog[i].frame;
|
||||||
if (diff >= (360 * 10)) {
|
if (diff >= (60 * 1)) {
|
||||||
if (i == mVU->prog.cur) continue; // Don't Age/Kill last used program
|
if (i == mVU->prog.cur) continue; // Don't Age/Kill last used program
|
||||||
mVU->prog.total--;
|
mVU->prog.total--;
|
||||||
if (!mVU->index) mVUclearProg<0>(i);
|
if (!mVU->index) mVUclearProg<0>(i);
|
||||||
else mVUclearProg<1>(i);
|
else mVUclearProg<1>(i);
|
||||||
DevCon.WriteLn("microVU%d: Killing Dead Program [%03d]", mVU->index, i+1);
|
DevCon.WriteLn("microVU%d: Killing Dead Program [%03d]", mVU->index, i+1);
|
||||||
}
|
}
|
||||||
elif(diff >= (60 * 1)) { mVU->prog.prog[i].age = isOld; }
|
//elif(diff >= (60 * 1)) { mVU->prog.prog[i].age = isOld; }
|
||||||
elif(diff >= (20 * 1)) { mVU->prog.prog[i].age = isAged; }
|
//elif(diff >= (20 * 1)) { mVU->prog.prog[i].age = isAged; }
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
mVU->prog.curFrame++;
|
mVU->prog.curFrame++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mVUt _f bool mVUcmpPartial(int progIndex) {
|
_mVUt _f bool mVUcmpPartial(microProgram& prog) {
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
for (int i = 0; i <= mVUprogI.ranges.total; i++) {
|
for (int i = 0; i <= prog.ranges.total; i++) {
|
||||||
if ((mVUprogI.ranges.range[i][0] < 0)
|
if((prog.ranges.range[i][0] < 0)
|
||||||
|| (mVUprogI.ranges.range[i][1] < 0)) { DevCon.Error("microVU%d: Negative Range![%d][%d]", mVU->index, i, mVUprogI.ranges.total); }
|
|| (prog.ranges.range[i][1] < 0)) { DevCon.Error("microVU%d: Negative Range![%d][%d]", mVU->index, i, prog.ranges.total); }
|
||||||
if (memcmp_mmx(cmpOffset(mVUprogI.data), cmpOffset(mVU->regs->Micro), ((mVUprogI.ranges.range[i][1] + 8) - mVUprogI.ranges.range[i][0]))) {
|
if (memcmp_mmx(cmpOffset(prog.data), cmpOffset(mVU->regs->Micro), ((prog.ranges.range[i][1] + 8) - prog.ranges.range[i][0]))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,46 +304,53 @@ _mVUt _f bool mVUcmpPartial(int progIndex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare Cached microProgram to mVU->regs->Micro
|
// Compare Cached microProgram to mVU->regs->Micro
|
||||||
_mVUt _f bool mVUcmpProg(int progIndex, const int checkAge, const bool cmpWholeProg) {
|
_mVUt _f bool mVUcmpProg(microProgram& prog, const bool cmpWholeProg) {
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
if (checkAge == mVUprogI.age) {
|
if (prog.age == isDead) return 0;
|
||||||
if ((cmpWholeProg && !memcmp_mmx((u8*)mVUprogI.data, mVU->regs->Micro, mVU->microMemSize))
|
if ((cmpWholeProg && !memcmp_mmx((u8*)prog.data, mVU->regs->Micro, mVU->microMemSize))
|
||||||
|| (!cmpWholeProg && mVUcmpPartial<vuIndex>(progIndex))) {
|
|| (!cmpWholeProg && mVUcmpPartial<vuIndex>(prog))) {
|
||||||
mVU->prog.cur = progIndex;
|
|
||||||
mVU->prog.cleared = 0;
|
mVU->prog.cleared = 0;
|
||||||
|
mVU->prog.cur = prog.idx;
|
||||||
mVU->prog.isSame = cmpWholeProg ? 1 : -1;
|
mVU->prog.isSame = cmpWholeProg ? 1 : -1;
|
||||||
mVU->prog.prog[progIndex].used = 1;
|
prog.used = 1;
|
||||||
mVU->prog.prog[progIndex].age = isYoung;
|
prog.age = isYoung;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches for Cached Micro Program and sets prog.cur to it (returns 1 if program found, else returns 0)
|
// Searches for Cached Micro Program and sets prog.cur to it (returns entry-point to program)
|
||||||
_mVUt _f int mVUsearchProg() {
|
_mVUt _f void* mVUsearchProg(u32 startPC, uptr pState) {
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
if (mVU->prog.cleared) { // If cleared, we need to search for new program
|
microProgramList& list = mVU->prog.list[startPC/8];
|
||||||
for (int i = mVU->prog.max; i >= 0; i--) {
|
if(!list.quick) { // If null, we need to search for new program
|
||||||
if (mVUcmpProg<vuIndex>(mVU->prog.progList[i], 0, 0))
|
deque<microProgram*>::iterator it = list.list->begin();
|
||||||
return 1; // Check Young Programs
|
for ( ; it != list.list->end(); it++) {
|
||||||
|
if (mVUcmpProg<vuIndex>(*it[0], 0)) {
|
||||||
|
microProgram* t = it[0];
|
||||||
|
list.list->erase(it);
|
||||||
|
list.list->push_front(t);
|
||||||
|
list.quick = t->block[startPC/8];
|
||||||
|
list.quickIdx = t->idx;
|
||||||
|
return mVUentryGet(mVU, list.quick, startPC, pState);
|
||||||
}
|
}
|
||||||
for (int i = mVU->prog.max; i >= 0; i--) {
|
|
||||||
if (mVUcmpProg<vuIndex>(mVU->prog.progList[i], 1, 0))
|
|
||||||
return 1; // Check Aged Programs
|
|
||||||
}
|
|
||||||
for (int i = mVU->prog.max; i >= 0; i--) {
|
|
||||||
if (mVUcmpProg<vuIndex>(mVU->prog.progList[i], 2, 0))
|
|
||||||
return 1; // Check Old Programs
|
|
||||||
}
|
}
|
||||||
mVU->prog.cur = mVUfindLeastUsedProg<vuIndex>(); // If cleared and program not found, make a new program instance
|
mVU->prog.cur = mVUfindLeastUsedProg<vuIndex>(); // If cleared and program not found, make a new program instance
|
||||||
mVU->prog.cleared = 0;
|
mVU->prog.cleared = 0;
|
||||||
mVU->prog.isSame = 1;
|
mVU->prog.isSame = 1;
|
||||||
return 0;
|
mVUcurProg.startPC = startPC / 8;
|
||||||
|
void* entryPoint = mVUblockFetch(mVU, startPC, pState);
|
||||||
|
list.quick = mVUcurProg.block[startPC/8];
|
||||||
|
list.quickIdx = mVUcurProg.idx;
|
||||||
|
list.list->push_front(&mVUcurProg);
|
||||||
|
DevCon.WriteLn("List[%d].Size = %d", startPC/8, list.list->size());
|
||||||
|
return entryPoint;
|
||||||
}
|
}
|
||||||
mVU->prog.prog[mVU->prog.cur].used = 1;
|
mVU->prog.cur = list.quickIdx;
|
||||||
mVU->prog.prog[mVU->prog.cur].age = isYoung;
|
mVU->prog.isSame = -1;
|
||||||
return 1; // If !cleared, then we're still on the same program as last-time ;)
|
mVUcurProg.used = 1;
|
||||||
|
mVUcurProg.age = isYoung;
|
||||||
|
return mVUentryGet(mVU, list.quick, startPC, pState); // If list.quick, then we've already found and recompiled the program ;)
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
|
@ -22,6 +22,8 @@ class AsciiFile;
|
||||||
using namespace x86Emitter;
|
using namespace x86Emitter;
|
||||||
#include "microVU_IR.h"
|
#include "microVU_IR.h"
|
||||||
#include "microVU_Misc.h"
|
#include "microVU_Misc.h"
|
||||||
|
using namespace std;
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
struct microBlockLink {
|
struct microBlockLink {
|
||||||
microBlock* block;
|
microBlock* block;
|
||||||
|
@ -119,6 +121,7 @@ enum microProgramAge {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define mProgSize (0x4000/4)
|
#define mProgSize (0x4000/4)
|
||||||
|
#define mMaxProg ((mVU->index)?400:8) // The amount of Micro Programs Recs will 'remember'
|
||||||
struct microProgram {
|
struct microProgram {
|
||||||
u32 data [mProgSize]; // Holds a copy of the VU microProgram
|
u32 data [mProgSize]; // Holds a copy of the VU microProgram
|
||||||
microBlockManager* block[mProgSize/2]; // Array of Block Managers
|
microBlockManager* block[mProgSize/2]; // Array of Block Managers
|
||||||
|
@ -126,13 +129,22 @@ struct microProgram {
|
||||||
u32 frame; // Frame # the program was last used on
|
u32 frame; // Frame # the program was last used on
|
||||||
u32 used; // Program was used this frame?
|
u32 used; // Program was used this frame?
|
||||||
int age; // Program age... Young, Aged, Old, or Dead...
|
int age; // Program age... Young, Aged, Old, or Dead...
|
||||||
|
int idx; // Program idx in array[mMaxProg]
|
||||||
|
u32 startPC; // Start PC of this program
|
||||||
|
};
|
||||||
|
|
||||||
|
struct microProgramList {
|
||||||
|
deque<microProgram*>* list; // List of microPrograms who start with the same startPC value
|
||||||
|
microBlockManager* quick; // Quick reference to valid microBlockManager for current startPC
|
||||||
|
int quickIdx; // Index of the microProgram who is the owner of 'quick'
|
||||||
|
int size; // Current size of the list...
|
||||||
};
|
};
|
||||||
|
|
||||||
#define mMaxProg ((mVU->index)?400:8) // The amount of Micro Programs Recs will 'remember'
|
|
||||||
struct microProgManager {
|
struct microProgManager {
|
||||||
microIR<mProgSize> IRinfo; // IR information
|
microIR<mProgSize> IRinfo; // IR information
|
||||||
microProgram* prog; // Store MicroPrograms in memory
|
microProgram* prog; // Cache MicroPrograms in memory (indirect jumps are treated as new programs)
|
||||||
int* progList; // List of program indexes ordered by age (ordered from newest to oldest)
|
microProgramList list[mProgSize/2]; // List of microProgram references indexed by startPC values
|
||||||
|
//int* progList; // List of program indexes ordered by age (ordered from newest to oldest)
|
||||||
int max; // Max Number of MicroPrograms minus 1
|
int max; // Max Number of MicroPrograms minus 1
|
||||||
int total; // Total Number of valid MicroPrograms minus 1
|
int total; // Total Number of valid MicroPrograms minus 1
|
||||||
int cur; // Index to Current MicroProgram thats running (-1 = uncached)
|
int cur; // Index to Current MicroProgram thats running (-1 = uncached)
|
||||||
|
@ -203,11 +215,10 @@ mVUop(mVUopU);
|
||||||
mVUop(mVUopL);
|
mVUop(mVUopL);
|
||||||
|
|
||||||
// Private Functions
|
// Private Functions
|
||||||
_f void mVUsortProg(mV, int progIndex);
|
_mVUt _f void mVUclearProg(microProgram& prog);
|
||||||
_mVUt _f void mVUclearProg(int progIndex);
|
_mVUt _f void mVUcacheProg(microProgram& prog);
|
||||||
_mVUt _f void mVUcacheProg(int progIndex);
|
_mVUt _f int mVUfindLeastUsedProg();
|
||||||
_mVUt _f int mVUfindLeastUsedProg(microVU* mVU);
|
_mVUt _f int mVUsearchProg(u32 startPC);
|
||||||
_mVUt _f int mVUsearchProg();
|
|
||||||
void* __fastcall mVUexecuteVU0(u32 startPC, u32 cycles);
|
void* __fastcall mVUexecuteVU0(u32 startPC, u32 cycles);
|
||||||
void* __fastcall mVUexecuteVU1(u32 startPC, u32 cycles);
|
void* __fastcall mVUexecuteVU1(u32 startPC, u32 cycles);
|
||||||
|
|
||||||
|
|
|
@ -31,42 +31,14 @@
|
||||||
// Helper Functions
|
// Helper Functions
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
// Used by checkIfSibling below...
|
|
||||||
bool cmpSibling(mV, int progIndex) {
|
|
||||||
if (mVUprogI.age == isDead) return 0;
|
|
||||||
for (int i = 0; i <= mVUprogI.ranges.total; i++) {
|
|
||||||
if ((mVUprogI.ranges.range[i][0] < 0)
|
|
||||||
|| (mVUprogI.ranges.range[i][1] < 0)) { DevCon.Error("microVU%d: Negative Range![%d][%d]", mVU->index, i, mVUprogI.ranges.total); }
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we use partial-program comparisons to search cached microPrograms,
|
|
||||||
// it is possible that another cached microProgram we have also would've
|
|
||||||
// passed the comparison check. This function checks how often this happens...
|
|
||||||
_f void checkIfSibling(mV) {
|
|
||||||
if (mVU->prog.isSame != -1) return;
|
|
||||||
for (int i = mVU->prog.max; i >= 0; i--) {
|
|
||||||
if (i != mVU->prog.cur && cmpSibling(mVU, i)) {
|
|
||||||
if (mVU->prog.prog[i].block[iPC/2] != NULL) {
|
|
||||||
DevCon.WriteLn("mVU: microProgram Sibling Detected! [%d][%d]", mVU->prog.cur, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by mVUsetupRange
|
// Used by mVUsetupRange
|
||||||
_f void mVUcheckIsSame(mV) {
|
_f void mVUcheckIsSame(mV) {
|
||||||
if (0) checkIfSibling(mVU);
|
|
||||||
if (mVU->prog.isSame == -1) {
|
if (mVU->prog.isSame == -1) {
|
||||||
mVU->prog.isSame = !memcmp_mmx((u8*)mVUcurProg.data, mVU->regs->Micro, mVU->microMemSize);
|
mVU->prog.isSame = !memcmp_mmx((u8*)mVUcurProg.data, mVU->regs->Micro, mVU->microMemSize);
|
||||||
}
|
}
|
||||||
if (mVU->prog.isSame == 0) {
|
if (mVU->prog.isSame == 0) {
|
||||||
if (!isVU1) mVUcacheProg<0>(mVU->prog.cur);
|
if (!isVU1) mVUcacheProg<0>(mVU->prog.prog[mVU->prog.cur]);
|
||||||
else mVUcacheProg<1>(mVU->prog.cur);
|
else mVUcacheProg<1>(mVU->prog.prog[mVU->prog.cur]);
|
||||||
mVU->prog.isSame = 1;
|
mVU->prog.isSame = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,6 +428,13 @@ _r void* mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
|
||||||
return thisPtr;
|
return thisPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the entry point of the block (compiles it if not found)
|
||||||
|
_f void* mVUentryGet(microVU* mVU, microBlockManager* block, u32 startPC, uptr pState) {
|
||||||
|
microBlock* pBlock = block->search((microRegInfo*)pState);
|
||||||
|
if (pBlock) return pBlock->x86ptrStart;
|
||||||
|
else return mVUcompile(mVU, startPC, pState);
|
||||||
|
}
|
||||||
|
|
||||||
// Search for Existing Compiled Block (if found, return x86ptr; else, compile and return x86ptr)
|
// Search for Existing Compiled Block (if found, return x86ptr; else, compile and return x86ptr)
|
||||||
_f void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState) {
|
_f void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState) {
|
||||||
|
|
||||||
|
@ -463,12 +442,12 @@ _f void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState) {
|
||||||
startPC &= mVU->microMemSize-8;
|
startPC &= mVU->microMemSize-8;
|
||||||
|
|
||||||
blockCreate(startPC/8);
|
blockCreate(startPC/8);
|
||||||
microBlock* pBlock = mVUblocks[startPC/8]->search((microRegInfo*)pState);
|
return mVUentryGet(mVU, mVUblocks[startPC/8], startPC, pState);
|
||||||
if (pBlock) { return pBlock->x86ptrStart; }
|
|
||||||
else { return mVUcompile(mVU, startPC, pState); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mVUcompileJIT() - Called By JR/JALR during execution
|
// mVUcompileJIT() - Called By JR/JALR during execution
|
||||||
_mVUt void* __fastcall mVUcompileJIT(u32 startPC, uptr pState) {
|
_mVUt void* __fastcall mVUcompileJIT(u32 startPC, uptr pState) {
|
||||||
return mVUblockFetch(mVUx, startPC, pState);
|
//DevCon.WriteLn("JR/JALR!");
|
||||||
|
//return mVUblockFetch(mVUx, startPC, pState);
|
||||||
|
return mVUsearchProg<vuIndex>(startPC, pState); // Find and set correct program
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,12 +105,13 @@ _mVUt void* __fastcall mVUexecute(u32 startPC, u32 cycles) {
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
mVUprint("microVU%x: startPC = 0x%x, cycles = 0x%x", vuIndex, startPC, cycles);
|
mVUprint("microVU%x: startPC = 0x%x, cycles = 0x%x", vuIndex, startPC, cycles);
|
||||||
|
|
||||||
mVUsearchProg<vuIndex>(); // Find and set correct program
|
//mVUsearchProg<vuIndex>(startPC, 0); // Find and set correct program
|
||||||
mVU->cycles = cycles;
|
mVU->cycles = cycles;
|
||||||
mVU->totalCycles = cycles;
|
mVU->totalCycles = cycles;
|
||||||
|
|
||||||
xSetPtr(mVU->prog.x86ptr); // Set x86ptr to where last program left off
|
xSetPtr(mVU->prog.x86ptr); // Set x86ptr to where last program left off
|
||||||
return mVUblockFetch(mVU, startPC, (uptr)&mVU->prog.lpState);
|
//return mVUblockFetch(mVU, startPC, (uptr)&mVU->prog.lpState);
|
||||||
|
return mVUsearchProg<vuIndex>(startPC, (uptr)&mVU->prog.lpState); // Find and set correct program
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
|
@ -190,7 +190,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
|
||||||
#define branchAddr ((xPC + 8 + (_Imm11_ * 8)) & (mVU->microMemSize-8))
|
#define branchAddr ((xPC + 8 + (_Imm11_ * 8)) & (mVU->microMemSize-8))
|
||||||
#define branchAddrN ((xPC + 16 + (_Imm11_ * 8)) & (mVU->microMemSize-8))
|
#define branchAddrN ((xPC + 16 + (_Imm11_ * 8)) & (mVU->microMemSize-8))
|
||||||
#define shufflePQ (((mVU->p) ? 0xb0 : 0xe0) | ((mVU->q) ? 0x01 : 0x04))
|
#define shufflePQ (((mVU->p) ? 0xb0 : 0xe0) | ((mVU->q) ? 0x01 : 0x04))
|
||||||
#define cmpOffset(x) ((u8*)&(((u8*)x)[mVUprogI.ranges.range[i][0]]))
|
#define cmpOffset(x) ((u8*)&(((u8*)x)[prog.ranges.range[i][0]]))
|
||||||
#define Rmem (uptr)&mVU->regs->VI[REG_R].UL
|
#define Rmem (uptr)&mVU->regs->VI[REG_R].UL
|
||||||
#define aWrap(x, m) ((x > m) ? 0 : x)
|
#define aWrap(x, m) ((x > m) ? 0 : x)
|
||||||
#define shuffleSS(x) ((x==1)?(0x27):((x==2)?(0xc6):((x==4)?(0xe1):(0xe4))))
|
#define shuffleSS(x) ((x==1)?(0x27):((x==2)?(0xc6):((x==4)?(0xe1):(0xe4))))
|
||||||
|
|
Loading…
Reference in New Issue