- Implemented E-bit Conditional Branches and Jumps. Should fix infinite loop problems in games like Zone of the Enders, but it hasn't been tested yet since I don't have the game xD.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1343 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2009-06-07 09:42:10 +00:00
parent 96fb298371
commit b61f7cc4d1
2 changed files with 86 additions and 69 deletions

View File

@ -32,27 +32,27 @@
class microBlockManager {
private:
static const int MaxBlocks = mMaxBlocks - 1;
microBlock blockList[mMaxBlocks]; // note: should always be first in the class to ensure xmm alignment
microBlock blockList[mMaxBlocks]; // Should always be first in the class to ensure 16-byte alignment
int listSize; // Total Items - 1
int listI; // Index to Add new block
public:
// our aligned replacement for 'new':
// Aligned replacement for 'new'
static microBlockManager* AlignedNew() {
microBlockManager* alloc = (microBlockManager*)_aligned_malloc(sizeof(microBlockManager), 16);
new (alloc) microBlockManager();
return alloc;
}
static void Delete( microBlockManager* dead ) {
if( dead == NULL ) return;
// Use instead of normal 'delete'
static void Delete(microBlockManager* dead) {
if (dead == NULL) return;
dead->~microBlockManager();
_aligned_free( dead );
}
microBlockManager() { reset(); }
~microBlockManager() { }
void reset() { listSize = -1; listI = -1; };
~microBlockManager() {}
void reset() { listSize = -1; listI = -1; };
microBlock* add(microBlock* pBlock) {
microBlock* thisBlock = search(&pBlock->pState);
if (!thisBlock) {

View File

@ -22,15 +22,30 @@
// Helper Macros
//------------------------------------------------------------------
#define branchCase(JMPcc, nJMPcc) \
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles); \
CMP16ItoM((uptr)&mVU->branch, 0); \
incPC2(1); \
if (!mVUblocks[iPC/2]) { mVUblocks[iPC/2] = microBlockManager::AlignedNew(); } \
bBlock = mVUblocks[iPC/2]->search((microRegInfo*)&mVUregs); \
incPC2(-1); \
if (bBlock) { nJMPcc((uptr)bBlock->x86ptrStart - ((uptr)x86Ptr + 6)); } \
else { ajmp = JMPcc((uptr)0); } \
#define branchCase(JMPcc, nJMPcc, ebitJMP) \
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles); \
CMP16ItoM((uptr)&mVU->branch, 0); \
if (mVUup.eBit) { /* Conditional Branch With E-Bit Set */ \
mVUendProgram(mVU, 2, xStatus, xMac, xClip); \
u8* eJMP = ebitJMP(0); \
incPC(1); /* Set PC to First instruction of Non-Taken Side */ \
MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC].UL, xPC); \
JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5)); \
x86SetJ8(eJMP); \
incPC(-4); /* Go Back to Branch Opcode to get branchAddr */ \
iPC = branchAddr/4; \
MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC].UL, xPC); \
JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5)); \
return thisPtr; \
} \
else { /* Normal Conditional Branch */ \
incPC2(1); /* Check if Branch Non-Taken Side has already been recompiled */ \
if (!mVUblocks[iPC/2]) { mVUblocks[iPC/2] = microBlockManager::AlignedNew(); } \
bBlock = mVUblocks[iPC/2]->search((microRegInfo*)&mVUregs); \
incPC2(-1); \
if (bBlock) { nJMPcc((uptr)bBlock->x86ptrStart - ((uptr)x86Ptr + 6)); } \
else { ajmp = JMPcc((uptr)0); } \
} \
break
#define branchWarning() { \
@ -40,15 +55,6 @@
} \
}
#define branchEbit() { \
if (branch == 2) { \
if (!((mVUbranch == 1) || (mVUbranch == 2))) { \
Console::Error("microVU%d Warning: Jump with E-bit not Implemented [%04x]", params vuIndex, xPC); \
} \
else { eBitBranch = 1; } \
} \
}
#define doBackupVF1() { \
if (mVUinfo.backupVF && !mVUlow.noWriteVF) { \
DevCon::Status("microVU%d: Backing Up VF Reg [%04x]", params getIndex, xPC); \
@ -205,7 +211,31 @@ microVUt(void) mVUsetCycles(mV) {
tCycles(mVUregs.xgkick, mVUregsTemp.xgkick);
}
microVUt(void) mVUendProgram(mV, bool clearIsBusy, int qInst, int pInst, int fStatus, int fMac, int fClip) {
#define sI ((mVUpBlock->pState.needExactMatch & 0x000f) ? 0 : ((mVUpBlock->pState.flags >> 0) & 3))
#define cI ((mVUpBlock->pState.needExactMatch & 0x0f00) ? 0 : ((mVUpBlock->pState.flags >> 2) & 3))
microVUt(void) mVUendProgram(mV, int isEbit, int* xStatus, int* xMac, int* xClip) {
int fStatus = (isEbit) ? findFlagInst(xStatus, 0x7fffffff) : sI;
int fMac = (isEbit) ? findFlagInst(xMac, 0x7fffffff) : 0;
int fClip = (isEbit) ? findFlagInst(xClip, 0x7fffffff) : cI;
int qInst = 0;
int pInst = 0;
if (isEbit) {
mVUprint("mVUcompile ebit");
memset(&mVUinfo, 0, sizeof(mVUinfo));
mVUincCycles(mVU, 100); // Ensures Valid P/Q instances (And sets all cycle data to 0)
mVUcycles -= 100;
qInst = mVU->q;
pInst = mVU->p;
if (mVUinfo.doDivFlag) {
sFLAG.doFlag = 1;
sFLAG.write = fStatus;
mVUdivSet(mVU);
}
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
}
// Save P/Q Regs
if (qInst) { SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, 0xe5); }
@ -223,19 +253,18 @@ microVUt(void) mVUendProgram(mV, bool clearIsBusy, int qInst, int pInst, int fSt
MOV32RtoM((uptr)&mVU->regs->VI[REG_MAC_FLAG].UL, gprT1);
MOV32RtoM((uptr)&mVU->regs->VI[REG_CLIP_FLAG].UL, gprT2);
if (clearIsBusy) { // Clear 'is busy' Flags
if (isEbit || !isVU1) { // Clear 'is busy' Flags
AND32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, (isVU1 ? ~0x100 : ~0x001)); // VBS0/VBS1 flag
AND32ItoM((uptr)&mVU->regs->vifRegs->stat, ~0x4); // Clear VU 'is busy' signal for vif
}
//Save PC, and Jump to Exit Point
MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC].UL, xPC);
JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5));
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));
}
}
#define sI ((mVUpBlock->pState.needExactMatch & 0x000f) ? 0 : ((mVUpBlock->pState.flags >> 0) & 3))
#define cI ((mVUpBlock->pState.needExactMatch & 0x0f00) ? 0 : ((mVUpBlock->pState.flags >> 2) & 3))
void __fastcall mVUwarning0(u32 PC) { Console::Error("microVU0 Warning: Exiting from Possible Infinite Loop [%04x]", params PC); }
void __fastcall mVUwarning1(u32 PC) { Console::Error("microVU1 Warning: Exiting from Possible Infinite Loop [%04x]", params PC); }
void __fastcall mVUprintPC1(u32 PC) { Console::Write("Block PC [%04x] ", params PC); }
@ -250,7 +279,7 @@ microVUt(void) mVUtestCycles(mV) {
if (isVU1) CALLFunc((uptr)mVUwarning1);
//else CALLFunc((uptr)mVUwarning0); // VU0 is allowed early exit for COP2 Interlock Simulation
MOV32ItoR(gprR, Roffset); // Restore gprR
mVUendProgram(mVU, (isVU1)?1:0, 0, 0, sI, 0, cI);
mVUendProgram(mVU, 0, NULL, NULL, NULL);
x86SetJ32(jmp32);
}
@ -292,7 +321,6 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
mVUregs.flags = 0;
mVUflagInfo = 0;
mVUsFlagHack = CHECK_VU_FLAGHACK;
bool eBitBranch = 0; // E-bit Set on Branch
for (int branch = 0; mVUcount < (vuIndex ? (0x3fff/8) : (0xfff/8)); ) {
incPC(1);
@ -311,7 +339,7 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
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); branchEbit(); branch = 3; mVUbranch = 0; }
if (mVUbranch) { mVUsetFlagInfo(mVU); branch = 3; mVUbranch = 0; }
incPC(1);
mVUcount++;
}
@ -342,18 +370,18 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
mVUdebugNOW(1);
switch (mVUbranch) {
case 3: branchCase(JE32, JNE32); // IBEQ
case 4: branchCase(JGE32, JNGE32); // IBGEZ
case 5: branchCase(JG32, JNG32); // IBGTZ
case 6: branchCase(JLE32, JNLE32); // IBLEQ
case 7: branchCase(JL32, JNL32); // IBLTZ
case 8: branchCase(JNE32, JE32); // IBNEQ
case 3: branchCase(JE32, JNE32, JE8); // IBEQ
case 4: branchCase(JGE32, JNGE32, JGE8); // IBGEZ
case 5: branchCase(JG32, JNG32, JG8); // IBGTZ
case 6: branchCase(JLE32, JNLE32, JLE8); // IBLEQ
case 7: branchCase(JL32, JNL32, JL8); // IBLTZ
case 8: branchCase(JNE32, JE32, JNE8); // IBNEQ
case 1: case 2: // B/BAL
mVUprint("mVUcompile B/BAL");
incPC(-3); // Go back to branch opcode (to get branch imm addr)
if (eBitBranch) { iPC = branchAddr/4; goto eBitTemination; } // E-bit Was Set on Branch
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)
@ -368,6 +396,16 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
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);
JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5));
return thisPtr;
}
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
@ -375,8 +413,8 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
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 (!isVU1) CALLFunc((uptr)mVUcompileVU0); //(u32 startPC, uptr pState)
else CALLFunc((uptr)mVUcompileVU1);
if (!vuIndex) CALLFunc((uptr)mVUcompileVU0); //(u32 startPC, uptr pState)
else CALLFunc((uptr)mVUcompileVU1);
mVUrestoreRegs(mVU);
JMPR(gprT1); // Jump to rec-code address
return thisPtr;
@ -397,8 +435,7 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
}
else {
uptr jumpAddr;
u32 bPC = iPC; // mVUcompile can modify iPC, mVUregs, and mVUflagInfo, so back them up
u32 bFlagInfo = mVUflagInfo;
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
@ -406,7 +443,6 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
else mVUcompileVU1(xPC, (uptr)&mVUregs);
iPC = bPC;
mVUflagInfo = bFlagInfo;
incPC(-3); // Go back to branch opcode (to get branch imm addr)
if (!vuIndex) jumpAddr = (uptr)mVUcompileVU0(branchAddr, (uptr)&pBlock->pStateEnd);
else jumpAddr = (uptr)mVUcompileVU1(branchAddr, (uptr)&pBlock->pStateEnd);
@ -417,27 +453,8 @@ microVUf(void*) __fastcall mVUcompile(u32 startPC, uptr pState) {
}
if (x == (vuIndex?(0x3fff/8):(0xfff/8))) { Console::Error("microVU%d: Possible infinite compiling loop!", params vuIndex); }
eBitTemination:
mVUprint("mVUcompile ebit");
int lStatus = findFlagInst(xStatus, 0x7fffffff);
int lMac = findFlagInst(xMac, 0x7fffffff);
int lClip = findFlagInst(xClip, 0x7fffffff);
memset(&mVUinfo, 0, sizeof(mVUinfo));
mVUincCycles(mVU, 100); // Ensures Valid P/Q instances (And sets all cycle data to 0)
mVUcycles -= 100;
if (mVUinfo.doDivFlag) {
int flagReg;
getFlagReg(flagReg, lStatus);
AND32ItoR (flagReg, 0xfff3ffff);
OR32MtoR (flagReg, (uptr)&mVU->divFlag);
}
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
// Do E-bit end stuff here
mVUsetupRange(mVU, xPC - 8);
mVUendProgram(mVU, 1, mVU->q, mVU->p, lStatus, lMac, lClip);
// E-bit End
mVUendProgram(mVU, 1, xStatus, xMac, xClip);
return thisPtr;
}