From 995b9d1eaa43be5e6dc2efbb028aa004525cecfc Mon Sep 17 00:00:00 2001 From: cottonvibes Date: Sat, 23 May 2009 03:27:53 +0000 Subject: [PATCH] microVU: - Implemented the case where an Unconditional branch has the E-bit Set. This solves a few games from getting stuck in infinite loops. (I still need to handle conditional branches and jumps). - Max/Mini Opcodes shouldn't set status/mac flags. This should be a minor speedup. - Minor Changes/Cleanups... git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1241 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/x86/microVU_Compile.inl | 42 ++++++++++++++++++++++------------- pcsx2/x86/microVU_Execute.inl | 7 ------ pcsx2/x86/microVU_Flags.inl | 2 +- pcsx2/x86/microVU_Lower.inl | 4 ++-- pcsx2/x86/microVU_Upper.inl | 31 +++++++++++++++----------- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/pcsx2/x86/microVU_Compile.inl b/pcsx2/x86/microVU_Compile.inl index 016dff7217..0857fd144a 100644 --- a/pcsx2/x86/microVU_Compile.inl +++ b/pcsx2/x86/microVU_Compile.inl @@ -41,6 +41,15 @@ } \ } +#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 startLoop() { mVUdebug1(); mVUstall = 0; memset(&mVUregsTemp, 0, sizeof(mVUregsTemp)); } #define calcCycles(reg, x) { reg = ((reg > x) ? (reg - x) : 0); } #define tCycles(dest, src) { dest = aMax(dest, src); } @@ -163,9 +172,7 @@ microVUt(void) mVUendProgram(int qInst, int pInst, int fStatus, int fMac, int fC MOV32RtoM((uptr)&mVU->regs->VI[REG_MAC_FLAG].UL, gprT1); MOV32RtoM((uptr)&mVU->regs->VI[REG_CLIP_FLAG].UL, gprT2); - //memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo)); - //MOV32ItoM((uptr)&mVU->prog.lpState, (int)&mVUblock.pState); // Save pipeline state (clipflag instance) - //AND32ItoM((uptr)µVU0.regs->VI[REG_VPU_STAT].UL, (vuIndex ? ~0x100 : ~0x001)); // VBS0/VBS1 flag + // Clear 'is busy' Flags, Save PC, and Jump to Exit Point AND32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, (vuIndex ? ~0x100 : ~0x001)); // VBS0/VBS1 flag AND32ItoM((uptr)&mVU->regs->vifRegs->stat, ~0x4); // Clear VU 'is busy' signal for vif MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC].UL, xPC); @@ -175,7 +182,8 @@ microVUt(void) mVUendProgram(int qInst, int pInst, int fStatus, int fMac, int fC #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 mVUwarning() { Console::Error("microVU Warning: Exiting Execution Early (Possible Infinite Loop)"); } +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); } microVUt(void) mVUtestCycles() { microVU* mVU = mVUx; @@ -183,7 +191,9 @@ microVUt(void) mVUtestCycles() { CMP32ItoM((uptr)&mVU->cycles, 0); u8* jmp8 = JG8(0); PUSH32R(gprR); - CALLFunc((uptr)mVUwarning); + MOV32ItoR(gprT2, xPC); + if (!vuIndex) CALLFunc((uptr)mVUwarning0); + else CALLFunc((uptr)mVUwarning1); POP32R(gprR); mVUendProgram(0, 0, sI, 0, cI); x86SetJ8(jmp8); @@ -224,9 +234,10 @@ microVUt(void*) __fastcall mVUcompile(u32 startPC, uptr pState) { 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; + mVUpBlock = pBlock; + mVUregs.flags = 0; + mVUflagInfo = 0; + bool eBitBranch = 0; // E-bit Set on Branch for (int branch = 0; mVUcount < (vuIndex ? (0x3fff/8) : (0xfff/8)); ) { incPC(1); @@ -235,7 +246,7 @@ microVUt(void*) __fastcall mVUcompile(u32 startPC, uptr pState) { startLoop(); mVUopU(); if (curI & _Ebit_) { branch = 1; } - if (curI & _MDTbit_) { branch = 2; } + if (curI & _MDTbit_) { branch = 4; } if (curI & _Ibit_) { mVUinfo |= _isNOP; } else { incPC(-1); mVUopL(); incPC(1); } mVUsetCycles(); @@ -244,7 +255,7 @@ microVUt(void*) __fastcall mVUcompile(u32 startPC, uptr pState) { else { mVUinfo |= _writeQ; } if (branch >= 2) { mVUinfo |= _isEOB | ((branch == 3) ? _isBdelay : 0); mVUcount++; branchWarning(); break; } else if (branch == 1) { branch = 2; } - if (mVUbranch) { mVUsetFlagInfo(); branch = 3; mVUbranch = 0; mVUinfo |= _isBranch; } + if (mVUbranch) { mVUsetFlagInfo(); branchEbit(); branch = 3; mVUbranch = 0; mVUinfo |= _isBranch; } incPC(1); mVUcount++; } @@ -253,10 +264,6 @@ microVUt(void*) __fastcall mVUcompile(u32 startPC, uptr pState) { int xStatus[4], xMac[4], xClip[4]; int xCycles = mVUsetFlags(xStatus, xMac, xClip); mVUtestCycles(); - //SysPrintf("bS[0] = %08x, bS[1] = %08x, bS[2] = %08x, bS[3] = %08x\n", bStatus[0], bStatus[1], bStatus[2], bStatus[3]); - //SysPrintf("bM[0] = %08x, bM[1] = %08x, bM[2] = %08x, bM[3] = %08x\n", bMac[0], bMac[1], bMac[2], bMac[3]); - //SysPrintf("mVUcount = %d\n", mVUcount); - //SysPrintf("mVUflagInfo = %d\n", mVUflagInfo); // Second Pass iPC = mVUstartPC; @@ -286,6 +293,8 @@ microVUt(void*) __fastcall mVUcompile(u32 startPC, uptr pState) { 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 mVUsetupBranch(xStatus, xMac, xClip, xCycles); if (mVUblocks[branchAddr/8] == NULL) @@ -347,10 +356,11 @@ microVUt(void*) __fastcall mVUcompile(u32 startPC, uptr pState) { return thisPtr; } } - mVUprint("mVUcompile ebit"); if (x == (vuIndex?(0x3fff/8):(0xfff/8))) { Console::Error("microVU%d: Possible infinite compiling loop!", params vuIndex); } +eBitTemination: + mVUprint("mVUcompile ebit"); incCycles(100); // Ensures Valid P/Q instances (And sets all cycle data to 0) mVUcycles -= 100; @@ -358,7 +368,7 @@ microVUt(void*) __fastcall mVUcompile(u32 startPC, uptr pState) { mVUsetupRange(xPC - 8); mVUendProgram(mVU->q, mVU->p, findFlagInst(xStatus, 0x7fffffff), findFlagInst(xMac, 0x7fffffff), findFlagInst(xClip, 0x7fffffff)); - return thisPtr; //ToDo: Save pipeline state? + return thisPtr; } void* __fastcall mVUcompileVU0(u32 startPC, uptr pState) { return mVUcompile<0>(startPC, pState); } diff --git a/pcsx2/x86/microVU_Execute.inl b/pcsx2/x86/microVU_Execute.inl index 37dd5dbea2..148e0fd0c5 100644 --- a/pcsx2/x86/microVU_Execute.inl +++ b/pcsx2/x86/microVU_Execute.inl @@ -23,8 +23,6 @@ // Dispatcher Functions //------------------------------------------------------------------ -void testFunction() { mVUprint("microVU: Entered Execution Mode"); } - // Generates the code for entering recompiled blocks microVUt(void) mVUdispatcherA() { microVU* mVU = mVUx; @@ -70,11 +68,6 @@ microVUt(void) mVUdispatcherA() { if (isMMX(i)) { MOVQMtoR(mmVI(i), (uptr)&mVU->regs->VI[i].UL); } } - //PUSH32R(EAX); - //CALLFunc((uptr)testFunction); - //write8(0xcc); - //POP32R(EAX); - // Jump to Recompiled Code Block JMPR(EAX); } diff --git a/pcsx2/x86/microVU_Flags.inl b/pcsx2/x86/microVU_Flags.inl index dd68d718b7..b513f8f89c 100644 --- a/pcsx2/x86/microVU_Flags.inl +++ b/pcsx2/x86/microVU_Flags.inl @@ -202,7 +202,7 @@ microVUt(void) mVUpass4(int startPC) { if (mVUbranch) { branch = 3; mVUbranch = 0; } incPC(1); } - //if (mVUcount == 4) { mVUflagInfo |= 0xfff; } // Is this Too Slow? 99% of games probably don't need this. + //if (mVUcount < 4) { mVUflagInfo |= 0xfff; } // Is this Too Slow? 99% of games probably don't need this. iPC = oldPC; mVUcount = oldCount; mVUbranch = oldBranch; diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl index 3880f57766..9a192c958f 100644 --- a/pcsx2/x86/microVU_Lower.inl +++ b/pcsx2/x86/microVU_Lower.inl @@ -590,8 +590,8 @@ microVUf(void) mVU_FSSET() { int flagReg1, flagReg2; getFlagReg(flagReg1, fsInstance); if (!(doStatus||doDivFlag)) { getFlagReg(flagReg2, fpsInstance); MOV32RtoR(flagReg1, flagReg2); } // Get status result from last status setting instruction - AND16ItoR(flagReg1, 0x03f); // Remember not to modify upper 16 bits because of mac flag - OR16ItoR (flagReg1, (_Imm12_ & 0xfc0)); + AND32ItoR(flagReg1, 0x03f); + OR32ItoR (flagReg1, (_Imm12_ & 0xfc0)); } pass3 { mVUlog("FSSET $%x", _Imm12_); } pass4 { mVUsFlagHack = 0; } diff --git a/pcsx2/x86/microVU_Upper.inl b/pcsx2/x86/microVU_Upper.inl index eb51cc2b42..37a92f8442 100644 --- a/pcsx2/x86/microVU_Upper.inl +++ b/pcsx2/x86/microVU_Upper.inl @@ -461,6 +461,11 @@ microVUt(void) mVUupdateFlags(int reg, int regT1, int regT2, int xyzw, bool modX pass3 { mVUlog(OPname); mVUlogACC(); mVUlogQ(); } \ } +// FMAC27~29 - MAX/MINI FMAC Opcodes +#define mVU_FMAC27(operation, OPname) { mVU_FMAC1 (operation, OPname); pass1 { microVU* mVU = mVUx; mVUinfo &= ~_doStatus; } } +#define mVU_FMAC28(operation, OPname) { mVU_FMAC6 (operation, OPname); pass1 { microVU* mVU = mVUx; mVUinfo &= ~_doStatus; } } +#define mVU_FMAC29(operation, OPname) { mVU_FMAC3 (operation, OPname); pass1 { microVU* mVU = mVUx; mVUinfo &= ~_doStatus; } } + //------------------------------------------------------------------ // Micro VU Micromode Upper instructions //------------------------------------------------------------------ @@ -546,21 +551,21 @@ microVUf(void) mVU_MSUBAx() { mVU_FMAC15(SUB, "MSUBAx"); } microVUf(void) mVU_MSUBAy() { mVU_FMAC15(SUB, "MSUBAy"); } microVUf(void) mVU_MSUBAz() { mVU_FMAC15(SUB, "MSUBAz"); } microVUf(void) mVU_MSUBAw() { mVU_FMAC15(SUB, "MSUBAw"); } -microVUf(void) mVU_MAX() { mVU_FMAC1 (MAX2, "MAX"); } -microVUf(void) mVU_MAXi() { mVU_FMAC6 (MAX2, "MAXi"); } -microVUf(void) mVU_MAXx() { mVU_FMAC3 (MAX2, "MAXx"); } -microVUf(void) mVU_MAXy() { mVU_FMAC3 (MAX2, "MAXy"); } -microVUf(void) mVU_MAXz() { mVU_FMAC3 (MAX2, "MAXz"); } -microVUf(void) mVU_MAXw() { mVU_FMAC3 (MAX2, "MAXw"); } -microVUf(void) mVU_MINI() { mVU_FMAC1 (MIN2, "MINI"); } -microVUf(void) mVU_MINIi() { mVU_FMAC6 (MIN2, "MINIi"); } -microVUf(void) mVU_MINIx() { mVU_FMAC3 (MIN2, "MINIx"); } -microVUf(void) mVU_MINIy() { mVU_FMAC3 (MIN2, "MINIy"); } -microVUf(void) mVU_MINIz() { mVU_FMAC3 (MIN2, "MINIz"); } -microVUf(void) mVU_MINIw() { mVU_FMAC3 (MIN2, "MINIw"); } +microVUf(void) mVU_MAX() { mVU_FMAC27(MAX2, "MAX"); } +microVUf(void) mVU_MAXi() { mVU_FMAC28(MAX2, "MAXi"); } +microVUf(void) mVU_MAXx() { mVU_FMAC29(MAX2, "MAXx"); } +microVUf(void) mVU_MAXy() { mVU_FMAC29(MAX2, "MAXy"); } +microVUf(void) mVU_MAXz() { mVU_FMAC29(MAX2, "MAXz"); } +microVUf(void) mVU_MAXw() { mVU_FMAC29(MAX2, "MAXw"); } +microVUf(void) mVU_MINI() { mVU_FMAC27(MIN2, "MINI"); } +microVUf(void) mVU_MINIi() { mVU_FMAC28(MIN2, "MINIi"); } +microVUf(void) mVU_MINIx() { mVU_FMAC29(MIN2, "MINIx"); } +microVUf(void) mVU_MINIy() { mVU_FMAC29(MIN2, "MINIy"); } +microVUf(void) mVU_MINIz() { mVU_FMAC29(MIN2, "MINIz"); } +microVUf(void) mVU_MINIw() { mVU_FMAC29(MIN2, "MINIw"); } microVUf(void) mVU_OPMULA() { mVU_FMAC18(MUL, "OPMULA"); } microVUf(void) mVU_OPMSUB() { mVU_FMAC19(SUB, "OPMSUB"); } -microVUf(void) mVU_NOP() { pass3 { mVUlog("NOP"); } } +microVUf(void) mVU_NOP() { pass3 { mVUlog("NOP"); } } microVUq(void) mVU_FTOIx(uptr addr) { microVU* mVU = mVUx; pass1 { mVUanalyzeFMAC2(_Fs_, _Ft_); }