From 58db79672fbb0ec96c26c6c19f660f507eab127b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 8 Nov 2013 19:58:00 +0100 Subject: [PATCH] Fix vmtvc on ARM, fixing issues with our prefix check. Add some logging. Also improve vcmp on ARM. --- Core/MIPS/ARM/ArmCompVFPU.cpp | 23 +++++++++++++++++------ Core/MIPS/ARM/ArmJit.cpp | 11 ++++++----- Core/MIPS/JitCommon/JitCommon.h | 1 - Core/MIPS/JitCommon/JitState.h | 33 +++++++++++++++++++++++++++++++++ Core/MIPS/x86/CompVFPU.cpp | 2 +- 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index f594048d5f..41d7f08231 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -1016,11 +1016,10 @@ namespace MIPSComp gpr.MapReg(rt, MAP_NOINIT | MAP_DIRTY); VMOV(gpr.R(rt), fpr.V(imm)); } else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc - DISABLE; // In case we have a saved prefix. - //FlushPrefixV(); - //gpr.BindToRegister(rt, false, true); - //MOV(32, gpr.R(rt), M(¤tMIPS->vfpuCtrl[imm - 128])); + FlushPrefixV(); + gpr.MapReg(rt, MAP_NOINIT | MAP_DIRTY); + LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, vfpuCtrl) + 4 * (imm - 128)); } else { //ERROR - maybe need to make this value too an "interlock" value? ERROR_LOG(CPU, "mfv - invalid register %i", imm); @@ -1357,10 +1356,8 @@ namespace MIPSComp // Some, we just fall back to the interpreter. switch (cond) { - case VC_EN: // c = my_isnan(s[i]); break; case VC_EI: // c = my_isinf(s[i]); break; case VC_ES: // c = my_isnan(s[i]) || my_isinf(s[i]); break; // Tekken Dark Resurrection - case VC_NN: // c = !my_isnan(s[i]); break; case VC_NI: // c = !my_isinf(s[i]); break; case VC_NS: // c = !my_isnan(s[i]) && !my_isinf(s[i]); break; DISABLE; @@ -1387,6 +1384,20 @@ namespace MIPSComp ORR(R0, R0, 1 << n); break; + case VC_EN: // c = my_isnan(s[i]); break; // Tekken 6 + // Should we involve T? Where I found this used, it compared a register with itself so should be fine. + fpr.MapInInV(sregs[i], tregs[i]); + VCMP(fpr.V(sregs[i]), fpr.V(tregs[i])); + flag = CC_VS; // overflow = unordered : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204j/Chdhcfbc.html + break; + + case VC_NN: // c = !my_isnan(s[i]); break; + // Should we involve T? Where I found this used, it compared a register with itself so should be fine. + fpr.MapInInV(sregs[i], tregs[i]); + VCMP(fpr.V(sregs[i]), fpr.V(tregs[i])); + flag = CC_VC; // !overflow = !unordered : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204j/Chdhcfbc.html + break; + case VC_EQ: // c = s[i] == t[i] fpr.MapInInV(sregs[i], tregs[i]); VCMP(fpr.V(sregs[i]), fpr.V(tregs[i])); diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 39a2bafe6d..d8715e17bb 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -168,10 +168,8 @@ void Jit::CompileDelaySlot(int flags) _MSR(true, false, R8); // Restore flags register } -void Jit::Compile(u32 em_address) -{ - if (GetSpaceLeft() < 0x10000 || blocks.IsFull()) - { +void Jit::Compile(u32 em_address) { + if (GetSpaceLeft() < 0x10000 || blocks.IsFull()) { ClearCache(); } @@ -182,8 +180,11 @@ void Jit::Compile(u32 em_address) // Drat. The VFPU hit an uneaten prefix at the end of a block. if (js.startDefaultPrefix && js.MayHavePrefix()) { - WARN_LOG(JIT, "Uneaten prefix at end of block: %08x", js.compilerPC - 4); + WARN_LOG(JIT, "An uneaten prefix at end of block: %08x", js.compilerPC - 4); + js.LogPrefix(); + js.startDefaultPrefix = false; + // Our assumptions are all wrong so it's clean-slate time. ClearCache(); diff --git a/Core/MIPS/JitCommon/JitCommon.h b/Core/MIPS/JitCommon/JitCommon.h index 5fdc2791e1..ed18c309cc 100644 --- a/Core/MIPS/JitCommon/JitCommon.h +++ b/Core/MIPS/JitCommon/JitCommon.h @@ -21,7 +21,6 @@ struct JitBlock; - #if defined(PPC) #include "../PPC/PpcJit.h" #elif defined(ARM) diff --git a/Core/MIPS/JitCommon/JitState.h b/Core/MIPS/JitCommon/JitState.h index ad9dd7926b..f7f13db6a4 100644 --- a/Core/MIPS/JitCommon/JitState.h +++ b/Core/MIPS/JitCommon/JitState.h @@ -85,11 +85,13 @@ namespace MIPSComp { PrefixUnknown(); } } + void PrefixUnknown() { prefixSFlag = PREFIX_UNKNOWN; prefixTFlag = PREFIX_UNKNOWN; prefixDFlag = PREFIX_UNKNOWN; } + bool MayHavePrefix() const { if (HasUnknownPrefix()) { return true; @@ -100,15 +102,18 @@ namespace MIPSComp { } return false; } + bool HasUnknownPrefix() const { if (!(prefixSFlag & PREFIX_KNOWN) || !(prefixTFlag & PREFIX_KNOWN) || !(prefixDFlag & PREFIX_KNOWN)) { return true; } return false; } + bool HasNoPrefix() const { return (prefixDFlag & PREFIX_KNOWN) && (prefixSFlag & PREFIX_KNOWN) && (prefixTFlag & PREFIX_KNOWN) && (prefixS == 0xE4 && prefixT == 0xE4 && prefixD == 0); } + void EatPrefix() { if ((prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4) { prefixSFlag = PREFIX_KNOWN_DIRTY; @@ -123,13 +128,41 @@ namespace MIPSComp { prefixD = 0x0; } } + u8 VfpuWriteMask() const { _assert_(prefixDFlag & JitState::PREFIX_KNOWN); return (prefixD >> 8) & 0xF; } + bool VfpuWriteMask(int i) const { _assert_(prefixDFlag & JitState::PREFIX_KNOWN); return (prefixD >> (8 + i)) & 1; } + + void LogPrefix() { + LogSTPrefix("S", prefixS, prefixSFlag); + LogSTPrefix("T", prefixT, prefixTFlag); + LogDPrefix(); + } + + private: + void LogSTPrefix(const char *name, int p, int pflag) { + if ((prefixSFlag & PREFIX_KNOWN) == 0) { + ERROR_LOG(JIT, "%s: unknown (%08x %i)", name, p, pflag); + } else if (prefixS != 0xE4) { + ERROR_LOG(JIT, "%s: %08x flag: %i", name, p, pflag); + } else { + WARN_LOG(JIT, "%s: %08x flag: %i", name, p, pflag); + } + } + void LogDPrefix() { + if ((prefixDFlag & PREFIX_KNOWN) == 0) { + ERROR_LOG(JIT, "D: unknown (%08x %i)", prefixD, prefixDFlag); + } else if (prefixD != 0) { + ERROR_LOG(JIT, "D: (%08x %i)", prefixD, prefixDFlag); + } else { + WARN_LOG(JIT, "D: %08x flag: %i", prefixD, prefixDFlag); + } + } }; } diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index fa1bfbe551..c45c61fbda 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -1560,7 +1560,7 @@ void Jit::Comp_Mftv(MIPSOpcode op) { fpr.StoreFromRegisterV(imm); gpr.BindToRegister(rt, false, true); MOV(32, gpr.R(rt), fpr.V(imm)); - } else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc + } else if (imm < 128 + VFPU_CTRL_MAX) { //mfvc // In case we have a saved prefix. FlushPrefixV(); gpr.BindToRegister(rt, false, true);