microVU: minor changes

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1407 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2009-06-20 03:45:44 +00:00
parent 69e3dcfa63
commit 2f186e647e
5 changed files with 223 additions and 254 deletions

View File

@ -35,13 +35,14 @@ declareAllVariables // Declares All Global Variables :D
//------------------------------------------------------------------ //------------------------------------------------------------------
// Only run this once per VU! ;) // Only run this once per VU! ;)
microVUf(void) mVUinit(VURegs* vuRegsPtr) { microVUt(void) mVUinit(VURegs* vuRegsPtr, int vuIndex) {
microVU* mVU = mVUx; microVU* mVU = mVUx;
mVU->regs = vuRegsPtr; mVU->regs = vuRegsPtr;
mVU->index = vuIndex; mVU->index = vuIndex;
mVU->vuMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->microMemSize = (vuIndex ? 0x4000 : 0x1000); mVU->microMemSize = (vuIndex ? 0x4000 : 0x1000);
mVU->progMemSize = (vuIndex ? 0x4000 : 0x1000) / 4; mVU->progSize = (vuIndex ? 0x4000 : 0x1000) / 4;
mVU->cache = NULL; mVU->cache = NULL;
mVU->cacheSize = mVUcacheSize; mVU->cacheSize = mVUcacheSize;
memset(&mVU->prog, 0, sizeof(mVU->prog)); memset(&mVU->prog, 0, sizeof(mVU->prog));
@ -51,18 +52,17 @@ microVUf(void) mVUinit(VURegs* vuRegsPtr) {
if ( mVU->cache == NULL ) throw Exception::OutOfMemory(fmt_string( "microVU Error: Failed to allocate recompiler memory! (addr: 0x%x)", (u32)mVU->cache)); if ( mVU->cache == NULL ) throw Exception::OutOfMemory(fmt_string( "microVU Error: Failed to allocate recompiler memory! (addr: 0x%x)", (u32)mVU->cache));
mVUemitSearch(); mVUemitSearch();
mVUreset<vuIndex>(); mVUreset(mVU);
} }
// Resets Rec Data // Resets Rec Data
microVUx(void) mVUreset() { microVUt(void) mVUreset(mV) {
microVU* mVU = mVUx; mVUprint((mVU->index) ? "microVU1: reset" : "microVU0: reset");
mVUprint((vuIndex) ? "microVU1: reset" : "microVU0: reset");
// Delete Block Managers // Delete Block Managers
for (int i = 0; i <= mVU->prog.max; i++) { for (int i = 0; i <= mVU->prog.max; i++) {
for (u32 j = 0; j < (mVU->progMemSize / 2); j++) { for (u32 j = 0; j < (mVU->progSize / 2); j++) {
microBlockManager::Delete( mVU->prog.prog[i].block[j] ); microBlockManager::Delete( mVU->prog.prog[i].block[j] );
} }
} }
@ -99,16 +99,15 @@ microVUx(void) mVUreset() {
} }
// Free Allocated Resources // Free Allocated Resources
microVUf(void) mVUclose() { microVUt(void) mVUclose(mV) {
microVU* mVU = mVUx; mVUprint((mVU->index) ? "microVU1: close" : "microVU0: close");
mVUprint((vuIndex) ? "microVU1: close" : "microVU0: close");
if ( mVU->cache ) { HostSys::Munmap( mVU->cache, mVU->cacheSize ); mVU->cache = NULL; } if (mVU->cache) { HostSys::Munmap(mVU->cache, mVU->cacheSize); mVU->cache = NULL; }
// Delete Block Managers // Delete Block Managers
for (int i = 0; i <= mVU->prog.max; i++) { for (int i = 0; i <= mVU->prog.max; i++) {
for (u32 j = 0; j < (mVU->progMemSize / 2); j++) { for (u32 j = 0; j < (mVU->progSize / 2); j++) {
if (mVU->prog.prog[i].block[j]) { if (mVU->prog.prog[i].block[j]) {
microBlockManager::Delete( mVU->prog.prog[i].block[j] ); microBlockManager::Delete( mVU->prog.prog[i].block[j] );
} }
@ -117,8 +116,7 @@ microVUf(void) mVUclose() {
} }
// Clears Block Data in specified range // Clears Block Data in specified range
microVUf(void) mVUclear(u32 addr, u32 size) { microVUt(void) mVUclear(mV, u32 addr, u32 size) {
microVU* mVU = mVUx;
if (!mVU->prog.cleared) { if (!mVU->prog.cleared) {
memset(&mVU->prog.lpState, 0, sizeof(mVU->prog.lpState)); memset(&mVU->prog.lpState, 0, sizeof(mVU->prog.lpState));
mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram
@ -137,7 +135,7 @@ microVUf(void) mVUclearProg(int progIndex) {
mVU->prog.prog[progIndex].range[0] = -1; mVU->prog.prog[progIndex].range[0] = -1;
mVU->prog.prog[progIndex].range[1] = -1; mVU->prog.prog[progIndex].range[1] = -1;
mVU->prog.prog[progIndex].x86ptr = mVU->prog.prog[progIndex].x86start; mVU->prog.prog[progIndex].x86ptr = mVU->prog.prog[progIndex].x86start;
for (u32 i = 0; i < (mVU->progMemSize / 2); i++) { for (u32 i = 0; i < (mVU->progSize / 2); i++) {
if (mVU->prog.prog[progIndex].block[i]) if (mVU->prog.prog[progIndex].block[i])
mVU->prog.prog[progIndex].block[i]->reset(); mVU->prog.prog[progIndex].block[i]->reset();
} }
@ -191,9 +189,8 @@ microVUf(int) mVUfindLeastUsedProg() {
// frame-based decrementing system in combination with a program-execution-based incrementing // frame-based decrementing system in combination with a program-execution-based incrementing
// system. In english: if last_used >= 2 it means the program has been used for the current // system. In english: if last_used >= 2 it means the program has been used for the current
// or prev frame. if it's 0, the program hasn't been used for a while. // or prev frame. if it's 0, the program hasn't been used for a while.
microVUf(void) mVUvsyncUpdate() { microVUt(void) mVUvsyncUpdate(mV) {
microVU* mVU = mVUx;
if (mVU->prog.total < mVU->prog.max) return; if (mVU->prog.total < mVU->prog.max) return;
for (int i = 0; i <= mVU->prog.total; i++) { for (int i = 0; i <= mVU->prog.total; i++) {
@ -252,232 +249,17 @@ microVUf(int) mVUsearchProg() {
return 1; // If !cleared, then we're still on the same program as last-time ;) return 1; // If !cleared, then we're still on the same program as last-time ;)
} }
//------------------------------------------------------------------
// JIT recompiler -- called from recompiled code when register jumps are made.
//------------------------------------------------------------------
microVUf(void*) __fastcall mVUcompileJIT(u32 startPC, uptr pState) {
return mVUblockFetch( mVUx, startPC, pState );
}
//------------------------------------------------------------------
// Recompiler
//------------------------------------------------------------------
static void* __fastcall mVUcompile( microVU* mVU, u32 startPC, uptr pState )
{
using namespace x86Emitter;
// Setup Program Bounds/Range
mVUsetupRange(mVU, startPC);
microBlock* pBlock = NULL;
u8* thisPtr = x86Ptr;
const u32 microSizeDiv8 = (mVU->microMemSize-1) / 8;
// First Pass
iPC = startPC / 4;
setCode();
mVUbranch = 0;
mVUstartPC = iPC;
mVUcount = 0;
mVUcycles = 0; // Skips "M" phase, and starts counting cycles at "T" stage
mVU->p = 0; // All blocks start at p index #0
mVU->q = 0; // All blocks start at q index #0
memcpy_fast(&mVUregs, (microRegInfo*)pState, sizeof(microRegInfo)); // Loads up Pipeline State Info
mVUblock.x86ptrStart = thisPtr;
pBlock = mVUblocks[startPC/8]->add(&mVUblock); // Add this block to block manager
mVUpBlock = pBlock;
mVUregs.flags = 0;
mVUflagInfo = 0;
mVUsFlagHack = CHECK_VU_FLAGHACK;
for (int branch = 0; mVUcount < microSizeDiv8; ) {
incPC(1);
startLoop();
mVUincCycles(mVU, 1);
mVUopU(mVU, 0);
if (curI & _Ebit_) { branch = 1; mVUup.eBit = 1; }
if (curI & _DTbit_) { branch = 4; }
if (curI & _Mbit_) { mVUup.mBit = 1; }
if (curI & _Ibit_) { mVUlow.isNOP = 1; mVUup.iBit = 1; }
else { incPC(-1); mVUopL(mVU, 0); incPC(1); }
mVUsetCycles(mVU);
mVUinfo.readQ = mVU->q;
mVUinfo.writeQ = !mVU->q;
mVUinfo.readP = mVU->p;
mVUinfo.writeP = !mVU->p;
if (branch >= 2) { mVUinfo.isEOB = 1; if (branch == 3) { mVUinfo.isBdelay = 1; } mVUcount++; branchWarning(); break; }
else if (branch == 1) { branch = 2; }
if (mVUbranch) { mVUsetFlagInfo(mVU); branch = 3; mVUbranch = 0; }
incPC(1);
mVUcount++;
}
// Sets Up Flag instances
int xStatus[4], xMac[4], xClip[4];
int xCycles = mVUsetFlags(mVU, xStatus, xMac, xClip);
mVUtestCycles(mVU);
// Second Pass
iPC = mVUstartPC;
setCode();
mVUbranch = 0;
uint x;
for (x = 0; x < microSizeDiv8; x++) {
if (mVUinfo.isEOB) { x = 0xffff; }
if (mVUup.mBit) { OR32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET); }
if (mVUlow.isNOP) { incPC(1); doUpperOp(); doIbit(); }
else if (!mVUinfo.swapOps) { incPC(1); doUpperOp(); doLowerOp(); }
else { doSwapOp(); }
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
if (!mVUinfo.isBdelay) { incPC(1); }
else {
microBlock* bBlock = NULL;
s32* ajmp = 0;
mVUsetupRange(mVU, xPC);
mVUdebugNOW(1);
switch (mVUbranch) {
case 3: branchCase(Jcc_Equal); // IBEQ
case 4: branchCase(Jcc_GreaterOrEqual); // IBGEZ
case 5: branchCase(Jcc_Greater); // IBGTZ
case 6: branchCase(Jcc_LessOrEqual); // IBLEQ
case 7: branchCase(Jcc_Less); // IBLTZ
case 8: branchCase(Jcc_NotEqual); // IBNEQ
case 1: case 2: // B/BAL
mVUprint("mVUcompile B/BAL");
incPC(-3); // Go back to branch opcode (to get branch imm addr)
if (mVUup.eBit) { iPC = branchAddr/4; mVUendProgram(mVU, 1, xStatus, xMac, xClip); } // E-bit Branch
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
if (mVUblocks[branchAddr/8] == NULL)
mVUblocks[branchAddr/8] = microBlockManager::AlignedNew();
// Check if branch-block has already been compiled
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
if (pBlock) { xJMP(pBlock->x86ptrStart); }
else { mVUcompile(mVU, branchAddr, (uptr)&mVUregs); }
return thisPtr;
case 9: case 10: // JR/JALR
mVUprint("mVUcompile JR/JALR");
incPC(-3); // Go back to jump opcode
if (mVUup.eBit) { // E-bit Jump
mVUendProgram(mVU, 2, xStatus, xMac, xClip);
MOV32MtoR(gprT1, (uptr)&mVU->branch);
MOV32RtoM((uptr)&mVU->regs->VI[REG_TPC].UL, gprT1);
xJMP(mVU->exitFunct);
return thisPtr;
}
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
mVUbackupRegs(mVU);
MOV32MtoR(gprT2, (uptr)&mVU->branch); // Get startPC (ECX first argument for __fastcall)
MOV32ItoR(gprR, (u32)&pBlock->pStateEnd); // Get pState (EDX second argument for __fastcall)
if (!mVU->index) xCALL( mVUcompileJIT<0> ); //(u32 startPC, uptr pState)
else xCALL( mVUcompileJIT<1> );
mVUrestoreRegs(mVU);
JMPR(gprT1); // Jump to rec-code address
return thisPtr;
}
// Conditional Branches
mVUprint("mVUcompile conditional branch");
if (bBlock) { // Branch non-taken has already been compiled
incPC(-3); // Go back to branch opcode (to get branch imm addr)
if (mVUblocks[branchAddr/8] == NULL)
mVUblocks[branchAddr/8] = microBlockManager::AlignedNew();
// Check if branch-block has already been compiled
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
if (pBlock) { xJMP( pBlock->x86ptrStart ); }
else if (!mVU->index) { mVUblockFetch(mVU, branchAddr, (uptr)&mVUregs); }
else { mVUblockFetch(mVU, branchAddr, (uptr)&mVUregs); }
}
else {
uptr jumpAddr;
u32 bPC = iPC; // mVUcompile can modify iPC and mVUregs so back them up
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
incPC2(1); // Get PC for branch not-taken
mVUcompile(mVU, xPC, (uptr)&mVUregs);
iPC = bPC;
incPC(-3); // Go back to branch opcode (to get branch imm addr)
if (!mVU->index) jumpAddr = (uptr)mVUblockFetch(mVU, branchAddr, (uptr)&pBlock->pStateEnd);
else jumpAddr = (uptr)mVUblockFetch(mVU, branchAddr, (uptr)&pBlock->pStateEnd);
*ajmp = (jumpAddr - ((uptr)ajmp + 4));
}
return thisPtr;
}
}
if (x == microSizeDiv8) { Console::Error("microVU%d: Possible infinite compiling loop!", params mVU->index); }
// E-bit End
mVUendProgram(mVU, 1, xStatus, xMac, xClip);
return thisPtr;
}
microVUt(void*) mVUblockFetch( microVU* mVU, u32 startPC, uptr pState )
{
using namespace x86Emitter;
if (startPC > mVU->microMemSize-8) { Console::Error("microVU%d: invalid startPC", params mVU->index); }
startPC &= mVU->microMemSize-8;
if (mVUblocks[startPC/8] == NULL) {
mVUblocks[startPC/8] = microBlockManager::AlignedNew();
}
// Searches for Existing Compiled Block (if found, then returns; else, compile)
microBlock* pBlock = mVUblocks[startPC/8]->search((microRegInfo*)pState);
if (pBlock) { return pBlock->x86ptrStart; }
return mVUcompile( mVU, startPC, pState );
}
//------------------------------------------------------------------ //------------------------------------------------------------------
// Wrapper Functions - Called by other parts of the Emu // Wrapper Functions - Called by other parts of the Emu
//------------------------------------------------------------------ //------------------------------------------------------------------
void initVUrec(VURegs* vuRegs, const int vuIndex) { void initVUrec (VURegs* vuRegs, const int vuIndex) { mVUinit(vuRegs, vuIndex); }
if (!vuIndex) mVUinit<0>(vuRegs); void closeVUrec(const int vuIndex) { mVUclose(mVUx); }
else mVUinit<1>(vuRegs); void resetVUrec(const int vuIndex) { mVUreset(mVUx); }
} void vsyncVUrec(const int vuIndex) { mVUvsyncUpdate(mVUx); }
void clearVUrec(u32 addr, u32 size, const int vuIndex) { mVUclear(mVUx, addr, size); }
void closeVUrec(const int vuIndex) {
if (!vuIndex) mVUclose<0>();
else mVUclose<1>();
}
void resetVUrec(const int vuIndex) {
if (!vuIndex) mVUreset<0>();
else mVUreset<1>();
}
void clearVUrec(u32 addr, u32 size, const int vuIndex) {
if (!vuIndex) mVUclear<0>(addr, size);
else mVUclear<1>(addr, size);
}
void runVUrec(u32 startPC, u32 cycles, const int vuIndex) { void runVUrec(u32 startPC, u32 cycles, const int vuIndex) {
if (!vuIndex) startVU0(startPC, cycles); if (!vuIndex) startVU0(startPC, cycles);
else startVU1(startPC, cycles); else startVU1(startPC, cycles);
} }
void vsyncVUrec(const int vuIndex) {
if (!vuIndex) mVUvsyncUpdate<0>();
else mVUvsyncUpdate<1>();
}

View File

@ -117,8 +117,9 @@ struct microVU {
PCSX2_ALIGNED16(u32 xmmVFb[4]); // Backup for VF regs PCSX2_ALIGNED16(u32 xmmVFb[4]); // Backup for VF regs
u32 index; // VU Index (VU0 or VU1) u32 index; // VU Index (VU0 or VU1)
u32 vuMemSize; // VU Main Memory Size (in bytes)
u32 microMemSize; // VU Micro Memory Size (in bytes) u32 microMemSize; // VU Micro Memory Size (in bytes)
u32 progMemSize; // VU Micro Program Size (microSize/4, because each instruction of a program is 4 bytes) u32 progSize; // VU Micro Memory Size (in u32's)
u32 cacheSize; // VU Cache Size u32 cacheSize; // VU Cache Size
microProgManager<0x4000/4> prog; // Micro Program Data microProgManager<0x4000/4> prog; // Micro Program Data
@ -151,11 +152,12 @@ extern void (*mVU_LOWER_OPCODE[128])( VURegs* VU, s32 info );
extern int mVUdebugNow; extern int mVUdebugNow;
// Main Functions // Main Functions
microVUf(void) mVUinit(VURegs*); microVUt(void) mVUinit(VURegs*, int);
microVUx(void) mVUreset(); microVUt(void) mVUreset(mV);
microVUf(void) mVUclose(); microVUt(void) mVUclose(mV);
microVUf(void) mVUclear(u32, u32); microVUt(void) mVUclear(mV, u32, u32);
microVUt(void*) mVUblockFetch( microVU* mVU, u32 startPC, uptr pState ); microVUt(void*) mVUblockFetch(microVU* mVU, u32 startPC, uptr pState);
microVUx(void*) __fastcall mVUcompileJIT(u32 startPC, uptr pState);
// Prototypes for Linux // Prototypes for Linux
void __fastcall mVUcleanUpVU0(); void __fastcall mVUcleanUpVU0();

View File

@ -282,3 +282,189 @@ microVUt(void) mVUtestCycles(mV) {
mVUendProgram(mVU, 0, NULL, NULL, NULL); mVUendProgram(mVU, 0, NULL, NULL, NULL);
x86SetJ32(jmp32); x86SetJ32(jmp32);
} }
//------------------------------------------------------------------
// Recompiler
//------------------------------------------------------------------
static void* __fastcall mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
using namespace x86Emitter;
microBlock* pBlock = NULL;
u8* thisPtr = x86Ptr;
const u32 endCount = (mVU->microMemSize / 8) - 1;
// Setup Program Bounds/Range
mVUsetupRange(mVU, startPC);
// First Pass
iPC = startPC / 4;
setCode();
mVUbranch = 0;
mVUstartPC = iPC;
mVUcount = 0;
mVUcycles = 0; // Skips "M" phase, and starts counting cycles at "T" stage
mVU->p = 0; // All blocks start at p index #0
mVU->q = 0; // All blocks start at q index #0
memcpy_fast(&mVUregs, (microRegInfo*)pState, sizeof(microRegInfo)); // Loads up Pipeline State Info
mVUblock.x86ptrStart = thisPtr;
pBlock = mVUblocks[startPC/8]->add(&mVUblock); // Add this block to block manager
mVUpBlock = pBlock;
mVUregs.flags = 0;
mVUflagInfo = 0;
mVUsFlagHack = CHECK_VU_FLAGHACK;
for (int branch = 0; mVUcount < endCount; mVUcount++) {
incPC(1);
startLoop();
mVUincCycles(mVU, 1);
mVUopU(mVU, 0);
if (curI & _Ebit_) { branch = 1; mVUup.eBit = 1; }
if (curI & _DTbit_) { branch = 4; }
if (curI & _Mbit_) { mVUup.mBit = 1; }
if (curI & _Ibit_) { mVUlow.isNOP = 1; mVUup.iBit = 1; }
else { incPC(-1); mVUopL(mVU, 0); incPC(1); }
mVUsetCycles(mVU);
mVUinfo.readQ = mVU->q;
mVUinfo.writeQ = !mVU->q;
mVUinfo.readP = mVU->p;
mVUinfo.writeP = !mVU->p;
if (branch >= 2) { mVUinfo.isEOB = 1; if (branch == 3) { mVUinfo.isBdelay = 1; } mVUcount++; branchWarning(); break; }
else if (branch == 1) { branch = 2; }
if (mVUbranch) { mVUsetFlagInfo(mVU); branch = 3; mVUbranch = 0; }
incPC(1);
}
// Sets Up Flag instances
int xStatus[4], xMac[4], xClip[4];
int xCycles = mVUsetFlags(mVU, xStatus, xMac, xClip);
mVUtestCycles(mVU);
// Second Pass
iPC = mVUstartPC;
setCode();
mVUbranch = 0;
uint x;
for (x = 0; x < endCount; x++) {
if (mVUinfo.isEOB) { x = 0xffff; }
if (mVUup.mBit) { OR32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET); }
if (mVUlow.isNOP) { incPC(1); doUpperOp(); doIbit(); }
else if (!mVUinfo.swapOps) { incPC(1); doUpperOp(); doLowerOp(); }
else { doSwapOp(); }
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
if (!mVUinfo.isBdelay) { incPC(1); }
else {
microBlock* bBlock = NULL;
s32* ajmp = 0;
mVUsetupRange(mVU, xPC);
mVUdebugNOW(1);
switch (mVUbranch) {
case 3: branchCase(Jcc_Equal); // IBEQ
case 4: branchCase(Jcc_GreaterOrEqual); // IBGEZ
case 5: branchCase(Jcc_Greater); // IBGTZ
case 6: branchCase(Jcc_LessOrEqual); // IBLEQ
case 7: branchCase(Jcc_Less); // IBLTZ
case 8: branchCase(Jcc_NotEqual); // IBNEQ
case 1: case 2: // B/BAL
mVUprint("mVUcompile B/BAL");
incPC(-3); // Go back to branch opcode (to get branch imm addr)
if (mVUup.eBit) { iPC = branchAddr/4; mVUendProgram(mVU, 1, xStatus, xMac, xClip); } // E-bit Branch
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
if (mVUblocks[branchAddr/8] == NULL)
mVUblocks[branchAddr/8] = microBlockManager::AlignedNew();
// Check if branch-block has already been compiled
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
if (pBlock) { xJMP(pBlock->x86ptrStart); }
else { mVUcompile(mVU, branchAddr, (uptr)&mVUregs); }
return thisPtr;
case 9: case 10: // JR/JALR
mVUprint("mVUcompile JR/JALR");
incPC(-3); // Go back to jump opcode
if (mVUup.eBit) { // E-bit Jump
mVUendProgram(mVU, 2, xStatus, xMac, xClip);
MOV32MtoR(gprT1, (uptr)&mVU->branch);
MOV32RtoM((uptr)&mVU->regs->VI[REG_TPC].UL, gprT1);
xJMP(mVU->exitFunct);
return thisPtr;
}
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
mVUbackupRegs(mVU);
MOV32MtoR(gprT2, (uptr)&mVU->branch); // Get startPC (ECX first argument for __fastcall)
MOV32ItoR(gprR, (u32)&pBlock->pStateEnd); // Get pState (EDX second argument for __fastcall)
if (!mVU->index) xCALL(mVUcompileJIT<0>); //(u32 startPC, uptr pState)
else xCALL(mVUcompileJIT<1>);
mVUrestoreRegs(mVU);
JMPR(gprT1); // Jump to rec-code address
return thisPtr;
}
// Conditional Branches
mVUprint("mVUcompile conditional branch");
if (bBlock) { // Branch non-taken has already been compiled
incPC(-3); // Go back to branch opcode (to get branch imm addr)
if (mVUblocks[branchAddr/8] == NULL)
mVUblocks[branchAddr/8] = microBlockManager::AlignedNew();
// Check if branch-block has already been compiled
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
if (pBlock) { xJMP( pBlock->x86ptrStart ); }
else { mVUblockFetch(mVU, branchAddr, (uptr)&mVUregs); }
}
else {
uptr jumpAddr;
u32 bPC = iPC; // mVUcompile can modify iPC and mVUregs so back them up
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
incPC2(1); // Get PC for branch not-taken
mVUcompile(mVU, xPC, (uptr)&mVUregs);
iPC = bPC;
incPC(-3); // Go back to branch opcode (to get branch imm addr)
jumpAddr = (uptr)mVUblockFetch(mVU, branchAddr, (uptr)&pBlock->pStateEnd);
*ajmp = (jumpAddr - ((uptr)ajmp + 4));
}
return thisPtr;
}
}
if (x == endCount) { Console::Error("microVU%d: Possible infinite compiling loop!", params mVU->index); }
// E-bit End
mVUendProgram(mVU, 1, xStatus, xMac, xClip);
return thisPtr;
}
microVUt(void*) mVUblockFetch(microVU* mVU, u32 startPC, uptr pState) {
using namespace x86Emitter;
if (startPC > mVU->microMemSize-8) { DevCon::Error("microVU%d: invalid startPC", params mVU->index); }
startPC &= mVU->microMemSize-8;
if (mVUblocks[startPC/8] == NULL) {
mVUblocks[startPC/8] = microBlockManager::AlignedNew();
}
// Searches for Existing Compiled Block (if found, then returns; else, compile)
microBlock* pBlock = mVUblocks[startPC/8]->search((microRegInfo*)pState);
if (pBlock) { return pBlock->x86ptrStart; }
else { return mVUcompile(mVU, startPC, pState); }
}
// Called By JR/JALR
microVUx(void*) __fastcall mVUcompileJIT(u32 startPC, uptr pState) {
return mVUblockFetch(mVUx, startPC, pState);
}

View File

@ -62,7 +62,7 @@ microVUx(void) __mVUdumpProgram(int progIndex) {
mVUlog("*********************\n\n<br><br>", progIndex); mVUlog("*********************\n\n<br><br>", progIndex);
mVUlog("</font>"); mVUlog("</font>");
for (u32 i = 0; i < mVU->progMemSize; i+=2) { for (u32 i = 0; i < mVU->progSize; i+=2) {
if (delay) { delay--; mVUlog("</font>"); if (!delay) mVUlog("<hr/>"); } if (delay) { delay--; mVUlog("</font>"); if (!delay) mVUlog("<hr/>"); }
if (mVUbranch) { delay = 1; mVUbranch = 0; } if (mVUbranch) { delay = 1; mVUbranch = 0; }

View File

@ -201,8 +201,8 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
#define xPC ((iPC / 2) * 8) #define xPC ((iPC / 2) * 8)
#define curI ((u32*)mVU->regs->Micro)[iPC] //mVUcurProg.data[iPC] #define curI ((u32*)mVU->regs->Micro)[iPC] //mVUcurProg.data[iPC]
#define setCode() { mVU->code = curI; } #define setCode() { mVU->code = curI; }
#define incPC(x) { iPC = ((iPC + x) & (mVU->progMemSize-1)); setCode(); } #define incPC(x) { iPC = ((iPC + x) & (mVU->progSize-1)); setCode(); }
#define incPC2(x) { iPC = ((iPC + x) & (mVU->progMemSize-1)); } #define incPC2(x) { iPC = ((iPC + x) & (mVU->progSize-1)); }
#define bSaveAddr (((xPC + (2 * 8)) & ((isVU1) ? 0x3ff8:0xff8)) / 8) #define bSaveAddr (((xPC + (2 * 8)) & ((isVU1) ? 0x3ff8:0xff8)) / 8)
#define branchAddr ((xPC + 8 + (_Imm11_ * 8)) & (mVU->microMemSize-8)) #define branchAddr ((xPC + 8 + (_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))
@ -274,8 +274,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
uptr diff = ptr - start; \ uptr diff = ptr - start; \
if (diff >= limit) { \ if (diff >= limit) { \
Console::Error("microVU Error: Program went over its cache limit. Size = 0x%x", params diff); \ Console::Error("microVU Error: Program went over its cache limit. Size = 0x%x", params diff); \
if (!isVU1) mVUreset<0>(); \ mVUreset(mVU); \
else mVUreset<1>(); \
} \ } \
} }