From 26d78c7cd1baa781b2efde4740f76e62d664e1e1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 16 Mar 2019 16:17:24 -0700 Subject: [PATCH] interp: Cleanup prefix/size in vcrsp/vqmul. --- Core/MIPS/IR/IRCompVFPU.cpp | 10 +++---- Core/MIPS/MIPSIntVFPU.cpp | 57 ++++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 434c4fb57e..aaeb70be85 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -1628,13 +1628,12 @@ namespace MIPSComp { void IRFrontend::Comp_VCrossQuat(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - // TODO: Does this instruction even look at prefixes at all? - if (js.HasUnknownPrefix()) + if (!js.HasNoPrefix()) DISABLE; - // Vector cross product (n = 3) + // Vector cross product (n = 3, weird prefixes) // d[0 .. 2] = s[0 .. 2] X t[0 .. 2] - // Vector quaternion product (n = 4) + // Vector quaternion product (n = 4, weird prefixes) // d[0 .. 2] = t[0 .. 2] X s[0 .. 2] + s[3] * t[0 .. 2] + t[3] * s[0 .. 2] // d[3] = s[3]*t[3] - s[0 .. 2] dot t[0 .. 3] @@ -1674,13 +1673,14 @@ namespace MIPSComp { ir.Write(IROp::FSub, tempregs[2], temp0, temp1); } else if (sz == V_Quad) { DISABLE; + } else { + DISABLE; } for (int i = 0; i < n; i++) { if (tempregs[i] != dregs[i]) ir.Write(IROp::FMov, dregs[i], tempregs[i]); } - // No D prefix supported } void IRFrontend::Comp_Vcmp(MIPSOpcode op) { diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 84917eb83c..e80ce283bb 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -1956,38 +1956,69 @@ namespace MIPSInt EatPrefixes(); } - void Int_CrossQuat(MIPSOpcode op) - { + void Int_CrossQuat(MIPSOpcode op) { + float s[4]{}, t[4]{}, d[4]; int vd = _VD; int vs = _VS; int vt = _VT; VectorSize sz = GetVecSize(op); - float s[4]; - float t[4]; - float d[4]; + int n = GetNumVectorElements(sz); ReadVector(s, sz, vs); ReadVector(t, sz, vt); - switch (sz) - { + + u32 tprefixRemove = VFPU_ANY_SWIZZLE() | VFPU_NEGATE(1, 1, 1, 1); + u32 tprefixAdd; + + switch (sz) { case V_Triple: // vcrsp.t d[0] = s[1]*t[2] - s[2]*t[1]; d[1] = s[2]*t[0] - s[0]*t[2]; - d[2] = s[0]*t[1] - s[1]*t[0]; + + // T prefix forces siwzzle and negate, can be used to have weird constants. + tprefixAdd = VFPU_SWIZZLE(1, 0, 3, 2) | VFPU_NEGATE(0, 1, 0, 0); + ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad); + ApplySwizzleS(s, V_Quad); + d[2] = s[0] * t[0] + s[1] * t[1] + s[2] * t[2] + s[3] * t[3]; break; case V_Quad: // vqmul.q d[0] = s[0]*t[3] + s[1]*t[2] - s[2]*t[1] + s[3]*t[0]; d[1] = -s[0]*t[2] + s[1]*t[3] + s[2]*t[0] + s[3]*t[1]; d[2] = s[0]*t[1] - s[1]*t[0] + s[2]*t[3] + s[3]*t[2]; - d[3] = -s[0]*t[0] - s[1]*t[1] - s[2]*t[2] + s[3]*t[3]; + + // T prefix forces siwzzle and negate, can be used to have weird constants. + tprefixAdd = VFPU_SWIZZLE(0, 1, 2, 3) | VFPU_NEGATE(1, 1, 1, 0); + ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad); + ApplySwizzleS(s, sz); + d[3] = s[0] * t[0] + s[1] * t[1] + s[2] * t[2] + s[3] * t[3]; break; - default: - Reporting::ReportMessage("CrossQuat instruction with wrong size"); - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); + case V_Pair: + // t swizzles invalid so the multiply is always zero. d[0] = 0; - d[1] = 0; + + tprefixAdd = VFPU_SWIZZLE(0, 0, 0, 0) | VFPU_NEGATE(0, 0, 0, 0); + ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad); + ApplySwizzleS(s, V_Quad); + // It's possible to populate a value by swizzling s[2]. + d[1] = s[2] * t[2]; break; + + case V_Single: + // t swizzles invalid so the multiply is always zero. + d[0] = 0; + break; + } + + // D prefix applies to the last element only (mask and sat) for pair and larger. + if (sz != V_Single) { + u32 lastmask = (currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] & (1 << 8)) << (n - 1); + u32 lastsat = (currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] & 3) << (n + n - 2); + currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] = lastmask | lastsat; + ApplyPrefixD(d, sz); + } else { + // Single always seems to write out zero. + currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] = 0; } WriteVector(d, sz, vd); PC += 4;