diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index c1684f96a5..a3590b8e60 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -243,6 +243,7 @@ struct microVU u32 branch; // Holds branch compare result (IBxx) OR Holds address to Jump to (JALR/JR) u32 badBranch; // For Branches in Branch Delay Slots, holds Address the first Branch went to + 8 u32 evilBranch; // For Branches in Branch Delay Slots, holds Address to Jump to + u32 evilevilBranch;// For Branches in Branch Delay Slots (chained), holds Address to Jump to u32 p; // Holds current P instance index u32 q; // Holds current Q instance index u32 totalCycles; // Total Cycles that mVU is expected to run for diff --git a/pcsx2/x86/microVU_Analyze.inl b/pcsx2/x86/microVU_Analyze.inl index 11392b452a..e903d304d7 100644 --- a/pcsx2/x86/microVU_Analyze.inl +++ b/pcsx2/x86/microVU_Analyze.inl @@ -584,9 +584,30 @@ static void analyzeBranchVI(mV, int xReg, bool& infoVar) // Branch in Branch Delay-Slots __ri int mVUbranchCheck(mV) { - if (!mVUcount) + if (!mVUcount && !isEvilBlock) return 0; + // This means we have jumped from an evil branch situation, so this is another branch in delay slot + if (isEvilBlock) + { + mVUlow.evilBranch = true; + mVUregs.blockType = 2; + mVUregs.needExactMatch |= 7; // This might not be necessary, but w/e... + mVUregs.flagInfo = 0; + + if (mVUlow.branch == 2 || mVUlow.branch == 10) + { + Console.Error("microVU%d: %s in branch, branch delay slot requires link [%04x] - If game broken report to PCSX2 Team", mVU.index, + branchSTR[mVUlow.branch & 0xf], xPC); + } + else + { + DevCon.Warning("microVU%d: %s in branch, branch delay slot! [%04x] - If game broken report to PCSX2 Team", mVU.index, + branchSTR[mVUlow.branch & 0xf], xPC); + } + return 1; + } + incPC(-2); if (mVUlow.branch) diff --git a/pcsx2/x86/microVU_Branch.inl b/pcsx2/x86/microVU_Branch.inl index 7b5d7ccfac..6027aac471 100644 --- a/pcsx2/x86/microVU_Branch.inl +++ b/pcsx2/x86/microVU_Branch.inl @@ -304,7 +304,11 @@ void normJumpCompile(mV, microFlagCycles& mFC, bool isEvilJump) } if (isEvilJump) + { xMOV(arg1regd, ptr32[&mVU.evilBranch]); + xMOV(gprT1, ptr32[&mVU.evilevilBranch]); + xMOV(ptr32[&mVU.evilBranch], gprT1); + } else xMOV(arg1regd, ptr32[&mVU.branch]); if (doJumpCaching) diff --git a/pcsx2/x86/microVU_Compile.inl b/pcsx2/x86/microVU_Compile.inl index 98fbda7013..2dc98ed027 100644 --- a/pcsx2/x86/microVU_Compile.inl +++ b/pcsx2/x86/microVU_Compile.inl @@ -903,13 +903,13 @@ void* mVUcompile(microVU& mVU, u32 startPC, uptr pState) mVU_XGKICK_DELAY(mVU); } - if (isEvilBlock && !isConditional) + if (isEvilBlock) { mVUsetupRange(mVU, xPC + 8, false); normJumpCompile(mVU, mFC, true); goto perf_and_return; } - else if (!mVUinfo.isBdelay && !isEvilBlock) + else if (!mVUinfo.isBdelay) { // Handle range wrapping if ((xPC + 8) == mVU.microMemSize) diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl index dd28730ea6..a38c481032 100644 --- a/pcsx2/x86/microVU_Lower.inl +++ b/pcsx2/x86/microVU_Lower.inl @@ -1756,16 +1756,30 @@ void condEvilBranch(mV, int JMPcc) cJMP.SetTarget(); return; } - xMOV(ptr32[&mVU.evilBranch], branchAddr(mVU)); - xCMP(gprT1b, 0); - xForwardJump8 cJMP((JccComparisonType)JMPcc); + if (isEvilBlock) + { + xMOV(ptr32[&mVU.evilevilBranch], branchAddr(mVU)); + xCMP(gprT1b, 0); + xForwardJump8 cJMP((JccComparisonType)JMPcc); + xMOV(gprT1, ptr32[&mVU.evilBranch]); // Branch Not Taken + xADD(gprT1, 8); // We have already executed 1 instruction from the original branch + xMOV(ptr32[&mVU.evilevilBranch], gprT1); + cJMP.SetTarget(); + } + else + { + xMOV(ptr32[&mVU.evilBranch], branchAddr(mVU)); + xCMP(gprT1b, 0); + xForwardJump8 cJMP((JccComparisonType)JMPcc); xMOV(gprT1, ptr32[&mVU.badBranch]); // Branch Not Taken + //xADD(gprT1, 8); // We have already executed 1 instruction from the original branch xMOV(ptr32[&mVU.evilBranch], gprT1); - cJMP.SetTarget(); - incPC(-2); - if (mVUlow.branch >= 9) - DevCon.Warning("Conditional in JALR/JR delay slot - If game broken report to PCSX2 Team"); - incPC(2); + cJMP.SetTarget(); + incPC(-2); + if (mVUlow.branch >= 9) + DevCon.Warning("Conditional in JALR/JR delay slot - If game broken report to PCSX2 Team"); + incPC(2); + } } mVUop(mVU_B) @@ -1774,8 +1788,8 @@ mVUop(mVU_B) pass1 { mVUanalyzeNormBranch(mVU, 0, false); } pass2 { - if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddrN(mVU)); } - if (mVUlow.evilBranch) { xMOV(ptr32[&mVU.evilBranch], branchAddr(mVU)); } + if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddr(mVU)); } + if (mVUlow.evilBranch) { if(isEvilBlock) xMOV(ptr32[&mVU.evilevilBranch], branchAddr(mVU)); else xMOV(ptr32[&mVU.evilBranch], branchAddr(mVU)); } mVU.profiler.EmitOp(opB); } pass3 { mVUlog("B [%04x]", branchAddr(mVU), branchAddr(mVU)); } @@ -1792,9 +1806,23 @@ mVUop(mVU_BAL) xMOV(gprT1, bSaveAddr); mVUallocVIb(mVU, gprT1, _It_); } + else + { + incPC(-2); + DevCon.Warning("Linking BAL from %s branch taken/nottaken target! - If game broken report to PCSX2 Team", branchSTR[mVUlow.branch & 0xf]); + incPC(2); + if (isEvilBlock) + xMOV(gprT1, ptr32[&mVU.evilBranch]); + else + xMOV(gprT1, ptr32[&mVU.badBranch]); - if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddrN(mVU)); } - if (mVUlow.evilBranch) { xMOV(ptr32[&mVU.evilBranch], branchAddr(mVU));} + xADD(gprT1, 8); + xSHR(gprT1, 3); + mVUallocVIb(mVU, gprT1, _It_); + } + + if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddr(mVU)); } + if (mVUlow.evilBranch) { if (isEvilBlock) xMOV(ptr32[&mVU.evilevilBranch], branchAddr(mVU)); else xMOV(ptr32[&mVU.evilBranch], branchAddr(mVU)); } mVU.profiler.EmitOp(opBAL); } pass3 { mVUlog("BAL vi%02d [%04x]", _Ft_, branchAddr(mVU), branchAddr(mVU)); } @@ -1946,7 +1974,10 @@ void normJumpPass2(mV) } else { - xMOV(ptr32[&mVU.evilBranch], gprT1); + if(isEvilBlock) + xMOV(ptr32[&mVU.evilevilBranch], gprT1); + else + xMOV(ptr32[&mVU.evilBranch], gprT1); } //If delay slot is conditional, it uses badBranch to go to its target if (mVUlow.badBranch) @@ -1983,18 +2014,35 @@ mVUop(mVU_JALR) } 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. + if (isEvilBlock) { - DevCon.Warning("Linking JALR from JALR/JR branch target! - If game broken report to PCSX2 Team"); - mVUallocVIa(mVU, gprT1, _Is_); + xMOV(gprT1, ptr32[&mVU.evilBranch]); xADD(gprT1, 8); xSHR(gprT1, 3); - incPC(2); mVUallocVIb(mVU, gprT1, _It_); } else - incPC(2); + { + 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 // Else we take the branch target of the previous branch + { + DevCon.Warning("Linking JALR from %d branch taken/nottaken target! - If game broken report to PCSX2 Team", branchSTR[mVUlow.branch & 0xf]); + xMOV(gprT1, ptr32[&mVU.badBranch]); + xADD(gprT1, 8); + xSHR(gprT1, 3); + incPC(2); + mVUallocVIb(mVU, gprT1, _It_); + } + } } mVU.profiler.EmitOp(opJALR); diff --git a/pcsx2/x86/microVU_Misc.inl b/pcsx2/x86/microVU_Misc.inl index 8d6f711f34..8db7f627d5 100644 --- a/pcsx2/x86/microVU_Misc.inl +++ b/pcsx2/x86/microVU_Misc.inl @@ -229,13 +229,6 @@ static void __fc mVUEBit() vu1Thread.mtvuInterrupts.fetch_or(VU_Thread::InterruptFlagVUEBit, std::memory_order_release); } -static inline u32 branchAddrN(const mV) -{ - pxAssumeDev(islowerOP, "MicroVU: Expected Lower OP code for valid branch addr."); - return ((((iPC + 4) + (_Imm11_ * 2)) & mVU.progMemMask) * 4); -} - - static inline u32 branchAddr(const mV) { pxAssumeDev(islowerOP, "MicroVU: Expected Lower OP code for valid branch addr.");