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
This commit is contained in:
cottonvibes 2009-08-18 00:17:09 +00:00
parent 4509e085c6
commit 9da4a53929
7 changed files with 67 additions and 58 deletions

View File

@ -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;
}

View File

@ -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>);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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")))