From 9da4a53929bc3ac137f661c72486c9a16b9f8baa Mon Sep 17 00:00:00 2001 From: cottonvibes Date: Tue, 18 Aug 2009 00:17:09 +0000 Subject: [PATCH] microVU: Now properly supports E-bit set on branch delay slot instructions. (Gets rid of "Unknown Micro VU opcode called" errors in Dark Cloud 2, and possibly fixes some other games) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1647 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/x86/microVU.h | 1 + pcsx2/x86/microVU_Branch.inl | 16 ++++----- pcsx2/x86/microVU_Compile.inl | 68 +++++++++++++++++++---------------- pcsx2/x86/microVU_Flags.inl | 10 +++--- pcsx2/x86/microVU_IR.h | 3 +- pcsx2/x86/microVU_Lower.inl | 20 +++++------ pcsx2/x86/microVU_Misc.h | 7 ++-- 7 files changed, 67 insertions(+), 58 deletions(-) diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index 38b15cce9d..db7063f98e 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -89,6 +89,7 @@ public: && (linkI->block->pState.flags == pState->flags) && (linkI->block->pState.xgkick == pState->xgkick) && (linkI->block->pState.viBackUp == pState->viBackUp) + && (linkI->block->pState.blockType == pState->blockType) && !(linkI->block->pState.needExactMatch & 5)) { return linkI->block; } linkI = linkI->next; } diff --git a/pcsx2/x86/microVU_Branch.inl b/pcsx2/x86/microVU_Branch.inl index b081222006..27dc66bf37 100644 --- a/pcsx2/x86/microVU_Branch.inl +++ b/pcsx2/x86/microVU_Branch.inl @@ -108,7 +108,7 @@ void normBranch(mV, microFlagCycles& mFC) { normBranchCompile(mVU, branchAddr); } -void condBranch(mV, microFlagCycles& mFC, microBlock* &pBlock, int JMPcc) { +void condBranch(mV, microFlagCycles& mFC, int JMPcc) { using namespace x86Emitter; mVUsetupBranch(mVU, mFC); xCMP(ptr16[&mVU->branch], 0); @@ -138,8 +138,8 @@ void condBranch(mV, microFlagCycles& mFC, microBlock* &pBlock, int JMPcc) { } else { s32* ajmp = xJcc32((JccComparisonType)JMPcc); - uptr jumpAddr; - u32 bPC = iPC; // mVUcompile can modify iPC and mVUregs so back them up + u32 bPC = iPC; // mVUcompile can modify iPC, mVUpBlock, and mVUregs so back them up + microBlock* pBlock = mVUpBlock; memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo)); incPC2(1); // Get PC for branch not-taken @@ -147,13 +147,13 @@ void condBranch(mV, microFlagCycles& mFC, microBlock* &pBlock, int JMPcc) { iPC = bPC; incPC(-3); // Go back to branch opcode (to get branch imm addr) - jumpAddr = (uptr)mVUblockFetch(mVU, branchAddr, (uptr)&pBlock->pStateEnd); + uptr jumpAddr = (uptr)mVUblockFetch(mVU, branchAddr, (uptr)&pBlock->pStateEnd); *ajmp = (jumpAddr - ((uptr)ajmp + 4)); } } } -void normJump(mV, microFlagCycles& mFC, microBlock* &pBlock) { +void normJump(mV, microFlagCycles& mFC) { using namespace x86Emitter; mVUprint("mVUcompile JR/JALR"); incPC(-3); // Go back to jump opcode @@ -178,12 +178,12 @@ void normJump(mV, microFlagCycles& mFC, microBlock* &pBlock) { return; } - memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo)); + memcpy_fast(&mVUpBlock->pStateEnd, &mVUregs, sizeof(microRegInfo)); mVUsetupBranch(mVU, mFC); mVUbackupRegs(mVU); - MOV32MtoR(gprT2, (uptr)&mVU->branch); // Get startPC (ECX 1st argument for __fastcall) - MOV32ItoR(gprR, (u32)&pBlock->pStateEnd); // Get pState (EDX 2nd argument for __fastcall) + MOV32MtoR(gprT2, (uptr)&mVU->branch); // Get startPC (ECX 1st argument for __fastcall) + MOV32ItoR(gprR, (u32)&mVUpBlock->pStateEnd); // Get pState (EDX 2nd argument for __fastcall) if (!mVU->index) xCALL(mVUcompileJIT<0>); //(u32 startPC, uptr pState) else xCALL(mVUcompileJIT<1>); diff --git a/pcsx2/x86/microVU_Compile.inl b/pcsx2/x86/microVU_Compile.inl index 79ceb701b3..e01f7727ca 100644 --- a/pcsx2/x86/microVU_Compile.inl +++ b/pcsx2/x86/microVU_Compile.inl @@ -170,10 +170,19 @@ microVUt(void) branchWarning(mV) { } } -microVUt(void) eBitWarning(mV) { +microVUt(void) eBitPass1(mV, int& branch) { + if (!mVUregs.blockType) { + branch = 1; + mVUup.eBit = 1; + } +} + +microVUt(void) eBitWarning(mV, u32 endCount) { + if (endCount == 1) Console::Error("microVU%d Warning: Branch, E-bit, Branch! [%04x]", params mVU->index, xPC); incPC(2); if (curI & _Ebit_) { - Console::Error("microVU%d Warning: E-bit in Branch delay slot! [%04x]", params mVU->index, xPC); + DevCon::Status("microVU%d: E-bit in Branch delay slot! [%04x]", params mVU->index, xPC); + mVUregs.blockType = 1; } incPC(-2); } @@ -297,21 +306,21 @@ microVUt(void) mVUinitConstValues(microVU* mVU) { } // Initialize Variables -microVUt(void) mVUinitFirstPass(microVU* mVU, microBlock* &pBlock, uptr pState, u8* thisPtr) { - mVUstartPC = iPC; // Block Start PC - mVUbranch = 0; // Branch Type - mVUcount = 0; // Number of instructions ran - 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 +microVUt(void) mVUinitFirstPass(microVU* mVU, uptr pState, u8* thisPtr) { + mVUstartPC = iPC; // Block Start PC + mVUbranch = 0; // Branch Type + mVUcount = 0; // Number of instructions ran + 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[mVUstartPC/2]->add(&mVUblock); // Add this block to block manager - mVUpBlock = pBlock; - mVUregs.viBackUp= 0; - mVUregs.flags = 0; - mVUflagInfo = 0; - mVUsFlagHack = CHECK_VU_FLAGHACK; + mVUblock.x86ptrStart = thisPtr; + mVUpBlock = mVUblocks[mVUstartPC/2]->add(&mVUblock); // Add this block to block manager + mVUregs.blockType = 0; + mVUregs.viBackUp = 0; + mVUregs.flags = 0; + mVUregs.needExactMatch = 0; + mVUsFlagHack = CHECK_VU_FLAGHACK; mVUinitConstValues(mVU); } @@ -323,22 +332,21 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) { using namespace x86Emitter; microFlagCycles mFC; - microBlock* pBlock = NULL; u8* thisPtr = x86Ptr; - const u32 endCount = (mVU->microMemSize / 8) - 1; + const u32 endCount = (((microRegInfo*)pState)->blockType) ? 1 : (mVU->microMemSize / 8); // First Pass iPC = startPC / 4; mVUsetupRange(mVU, startPC, 1); // Setup Program Bounds/Range mVU->regAlloc->reset(); // Reset regAlloc - mVUinitFirstPass(mVU, pBlock, pState, thisPtr); + mVUinitFirstPass(mVU, pState, thisPtr); for (int branch = 0; mVUcount < endCount; mVUcount++) { incPC(1); startLoop(mVU); mVUincCycles(mVU, 1); mVUopU(mVU, 0); - if (curI & _Ebit_) { branch = 1; mVUup.eBit = 1; } + if (curI & _Ebit_) { eBitPass1(mVU, branch); } if (curI & _DTbit_) { branch = 4; } if (curI & _Mbit_) { mVUup.mBit = 1; } if (curI & _Ibit_) { mVUlow.isNOP = 1; mVUup.iBit = 1; } @@ -350,7 +358,7 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) { mVUinfo.writeP = !mVU->p; if (branch >= 2) { mVUinfo.isEOB = 1; if (branch == 3) { mVUinfo.isBdelay = 1; } mVUcount++; branchWarning(mVU); break; } else if (branch == 1) { branch = 2; } - if (mVUbranch) { mVUsetFlagInfo(mVU); eBitWarning(mVU); branch = 3; mVUbranch = 0; } + if (mVUbranch) { mVUsetFlagInfo(mVU); eBitWarning(mVU, endCount); branch = 3; mVUbranch = 0; } incPC(1); } @@ -379,18 +387,18 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) { mVUsetupRange(mVU, xPC, 0); mVUdebugNOW(1); switch (mVUbranch) { - case 3: condBranch(mVU, mFC, pBlock, Jcc_Equal); return thisPtr; // IBEQ - case 4: condBranch(mVU, mFC, pBlock, Jcc_GreaterOrEqual); return thisPtr; // IBGEZ - case 5: condBranch(mVU, mFC, pBlock, Jcc_Greater); return thisPtr; // IBGTZ - case 6: condBranch(mVU, mFC, pBlock, Jcc_LessOrEqual); return thisPtr; // IBLEQ - case 7: condBranch(mVU, mFC, pBlock, Jcc_Less); return thisPtr; // IBLTZ - case 8: condBranch(mVU, mFC, pBlock, Jcc_NotEqual); return thisPtr; // IBNEQ - case 1: case 2: normBranch(mVU, mFC); return thisPtr; // B/BAL - case 9: case 10: normJump (mVU, mFC, pBlock); return thisPtr; // JR/JALR + case 1: case 2: normBranch(mVU, mFC); return thisPtr; // B/BAL + case 9: case 10: normJump (mVU, mFC); return thisPtr; // JR/JALR + case 3: condBranch(mVU, mFC, Jcc_Equal); return thisPtr; // IBEQ + case 4: condBranch(mVU, mFC, Jcc_GreaterOrEqual); return thisPtr; // IBGEZ + case 5: condBranch(mVU, mFC, Jcc_Greater); return thisPtr; // IBGTZ + case 6: condBranch(mVU, mFC, Jcc_LessOrEqual); return thisPtr; // IBLEQ + case 7: condBranch(mVU, mFC, Jcc_Less); return thisPtr; // IBLTZ + case 8: condBranch(mVU, mFC, Jcc_NotEqual); return thisPtr; // IBNEQ } } } - if (x == endCount) { Console::Error("microVU%d: Possible infinite compiling loop!", params mVU->index); } + if ((x == endCount) && (x!=1)) { Console::Error("microVU%d: Possible infinite compiling loop!", params mVU->index); } // E-bit End mVUsetupRange(mVU, xPC-8, 0); diff --git a/pcsx2/x86/microVU_Flags.inl b/pcsx2/x86/microVU_Flags.inl index f2c0d1e15c..ddc58d5fe0 100644 --- a/pcsx2/x86/microVU_Flags.inl +++ b/pcsx2/x86/microVU_Flags.inl @@ -248,7 +248,7 @@ void mVUflagPass(mV, u32 startPC, u32 xCount) { if (mVUbranch) { branch = ((mVUbranch>8)?(5):((mVUbranch<3)?3:4)); aBranchAddr = branchAddr; mVUbranch = 0; } incPC(1); } - if (mVUcount < 4) { mVUflagInfo |= 0x7; } + if (mVUcount < 4) { mVUregs.needExactMatch |= 0x7; } iPC = oldPC; mVUcount = oldCount; mVUbranch = oldBranch; @@ -263,18 +263,18 @@ void mVUflagPass(mV, u32 startPC, u32 xCount) { microVUt(void) mVUsetFlagInfo(mV) { branchType1 { incPC(-1); mVUflagPass(mVU, branchAddr, 4); incPC(1); } branchType2 { - if (!mVUlow.constJump.isValid) { mVUflagInfo |= 0x7; } + if (!mVUlow.constJump.isValid) { mVUregs.needExactMatch |= 0x7; } else { mVUflagPass(mVU, (mVUlow.constJump.regValue*8)&(mVU->microMemSize-8), 4); } } branchType3 { incPC(-1); mVUflagPass(mVU, branchAddr, 4); - int backupFlagInfo = mVUflagInfo; - mVUflagInfo = 0; + int backupFlagInfo = mVUregs.needExactMatch; + mVUregs.needExactMatch = 0; incPC(4); // Branch Not Taken mVUflagPass(mVU, xPC, 4); incPC(-3); - mVUflagInfo |= backupFlagInfo; + mVUregs.needExactMatch |= backupFlagInfo; } } diff --git a/pcsx2/x86/microVU_IR.h b/pcsx2/x86/microVU_IR.h index 70a9cc3548..9ace1ed3f5 100644 --- a/pcsx2/x86/microVU_IR.h +++ b/pcsx2/x86/microVU_IR.h @@ -44,7 +44,8 @@ __declspec(align(16)) struct microRegInfo { // Ordered for Faster Compares u8 VI[16]; regInfo VF[32]; u8 flags; // clip x2 :: status x2 - u8 padding[6]; // 160 bytes + u8 blockType; // 0 = Normal; 1 = Compile one instruction with E-bit termination + u8 padding[5]; // 160 bytes #if defined(_MSC_VER) }; #else diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl index 621f58b451..1f696e4dc3 100644 --- a/pcsx2/x86/microVU_Lower.inl +++ b/pcsx2/x86/microVU_Lower.inl @@ -458,7 +458,7 @@ mVUop(mVU_FCAND) { mVUallocVIb(mVU, gprT1, 1); } pass3 { mVUlog("FCAND vi01, $%x", _Imm24_); } - pass4 { mVUflagInfo |= 4; } + pass4 { mVUregs.needExactMatch |= 4; } } mVUop(mVU_FCEQ) { @@ -471,7 +471,7 @@ mVUop(mVU_FCEQ) { mVUallocVIb(mVU, gprT1, 1); } pass3 { mVUlog("FCEQ vi01, $%x", _Imm24_); } - pass4 { mVUflagInfo |= 4; } + pass4 { mVUregs.needExactMatch |= 4; } } mVUop(mVU_FCGET) { @@ -482,7 +482,7 @@ mVUop(mVU_FCGET) { mVUallocVIb(mVU, gprT1, _It_); } pass3 { mVUlog("FCGET vi%02d", _Ft_); } - pass4 { mVUflagInfo |= 4; } + pass4 { mVUregs.needExactMatch |= 4; } } mVUop(mVU_FCOR) { @@ -495,7 +495,7 @@ mVUop(mVU_FCOR) { mVUallocVIb(mVU, gprT1, 1); } pass3 { mVUlog("FCOR vi01, $%x", _Imm24_); } - pass4 { mVUflagInfo |= 4; } + pass4 { mVUregs.needExactMatch |= 4; } } mVUop(mVU_FCSET) { @@ -520,7 +520,7 @@ mVUop(mVU_FMAND) { mVUallocVIb(mVU, gprT1, _It_); } pass3 { mVUlog("FMAND vi%02d, vi%02d", _Ft_, _Fs_); } - pass4 { mVUflagInfo |= 2; } + pass4 { mVUregs.needExactMatch |= 2; } } mVUop(mVU_FMEQ) { @@ -534,7 +534,7 @@ mVUop(mVU_FMEQ) { mVUallocVIb(mVU, gprT1, _It_); } pass3 { mVUlog("FMEQ vi%02d, vi%02d", _Ft_, _Fs_); } - pass4 { mVUflagInfo |= 2; } + pass4 { mVUregs.needExactMatch |= 2; } } mVUop(mVU_FMOR) { @@ -546,7 +546,7 @@ mVUop(mVU_FMOR) { mVUallocVIb(mVU, gprT1, _It_); } pass3 { mVUlog("FMOR vi%02d, vi%02d", _Ft_, _Fs_); } - pass4 { mVUflagInfo |= 2; } + pass4 { mVUregs.needExactMatch |= 2; } } //------------------------------------------------------------------ @@ -561,7 +561,7 @@ mVUop(mVU_FSAND) { mVUallocVIb(mVU, gprT1, _It_); } pass3 { mVUlog("FSAND vi%02d, $%x", _Ft_, _Imm12_); } - pass4 { mVUflagInfo |= 1; } + pass4 { mVUregs.needExactMatch |= 1; } } mVUop(mVU_FSOR) { @@ -572,7 +572,7 @@ mVUop(mVU_FSOR) { mVUallocVIb(mVU, gprT1, _It_); } pass3 { mVUlog("FSOR vi%02d, $%x", _Ft_, _Imm12_); } - pass4 { mVUflagInfo |= 1; } + pass4 { mVUregs.needExactMatch |= 1; } } mVUop(mVU_FSEQ) { @@ -604,7 +604,7 @@ mVUop(mVU_FSEQ) { mVUallocVIb(mVU, gprT1, _It_); } pass3 { mVUlog("FSEQ vi%02d, $%x", _Ft_, _Imm12_); } - pass4 { mVUflagInfo |= 1; } + pass4 { mVUregs.needExactMatch |= 1; } } mVUop(mVU_FSSET) { diff --git a/pcsx2/x86/microVU_Misc.h b/pcsx2/x86/microVU_Misc.h index 6ae6b3c397..01985cc55f 100644 --- a/pcsx2/x86/microVU_Misc.h +++ b/pcsx2/x86/microVU_Misc.h @@ -205,7 +205,6 @@ typedef u32 (__fastcall *mVUCall)(void*, void*); #define sFLAG mVUinfo.sFlag #define mFLAG mVUinfo.mFlag #define cFLAG mVUinfo.cFlag -#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] @@ -222,9 +221,9 @@ typedef u32 (__fastcall *mVUCall)(void*, void*); #define shuffleSS(x) ((x==1)?(0x27):((x==2)?(0xc6):((x==4)?(0xe1):(0xe4)))) // Flag Info -#define __Status (mVUflagInfo & 1) -#define __Mac (mVUflagInfo & 2) -#define __Clip (mVUflagInfo & 4) +#define __Status (mVUregs.needExactMatch & 1) +#define __Mac (mVUregs.needExactMatch & 2) +#define __Clip (mVUregs.needExactMatch & 4) // Pass 3 Helper Macros #define _Fsf_String ((_Fsf_ == 3) ? "w" : ((_Fsf_ == 2) ? "z" : ((_Fsf_ == 1) ? "y" : "x")))