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.");