mirror of https://github.com/PCSX2/pcsx2.git
microVU: Fixed linking on branch delays. There may still be some situations that don't work correctly, but i don't have any games which use it, have ammended console logging to inform us if the game is broken.
Fixes in this commit: -Evil Dead - Fistful of Boomstick - Now goes ingame and works right (needs software mode on gsdx to fix lighting) -Tony Hawk's Project 8 - Graphics are no correct. Like earlier TH games, you need Negative rounding to fix it all. -Mark of Kri - The game now has collision detection! Apparently before you'd get stuck on objects, now you can walk freely. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5561 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
a7c8da7578
commit
484065d0a8
|
@ -460,12 +460,21 @@ __ri int mVUbranchCheck(mV) {
|
|||
mVUlow.badBranch = 1;
|
||||
incPC(2);
|
||||
mVUlow.evilBranch = 1;
|
||||
mVUregs.blockType = 2;
|
||||
|
||||
if(mVUlow.branch == 2 || mVUlow.branch == 10) //Needs linking, we can only guess this if the next is not conditional
|
||||
{
|
||||
if(branchType <= 2 && branchType >= 9) //First branch is not conditional so we know what the link will be
|
||||
{ //So we can let the existing evil block do its thing! We know where to get the addr :)
|
||||
mVUregs.blockType = 2;
|
||||
} //Else it is conditional, so we need to do some nasty processing later in microVU_Branch.inl
|
||||
}
|
||||
else mVUregs.blockType = 2; //Second branch doesn't need linking, so can let it run its evil block course (MGS2 for testing)
|
||||
|
||||
mVUregs.needExactMatch |= 7; // This might not be necessary, but w/e...
|
||||
mVUregs.flagInfo = 0;
|
||||
mVUregs.fullFlags0 = 0;
|
||||
mVUregs.fullFlags1 = 0;
|
||||
DevCon.Warning("microVU%d: %s in %s delay slot! [%04x]", mVU.index,
|
||||
DevCon.Warning("microVU%d: %s in %s delay slot! [%04x] - If game broken report to PCSX2 Team", mVU.index,
|
||||
branchSTR[mVUlow.branch&0xf], branchSTR[branchType&0xf], xPC);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
extern bool doEarlyExit (microVU& mVU);
|
||||
extern void mVUincCycles(microVU& mVU, int x);
|
||||
extern void* mVUcompile (microVU& mVU, u32 startPC, uptr pState);
|
||||
|
||||
extern void* mVUcompileSingleInstruction(microVU& mVU, u32 startPC, uptr pState, microFlagCycles& mFC);
|
||||
__fi int getLastFlagInst(microRegInfo& pState, int* xFlag, int flagType, int isEbit) {
|
||||
if (isEbit) return findFlagInst(xFlag, 0x7fffffff);
|
||||
if (pState.needExactMatch & (1<<flagType)) return 3;
|
||||
|
@ -126,18 +126,76 @@ void normJumpCompile(mV, microFlagCycles& mFC, bool isEvilJump) {
|
|||
void normBranch(mV, microFlagCycles& mFC) {
|
||||
|
||||
// E-bit Branch
|
||||
if (mVUup.eBit) { iPC = branchAddr/4; mVUendProgram(mVU, &mFC, 1); return; }
|
||||
if (mVUup.eBit) { if(mVUlow.badBranch) DevCon.Warning("End on evil Unconditional branch! - Not implemented! - If game broken report to PCSX2 Team"); iPC = branchAddr/4; mVUendProgram(mVU, &mFC, 1); return; }
|
||||
|
||||
if(mVUlow.badBranch)
|
||||
{
|
||||
u32 badBranchAddr = branchAddr+8;
|
||||
incPC(3);
|
||||
if(mVUlow.branch == 2 || mVUlow.branch == 10) //Delay slot branch needs linking
|
||||
{
|
||||
DevCon.Warning("Found %s in delay slot, linking - If game broken report to PCSX2 Team", mVUlow.branch == 2 ? "BAL" : "JALR");
|
||||
xMOV(gprT3, badBranchAddr);
|
||||
xSHR(gprT3, 3);
|
||||
mVUallocVIb(mVU, gprT3, _It_);
|
||||
|
||||
}
|
||||
incPC(-3);
|
||||
}
|
||||
|
||||
// Normal Branch
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
normBranchCompile(mVU, branchAddr);
|
||||
}
|
||||
|
||||
//Messy handler warning!!
|
||||
//This handles JALR/BAL in the delay slot of a conditional branch. We do this because the normal handling
|
||||
//Doesn't seem to work properly, even if the link is made to the correct address, so we do it manually instead.
|
||||
//Normally EvilBlock handles all this stuff, but something to do with conditionals and links don't quite work right :/
|
||||
void condJumpProcessingEvil(mV, microFlagCycles& mFC, int JMPcc) {
|
||||
|
||||
u32 bPC = iPC-1; // mVUcompile can modify iPC, mVUpBlock, and mVUregs so back them up
|
||||
microBlock* pBlock = mVUpBlock;
|
||||
u32 badBranchAddr;
|
||||
iPC = bPC-2;
|
||||
setCode();
|
||||
badBranchAddr = branchAddr;
|
||||
|
||||
xCMP(ptr16[&mVU.branch], 0);
|
||||
|
||||
xForwardJump32 eJMP(xInvertCond((JccComparisonType)JMPcc));
|
||||
|
||||
mVUcompileSingleInstruction(mVU, badBranchAddr, (uptr)&mVUregs, mFC);
|
||||
|
||||
xMOV(gprT3, badBranchAddr+8);
|
||||
iPC = bPC;
|
||||
setCode();
|
||||
xSHR(gprT3, 3);
|
||||
mVUallocVIb(mVU, gprT3, _It_); //Link to branch addr + 8
|
||||
|
||||
normJumpCompile(mVU, mFC, true); //Compile evil branch, just in time!
|
||||
|
||||
eJMP.SetTarget();
|
||||
|
||||
incPC(2); // Point to delay slot of evil Branch (as the original branch isn't taken)
|
||||
mVUcompileSingleInstruction(mVU, xPC, (uptr)&mVUregs, mFC);
|
||||
|
||||
xMOV(gprT3, xPC);
|
||||
iPC = bPC;
|
||||
setCode();
|
||||
xSHR(gprT3, 3);
|
||||
mVUallocVIb(mVU, gprT3, _It_);
|
||||
|
||||
normJumpCompile(mVU, mFC, true); //Compile evil branch, just in time!
|
||||
|
||||
}
|
||||
void condBranch(mV, microFlagCycles& mFC, int JMPcc) {
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
xCMP(ptr16[&mVU.branch], 0);
|
||||
incPC(3);
|
||||
if (mVUup.eBit) { // Conditional Branch With E-Bit Set
|
||||
if(mVUlow.evilBranch) DevCon.Warning("End on evil branch! - Not implemented! - If game broken report to PCSX2 Team");
|
||||
|
||||
mVUendProgram(mVU, &mFC, 2);
|
||||
xForwardJump8 eJMP((JccComparisonType)JMPcc);
|
||||
incPC(1); // Set PC to First instruction of Non-Taken Side
|
||||
|
@ -151,6 +209,17 @@ void condBranch(mV, microFlagCycles& mFC, int JMPcc) {
|
|||
return;
|
||||
}
|
||||
else { // Normal Conditional Branch
|
||||
|
||||
if(mVUlow.evilBranch) //We are dealing with an evil evil block, so we need to process this slightly differently
|
||||
{
|
||||
|
||||
if(mVUlow.branch == 10 || mVUlow.branch == 2) //Evil branch is a jump of some measure
|
||||
{
|
||||
//Because of how it is linked, we need to make sure the target is recompiled if taken
|
||||
condJumpProcessingEvil(mVU, mFC, JMPcc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
microBlock* bBlock;
|
||||
incPC2(1); // Check if Branch Non-Taken Side has already been recompiled
|
||||
blockCreate(iPC/2);
|
||||
|
@ -190,7 +259,22 @@ void normJump(mV, microFlagCycles& mFC) {
|
|||
normBranchCompile(mVU, jumpAddr);
|
||||
return;
|
||||
}
|
||||
if(mVUlow.badBranch)
|
||||
{
|
||||
incPC(3);
|
||||
if(mVUlow.branch == 2 || mVUlow.branch == 10) //Delay slot BAL needs linking, only need to do BAL here, JALR done earlier
|
||||
{
|
||||
DevCon.Warning("Found %x in delay slot, linking - If game broken report to PCSX2 Team", mVUlow.branch == 2 ? "BAL" : "JALR");
|
||||
incPC(-2);
|
||||
mVUallocVIa(mVU, gprT1, _Is_);
|
||||
xADD(gprT1, 8);
|
||||
xSHR(gprT1, 3);
|
||||
incPC(2);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
|
||||
}
|
||||
incPC(-3);
|
||||
}
|
||||
if (mVUup.eBit) { // E-bit Jump
|
||||
mVUendProgram(mVU, &mFC, 2);
|
||||
xMOV(gprT1, ptr32[&mVU.branch]);
|
||||
|
|
|
@ -186,7 +186,8 @@ __ri void branchWarning(mV) {
|
|||
mVUlow.isNOP = 1;
|
||||
}
|
||||
else incPC(2);
|
||||
if (mVUinfo.isBdelay) { // Check if VI Reg Written to on Branch Delay Slot Instruction
|
||||
|
||||
if (mVUinfo.isBdelay && !mVUlow.evilBranch) { // Check if VI Reg Written to on Branch Delay Slot Instruction
|
||||
if (mVUlow.VI_write.reg && mVUlow.VI_write.used && !mVUlow.readFlags) {
|
||||
mVUlow.backupVI = 1;
|
||||
mVUregs.viBackUp = mVUlow.VI_write.reg;
|
||||
|
@ -420,6 +421,57 @@ __fi void mVUinitFirstPass(microVU& mVU, uptr pState, u8* thisPtr) {
|
|||
// Recompiler
|
||||
//------------------------------------------------------------------
|
||||
|
||||
//This bastardized function is used when a linked branch is in a conditional delay slot. It's messy, it's horrible, but it works.
|
||||
//Unfortunately linking the reg manually and using the normal evil block method seems to suck at this :/
|
||||
//If this is removed, test Evil Dead: Fistful of Boomstick (hangs going ingame), Mark of Kri (collision detection)
|
||||
//and Tony Hawks Project 8 (graphics are half missing, requires Negative rounding when working)
|
||||
void* mVUcompileSingleInstruction(microVU& mVU, u32 startPC, uptr pState, microFlagCycles& mFC) {
|
||||
|
||||
u8* thisPtr = x86Ptr;
|
||||
|
||||
// First Pass
|
||||
iPC = startPC / 4;
|
||||
|
||||
mVUbranch = 0;
|
||||
incPC(1);
|
||||
startLoop(mVU);
|
||||
|
||||
mVUincCycles(mVU, 1);
|
||||
mVUopU(mVU, 0);
|
||||
mVUcheckBadOp(mVU);
|
||||
if (curI & _Ebit_) { eBitPass1(mVU, branch); DevCon.Warning("E Bit on single instruction");}
|
||||
if (curI & _DTbit_) { branch = 4; DevCon.Warning("D Bit on single instruction");}
|
||||
if (curI & _Mbit_) { mVUup.mBit = 1; DevCon.Warning("M Bit on single instruction");}
|
||||
if (curI & _Ibit_) { mVUlow.isNOP = 1; mVUup.iBit = 1; DevCon.Warning("I Bit on single instruction");}
|
||||
else { incPC(-1); mVUopL(mVU, 0); incPC(1); }
|
||||
mVUsetCycles(mVU);
|
||||
mVUinfo.readQ = mVU.q;
|
||||
mVUinfo.writeQ = !mVU.q;
|
||||
mVUinfo.readP = mVU.p;
|
||||
mVUinfo.writeP = !mVU.p;
|
||||
mVUcount++;
|
||||
mVUsetFlagInfo(mVU);
|
||||
incPC(1);
|
||||
|
||||
|
||||
mVUsetFlags(mVU, mFC); // Sets Up Flag instances
|
||||
mVUoptimizePipeState(mVU); // Optimize the End Pipeline State for nicer Block Linking
|
||||
mVUdebugPrintBlocks(mVU,0);// Prints Start/End PC of blocks executed, for debugging...
|
||||
mVUtestCycles(mVU); // Update VU Cycles and Exit Early if Necessary
|
||||
|
||||
// Second Pass
|
||||
iPC = startPC / 4;
|
||||
setCode();
|
||||
|
||||
if (mVUup.mBit) { xOR(ptr32[&mVU.regs().flags], VUFLAG_MFLAGSET); }
|
||||
mVUexecuteInstruction(mVU);
|
||||
|
||||
mVUincCycles(mVU, 1); //Just incase the is XGKick
|
||||
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
|
||||
|
||||
return thisPtr;
|
||||
}
|
||||
|
||||
void* mVUcompile(microVU& mVU, u32 startPC, uptr pState) {
|
||||
|
||||
microFlagCycles mFC;
|
||||
|
@ -431,6 +483,7 @@ void* mVUcompile(microVU& mVU, u32 startPC, uptr pState) {
|
|||
mVUsetupRange(mVU, startPC, 1); // Setup Program Bounds/Range
|
||||
mVU.regAlloc->reset(); // Reset regAlloc
|
||||
mVUinitFirstPass(mVU, pState, thisPtr);
|
||||
mVUbranch = 0;
|
||||
for(int branch = 0; mVUcount < endCount; mVUcount++) {
|
||||
incPC(1);
|
||||
startLoop(mVU);
|
||||
|
@ -478,6 +531,7 @@ void* mVUcompile(microVU& mVU, u32 startPC, uptr pState) {
|
|||
mVUsetupRange(mVU, xPC, 0);
|
||||
mVUdebugPrintBlocks(mVU,1);
|
||||
incPC(-3); // Go back to branch opcode
|
||||
|
||||
switch (mVUlow.branch) {
|
||||
case 1: case 2: normBranch(mVU, mFC); return thisPtr; // B/BAL
|
||||
case 9: case 10: normJump (mVU, mFC); return thisPtr; // JR/JALR
|
||||
|
@ -502,7 +556,7 @@ void* mVUcompile(microVU& mVU, u32 startPC, uptr pState) {
|
|||
__fi void* mVUentryGet(microVU& mVU, microBlockManager* block, u32 startPC, uptr pState) {
|
||||
microBlock* pBlock = block->search((microRegInfo*)pState);
|
||||
if (pBlock) return pBlock->x86ptrStart;
|
||||
else return mVUcompile(mVU, startPC, pState);
|
||||
else { return mVUcompile(mVU, startPC, pState);}
|
||||
}
|
||||
|
||||
// Search for Existing Compiled Block (if found, return x86ptr; else, compile and return x86ptr)
|
||||
|
|
|
@ -1245,7 +1245,8 @@ void setBranchA(mP, int x, int _x_) {
|
|||
void condEvilBranch(mV, int JMPcc) {
|
||||
if (mVUlow.badBranch) {
|
||||
xMOV(ptr32[&mVU.branch], gprT1);
|
||||
xMOV(ptr32[&mVU.badBranch], branchAddrN);
|
||||
xMOV(ptr32[&mVU.badBranch], branchAddr);
|
||||
|
||||
xCMP(gprT1b, 0);
|
||||
xForwardJump8 cJMP((JccComparisonType)JMPcc);
|
||||
incPC(6); // Branch Not Taken Addr + 8
|
||||
|
@ -1277,10 +1278,14 @@ mVUop(mVU_BAL) {
|
|||
setBranchA(mX, 2, _It_);
|
||||
pass1 { mVUanalyzeNormBranch(mVU, _It_, 1); }
|
||||
pass2 {
|
||||
xMOV(gprT1, bSaveAddr);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddrN); }
|
||||
if (mVUlow.evilBranch) { xMOV(ptr32[&mVU.evilBranch], branchAddr); }
|
||||
if(!mVUlow.evilBranch)
|
||||
{
|
||||
xMOV(gprT1, bSaveAddr);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
}
|
||||
|
||||
if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddr); }
|
||||
if (mVUlow.evilBranch) { xMOV(ptr32[&mVU.evilBranch], branchAddr);}
|
||||
mVU.profiler.EmitOp(opBAL);
|
||||
}
|
||||
pass3 { mVUlog("BAL vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Ft_, branchAddr, branchAddr); }
|
||||
|
@ -1377,13 +1382,9 @@ void normJumpPass2(mV) {
|
|||
mVUallocVIa(mVU, gprT1, _Is_);
|
||||
xSHL(gprT1, 3);
|
||||
xAND(gprT1, mVU.microMemSize - 8);
|
||||
if (!mVUlow.evilBranch) xMOV(ptr32[&mVU.branch], gprT1);
|
||||
else xMOV(ptr32[&mVU.evilBranch], gprT1);
|
||||
if (mVUlow.badBranch) {
|
||||
xADD(gprT1, 8);
|
||||
xAND(gprT1, mVU.microMemSize - 8);
|
||||
xMOV(ptr32[&mVU.badBranch], gprT1);
|
||||
}
|
||||
|
||||
if (!mVUlow.evilBranch) xMOV(ptr32[&mVU.branch], gprT1);
|
||||
else { xMOV(ptr32[&mVU.evilBranch], gprT1);}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1399,8 +1400,27 @@ mVUop(mVU_JALR) {
|
|||
pass1 { mVUanalyzeJump(mVU, _Is_, _It_, 1); }
|
||||
pass2 {
|
||||
normJumpPass2(mVU);
|
||||
xMOV(gprT1, bSaveAddr);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
if(!mVUlow.evilBranch)
|
||||
{
|
||||
xMOV(gprT1, bSaveAddr);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
}
|
||||
if(mVUlow.evilBranch)
|
||||
{
|
||||
incPC(-2);
|
||||
if(mVUlow.branch >= 9) //Previous branch is a jump of some type so
|
||||
//we need to take the branch address from the register it uses.
|
||||
{
|
||||
DevCon.Warning("Linking JALR from JALR/JR branch target! - If game broken report to PCSX2 Team");
|
||||
mVUallocVIa(mVU, gprT1, _Is_);
|
||||
xADD(gprT1, 8);
|
||||
xSHR(gprT1, 3);
|
||||
incPC(2);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
}
|
||||
else incPC(2);
|
||||
}
|
||||
|
||||
mVU.profiler.EmitOp(opJALR);
|
||||
}
|
||||
pass3 { mVUlog("JALR vi%02d, [vi%02d]", _Ft_, _Fs_); }
|
||||
|
|
Loading…
Reference in New Issue