diff --git a/pcsx2/x86/microVU_Analyze.inl b/pcsx2/x86/microVU_Analyze.inl index 27b57457d21494..64f866f66d2ab2 100644 --- a/pcsx2/x86/microVU_Analyze.inl +++ b/pcsx2/x86/microVU_Analyze.inl @@ -228,7 +228,7 @@ __fi void mVUanalyzeIALU2(mV, int Is, int It) __fi void mVUanalyzeIADDI(mV, int Is, int It, s16 imm) { mVUanalyzeIALU2(mVU, Is, It); - if (!Is) + if (!Is && !EmuConfig.Gamefixes.IbitHack) { setConstReg(It, imm); } diff --git a/pcsx2/x86/microVU_Compile.inl b/pcsx2/x86/microVU_Compile.inl index a345fe5ad4b50d..1771dbd4e121e4 100644 --- a/pcsx2/x86/microVU_Compile.inl +++ b/pcsx2/x86/microVU_Compile.inl @@ -744,12 +744,27 @@ void* mVUcompile(microVU& mVU, u32 startPC, uptr pState) { mVUsetupRange(mVU, xPC, false); if (branch < 2) - mVUsetupRange(mVU, xPC + 8, true); // Ideally we'd do +4 but the mmx compare only works in 64bits, this should be fine + mVUsetupRange(mVU, xPC + 4, true); } } else { incPC(-1); + if (EmuConfig.Gamefixes.IbitHack) + { + // Ignore IADDI, IADDIU and ISUBU, ILW, ISW, LQ, SQ. + // Be wared, this is a little risky as we could be ignoring subtle differences in the operations. + // 2 is too much, 1 is too little, so it gets 2. It's a hack anyways... + const u32 upper = (mVU.code >> 25); + if (upper == 0x1 || upper == 0x0 || upper == 0x4 || upper == 0x5 || upper == 0x8 || upper == 0x9 || (upper == 0x40 && (mVU.code & 0x3F) == 0x32)) + { + incPC(1); + mVUsetupRange(mVU, xPC, false); + if (branch < 2) + mVUsetupRange(mVU, xPC + 2, true); + incPC(-1); + } + } mVUopL(mVU, 0); incPC(1); } diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl index da4405e0a0acdf..1b81b78d7501b6 100644 --- a/pcsx2/x86/microVU_Lower.inl +++ b/pcsx2/x86/microVU_Lower.inl @@ -858,17 +858,50 @@ mVUop(mVU_IADDI) if (_Is_ == 0) { const xRegister32& regT = mVU.regAlloc->allocGPR(-1, _It_, mVUlow.backupVI); - if (_Imm5_ != 0) - xMOV(regT, _Imm5_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm5_ != 0) + xMOV(regT, _Imm5_); + else + xXOR(regT, regT); + } else - xXOR(regT, regT); + { + xMOV(gprT1, ptr32[&curI]); + xSHR(gprT1, 6); + xAND(gprT1, 0x1F); + xTEST(gprT1, 0x10); + + xForwardJZ32 skipExtend; + xOR(gprT1, 0xFFF0); + skipExtend.SetTarget(); + + xMOVSX(regT, xRegister16(gprT1)); + } mVU.regAlloc->clearNeeded(regT); } else { const xRegister32& regS = mVU.regAlloc->allocGPR(_Is_, _It_, mVUlow.backupVI); - if (_Imm5_ != 0) - xADD(regS, _Imm5_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm5_ != 0) + xADD(regS, _Imm5_); + } + else + { + xMOV(gprT1, ptr32[&curI]); + xSHR(gprT1, 6); + xAND(gprT1, 0x1F); + xTEST(gprT1, 0x10); + + xForwardJZ32 skipExtend; + xOR(gprT1, 0xFFF0); + xMOVSX(gprT1, xRegister16(gprT1)); + skipExtend.SetTarget(); + + xADD(regS, gprT1); + } mVU.regAlloc->clearNeeded(regS); } mVU.profiler.EmitOp(opIADDI); @@ -884,17 +917,43 @@ mVUop(mVU_IADDIU) if (_Is_ == 0) { const xRegister32& regT = mVU.regAlloc->allocGPR(-1, _It_, mVUlow.backupVI); - if (_Imm15_ != 0) - xMOV(regT, _Imm15_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm15_ != 0) + xMOV(regT, _Imm15_); + else + xXOR(regT, regT); + } else - xXOR(regT, regT); + { + xMOV(regT, ptr32[&curI]); + xMOV(gprT1, regT); + xSHR(gprT1, 10); + xAND(gprT1, 0x7800); + xAND(regT, 0x7FF); + xOR(regT, gprT1); + } mVU.regAlloc->clearNeeded(regT); } else { const xRegister32& regS = mVU.regAlloc->allocGPR(_Is_, _It_, mVUlow.backupVI); - if (_Imm15_ != 0) - xADD(regS, _Imm15_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm15_ != 0) + xADD(regS, _Imm15_); + } + else + { + xMOV(gprT1, ptr32[&curI]); + xMOV(gprT2, gprT1); + xSHR(gprT2, 10); + xAND(gprT2, 0x7800); + xAND(gprT1, 0x7FF); + xOR(gprT1, gprT2); + + xADD(regS, gprT1); + } mVU.regAlloc->clearNeeded(regS); } mVU.profiler.EmitOp(opIADDIU); @@ -964,8 +1023,22 @@ mVUop(mVU_ISUBIU) pass2 { const xRegister32& regS = mVU.regAlloc->allocGPR(_Is_, _It_, mVUlow.backupVI); - if (_Imm15_ != 0) - xSUB(regS, _Imm15_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm15_ != 0) + xSUB(regS, _Imm15_); + } + else + { + xMOV(gprT1, ptr32[&curI]); + xMOV(gprT2, gprT1); + xSHR(gprT2, 10); + xAND(gprT2, 0x7800); + xAND(gprT1, 0x7FF); + xOR(gprT1, gprT2); + + xSUB(regS, gprT1); + } mVU.regAlloc->clearNeeded(regS); mVU.profiler.EmitOp(opISUBIU); } @@ -1101,16 +1174,31 @@ mVUop(mVU_ILW) { void* ptr = mVU.regs().Mem + offsetSS; std::optional optaddr(mVUoptimizeConstantAddr(mVU, _Is_, _Imm11_, offsetSS)); - if (!optaddr.has_value()) + if (EmuConfig.Gamefixes.IbitHack || !optaddr.has_value()) { mVU.regAlloc->moveVIToGPR(gprT1, _Is_); - if (_Imm11_ != 0) - xADD(gprT1, _Imm11_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm11_ != 0) + xADD(gprT1, _Imm11_); + } + else + { + xMOV(gprT2, ptr32[&curI]); + xAND(gprT2, 0x7FF); + xTEST(gprT2, 0x400); + + xForwardJZ32 skipExtend; + xOR(gprT2, 0xFFFFF800); + skipExtend.SetTarget(); + + xADD(gprT1, gprT2); + } mVUaddrFix(mVU, gprT1q); } const xRegister32& regT = mVU.regAlloc->allocGPR(-1, _It_, mVUlow.backupVI); - xMOVZX(regT, ptr16[optaddr.has_value() ? optaddr.value() : xComplexAddress(gprT2q, ptr, gprT1q)]); + xMOVZX(regT, ptr16[(optaddr.has_value() && !EmuConfig.Gamefixes.IbitHack) ? optaddr.value() : xComplexAddress(gprT2q, ptr, gprT1q)]); mVU.regAlloc->clearNeeded(regT); mVU.profiler.EmitOp(opILW); } @@ -1165,17 +1253,32 @@ mVUop(mVU_ISW) pass2 { std::optional optaddr(mVUoptimizeConstantAddr(mVU, _Is_, _Imm11_, 0)); - if (!optaddr.has_value()) + if (EmuConfig.Gamefixes.IbitHack || !optaddr.has_value()) { mVU.regAlloc->moveVIToGPR(gprT1, _Is_); - if (_Imm11_ != 0) - xADD(gprT1, _Imm11_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm11_ != 0) + xADD(gprT1, _Imm11_); + } + else + { + xMOV(gprT2, ptr32[&curI]); + xAND(gprT2, 0x7FF); + xTEST(gprT2, 0x400); + + xForwardJZ32 skipExtend; + xOR(gprT2, 0xFFFFF800); + skipExtend.SetTarget(); + + xADD(gprT1, gprT2); + } mVUaddrFix(mVU, gprT1q); } // If regT is dirty, the high bits might not be zero. const xRegister32& regT = mVU.regAlloc->allocGPR(_It_, -1, false, true); - const xAddressVoid ptr(optaddr.has_value() ? optaddr.value() : xComplexAddress(gprT2q, mVU.regs().Mem, gprT1q)); + const xAddressVoid ptr((optaddr.has_value() && !EmuConfig.Gamefixes.IbitHack) ? optaddr.value() : xComplexAddress(gprT2q, mVU.regs().Mem, gprT1q)); if (_X) xMOV(ptr32[ptr], regT); if (_Y) xMOV(ptr32[ptr + 4], regT); if (_Z) xMOV(ptr32[ptr + 8], regT); @@ -1252,16 +1355,31 @@ mVUop(mVU_LQ) pass2 { const std::optional optaddr(mVUoptimizeConstantAddr(mVU, _Is_, _Imm11_, 0)); - if (!optaddr.has_value()) + if (EmuConfig.Gamefixes.IbitHack || !optaddr.has_value()) { mVU.regAlloc->moveVIToGPR(gprT1, _Is_); - if (_Imm11_ != 0) - xADD(gprT1, _Imm11_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm11_ != 0) + xADD(gprT1, _Imm11_); + } + else + { + xMOV(gprT2, ptr32[&curI]); + xAND(gprT2, 0x7FF); + xTEST(gprT2, 0x400); + + xForwardJZ32 skipExtend; + xOR(gprT2, 0xFFFFF800); + skipExtend.SetTarget(); + + xADD(gprT1, gprT2); + } mVUaddrFix(mVU, gprT1q); } const xmm& Ft = mVU.regAlloc->allocReg(-1, _Ft_, _X_Y_Z_W); - mVUloadReg(Ft, optaddr.has_value() ? optaddr.value() : xComplexAddress(gprT2q, mVU.regs().Mem, gprT1q), _X_Y_Z_W); + mVUloadReg(Ft, (optaddr.has_value() && !EmuConfig.Gamefixes.IbitHack) ? optaddr.value() : xComplexAddress(gprT2q, mVU.regs().Mem, gprT1q), _X_Y_Z_W); mVU.regAlloc->clearNeeded(Ft); mVU.profiler.EmitOp(opLQ); } @@ -1346,16 +1464,31 @@ mVUop(mVU_SQ) pass2 { const std::optional optptr(mVUoptimizeConstantAddr(mVU, _It_, _Imm11_, 0)); - if (!optptr.has_value()) + if (EmuConfig.Gamefixes.IbitHack || !optptr.has_value()) { mVU.regAlloc->moveVIToGPR(gprT1, _It_); - if (_Imm11_ != 0) - xADD(gprT1, _Imm11_); + if (!EmuConfig.Gamefixes.IbitHack) + { + if (_Imm11_ != 0) + xADD(gprT1, _Imm11_); + } + else + { + xMOV(gprT2, ptr32[&curI]); + xAND(gprT2, 0x7FF); + xTEST(gprT2, 0x400); + + xForwardJZ32 skipExtend; + xOR(gprT2, 0xFFFFF800); + skipExtend.SetTarget(); + + xADD(gprT1, gprT2); + } mVUaddrFix(mVU, gprT1q); } const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, _XYZW_PS ? -1 : 0, _X_Y_Z_W); - mVUsaveReg(Fs, optptr.has_value() ? optptr.value() : xComplexAddress(gprT2q, mVU.regs().Mem, gprT1q), _X_Y_Z_W, 1); + mVUsaveReg(Fs, (optptr.has_value() && !EmuConfig.Gamefixes.IbitHack) ? optptr.value() : xComplexAddress(gprT2q, mVU.regs().Mem, gprT1q), _X_Y_Z_W, 1); mVU.regAlloc->clearNeeded(Fs); mVU.profiler.EmitOp(opSQ); }