Better fix for Dawn of Mana problem; solves the constant recompilation as well.

Basically:
If a block begins with an illegal instruction then don't continue recompiling the block, instead recompile code that prints an error message if block is taken at execution time, and then exit execution if it is.
Dawn of Mana has a conditional branch which leads to a bunch of illegal instructions, but the branch is never really taken at execution time.
The programmer either left this in for debugging, or possibly because real code is swapped in-place of the illegal instructions at a later time.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3263 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2010-06-22 03:08:30 +00:00
parent bd9606ab0b
commit 856968812a
3 changed files with 39 additions and 19 deletions

View File

@ -27,6 +27,17 @@
#define doUpperOp() { mVUopU(mVU, 1); mVUdivSet(mVU); }
#define doLowerOp() { incPC(-1); mVUopL(mVU, 1); incPC(1); }
//------------------------------------------------------------------
// Messages Called at Execution Time...
//------------------------------------------------------------------
void __fastcall mVUbadOp0(mV) { Console.Error("microVU0 Warning: Exiting... Block started with illegal opcode. [%04x] [%x]", xPC, mVU->prog.cur); }
void __fastcall mVUbadOp1(mV) { Console.Error("microVU1 Warning: Exiting... Block started with illegal opcode. [%04x] [%x]", xPC, mVU->prog.cur); }
void __fastcall mVUwarning0(mV) { Console.Error("microVU0 Warning: Exiting from Possible Infinite Loop [%04x] [%x]", xPC, mVU->prog.cur); }
void __fastcall mVUwarning1(mV) { Console.Error("microVU1 Warning: Exiting from Possible Infinite Loop [%04x] [%x]", xPC, mVU->prog.cur); }
void __fastcall mVUprintPC1(u32 PC) { Console.Write("Block PC [%04x] ", PC); }
void __fastcall mVUprintPC2(u32 PC) { Console.Write("[%04x]\n", PC); }
//------------------------------------------------------------------
// Helper Functions
//------------------------------------------------------------------
@ -44,7 +55,7 @@ _f void mVUcheckIsSame(mV) {
}
// Sets up microProgram PC ranges based on whats been recompiled
_f void mVUsetupRange(microVU* mVU, s32 pc, bool isStartPC) {
void mVUsetupRange(microVU* mVU, s32 pc, bool isStartPC) {
deque<microRange>*& ranges = mVUcurProg.ranges;
pc &= mVU->microMemSize - 8;
@ -103,7 +114,7 @@ _f void startLoop(mV) {
memzero(mVUregsTemp);
}
_f void doIbit(mV) {
void doIbit(mV) {
if (mVUup.iBit) {
incPC(-1);
u32 tempI;
@ -120,7 +131,7 @@ _f void doIbit(mV) {
}
}
_f void doSwapOp(mV) {
void doSwapOp(mV) {
if (mVUinfo.backupVF && !mVUlow.noWriteVF) {
DevCon.WriteLn(Color_Green, "microVU%d: Backing Up VF Reg [%04x]", getIndex, xPC);
int t1 = mVU->regAlloc->allocReg(mVUlow.VF_write.reg);
@ -143,6 +154,23 @@ _f void doSwapOp(mV) {
else { mVUopL(mVU, 1); incPC(1); doUpperOp(); }
}
// If 1st op in block is a bad opcode, then don't compile rest of block (Dawn of Mana Level 2)
_f void mVUcheckBadOp(mV) {
if (mVUinfo.isBadOp && mVUcount == 0) {
mVUinfo.isEOB = true;
Console.Warning("microVU Warning: First Instruction of block contains illegal opcode...");
}
}
// Prints msg when exiting block early if 1st op was a bad opcode (Dawn of Mana Level 2)
_f void handleBadOp(mV, int count) {
if (mVUinfo.isBadOp && count == 0) {
MOV32ItoR(gprT2, (uptr)mVU);
if (!isVU1) CALLFunc((uptr)mVUbadOp0);
else CALLFunc((uptr)mVUbadOp1);
}
}
_f void branchWarning(mV) {
incPC(-2);
if (mVUup.eBit && mVUbranch) {
@ -193,7 +221,7 @@ _f void mVUoptimizePipeState(mV) {
mVUregs.r = 0; // There are no stalls on the R-reg, so its Safe to discard info
}
_f void mVUincCycles(mV, int x) {
void mVUincCycles(mV, int x) {
mVUcycles += x;
for (int z = 31; z > 0; z--) {
calcCycles(mVUregs.VF[z].x, x);
@ -230,7 +258,7 @@ _f void mVUincCycles(mV, int x) {
} \
}
_f void mVUsetCycles(mV) {
void mVUsetCycles(mV) {
mVUincCycles(mVU, mVUstall);
// If upper Op && lower Op write to same VF reg:
if ((mVUregsTemp.VFreg[0] == mVUregsTemp.VFreg[1]) && mVUregsTemp.VFreg[0]) {
@ -265,11 +293,6 @@ _f void mVUsetCycles(mV) {
tCycles(mVUregs.xgkick, mVUregsTemp.xgkick);
}
void __fastcall mVUwarning0(mV) { Console.Error("microVU0 Warning: Exiting from Possible Infinite Loop [%04x] [%x]", xPC, mVU->prog.cur); }
void __fastcall mVUwarning1(mV) { Console.Error("microVU1 Warning: Exiting from Possible Infinite Loop [%04x] [%x]", xPC, mVU->prog.cur); }
void __fastcall mVUprintPC1(u32 PC) { Console.Write("Block PC [%04x] ", PC); }
void __fastcall mVUprintPC2(u32 PC) { Console.Write("[%04x]\n", PC); }
// vu0 is allowed to exit early, so are dev builds (for inf loops)
_f bool doEarlyExit(microVU* mVU) {
return IsDevBuild || !isVU1;
@ -283,7 +306,7 @@ _f void mVUsavePipelineState(microVU* mVU) {
}
}
_f void mVUtestCycles(microVU* mVU) {
void mVUtestCycles(microVU* mVU) {
//u32* vu0jmp;
iPC = mVUstartPC;
mVUdebugNOW(0);
@ -356,6 +379,7 @@ _r void* mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
startLoop(mVU);
mVUincCycles(mVU, 1);
mVUopU(mVU, 0);
mVUcheckBadOp(mVU);
if (curI & _Ebit_) { eBitPass1(mVU, branch); }
if (curI & _DTbit_) { branch = 4; }
if (curI & _Mbit_) { mVUup.mBit = 1; }
@ -385,7 +409,7 @@ _r void* mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
mVUbranch = 0;
u32 x = 0;
for (; x < endCount; x++) {
if (mVUinfo.isEOB) { x = 0xffff; }
if (mVUinfo.isEOB) { handleBadOp(mVU, x); x = 0xffff; }
if (mVUup.mBit) { OR32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET); }
if (mVUlow.isNOP) { incPC(1); doUpperOp(); doIbit(mVU); }
else if (!mVUinfo.swapOps) { incPC(1); doUpperOp(); doLowerOp(); }

View File

@ -126,6 +126,7 @@ struct microFlagCycles {
struct microOp {
u8 stall; // Info on how much current instruction stalled
bool isBadOp; // Cur Instruction is a bad opcode (not a legal instruction)
bool isEOB; // Cur Instruction is last instruction in block (End of Block)
bool isBdelay; // Cur Instruction in Branch Delay slot
bool swapOps; // Run Lower Instruction before Upper Instruction

View File

@ -211,13 +211,8 @@ mVUop(mVULowerOP_T3_11) { mVULowerOP_T3_11_OPCODE [((mVU->code >> 6) & 0x1f)](mX
mVUop(mVUopU) { mVU_UPPER_OPCODE [ (mVU->code & 0x3f) ](mX); } // Gets Upper Opcode
mVUop(mVUopL) { mVULOWER_OPCODE [ (mVU->code >> 25) ](mX); } // Gets Lower Opcode
mVUop(mVUunknown) {
pass2 {
if (!IsDevBuild) { // Dawn Of Mana Level 2 spams this slowing down the game; but game is fine
static int UnknownOpCount = 0;
if (UnknownOpCount++ >= 5) return;
}
Console.Error("microVU%d: Unknown Micro VU opcode called (%x) [%04x]\n", getIndex, mVU->code, xPC);
}
pass1 { mVUinfo.isBadOp = true; }
pass2 { Console.Error("microVU%d: Unknown Micro VU opcode called (%x) [%04x]\n", getIndex, mVU->code, xPC); }
pass3 { mVUlog("Unknown", mVU->code); }
}