diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 250c2cc0ac..83911bcfa0 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -1334,17 +1334,20 @@ namespace MIPSComp CONDITIONAL_DISABLE(VFPU_XFER); int vd = _VD; - int imm = (op >> 8) & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + int imm = (op >> 8) & 0x7F; + if (imm < VFPU_CTRL_MAX) { fpr.MapRegV(vd); - if (imm - 128 == VFPU_CTRL_CC) { + if (imm == VFPU_CTRL_CC) { gpr.MapReg(MIPS_REG_VFPUCC, 0); VMOV(fpr.V(vd), gpr.R(MIPS_REG_VFPUCC)); } else { - ADDI2R(SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4, SCRATCHREG2); + ADDI2R(SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + imm * 4, SCRATCHREG2); VLDR(fpr.V(vd), SCRATCHREG1, 0); } fpr.ReleaseSpillLocksAndDiscardTemps(); + } else { + fpr.MapRegV(vd); + MOVI2F(fpr.V(vd), 0.0f, SCRATCHREG1); } } @@ -1353,23 +1356,23 @@ namespace MIPSComp CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; - int imm = op & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + int imm = op & 0x7F; + if (imm < VFPU_CTRL_MAX) { fpr.MapRegV(vs); - if (imm - 128 == VFPU_CTRL_CC) { + if (imm == VFPU_CTRL_CC) { gpr.MapReg(MIPS_REG_VFPUCC, MAP_DIRTY | MAP_NOINIT); VMOV(gpr.R(MIPS_REG_VFPUCC), fpr.V(vs)); } else { - ADDI2R(SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4, SCRATCHREG2); + ADDI2R(SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + imm * 4, SCRATCHREG2); VSTR(fpr.V(vs), SCRATCHREG1, 0); } fpr.ReleaseSpillLocksAndDiscardTemps(); - if (imm - 128 == VFPU_CTRL_SPREFIX) { + if (imm == VFPU_CTRL_SPREFIX) { js.prefixSFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_TPREFIX) { + } else if (imm == VFPU_CTRL_TPREFIX) { js.prefixTFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_DPREFIX) { + } else if (imm == VFPU_CTRL_DPREFIX) { js.prefixDFlag = JitState::PREFIX_UNKNOWN; } } diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp index 1e0382635f..cf67f4d84f 100644 --- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp @@ -1067,17 +1067,20 @@ namespace MIPSComp { CONDITIONAL_DISABLE(VFPU_XFER); int vd = _VD; - int imm = (op >> 8) & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + int imm = (op >> 8) & 0x7F; + if (imm < VFPU_CTRL_MAX) { fpr.MapRegV(vd); - if (imm - 128 == VFPU_CTRL_CC) { + if (imm == VFPU_CTRL_CC) { gpr.MapReg(MIPS_REG_VFPUCC, 0); fp.FMOV(fpr.V(vd), gpr.R(MIPS_REG_VFPUCC)); } else { - ADDI2R(SCRATCH1_64, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4, SCRATCH2); + ADDI2R(SCRATCH1_64, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + imm * 4, SCRATCH2); fp.LDR(32, INDEX_UNSIGNED, fpr.V(vd), SCRATCH1_64, 0); } fpr.ReleaseSpillLocksAndDiscardTemps(); + } else { + fpr.MapRegV(vd); + fp.MOVI2F(fpr.V(vd), 0.0f, SCRATCH1); } } @@ -1085,23 +1088,23 @@ namespace MIPSComp { CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; - int imm = op & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + int imm = op & 0x7F; + if (imm < VFPU_CTRL_MAX) { fpr.MapRegV(vs); - if (imm - 128 == VFPU_CTRL_CC) { + if (imm == VFPU_CTRL_CC) { gpr.MapReg(MIPS_REG_VFPUCC, MAP_DIRTY | MAP_NOINIT); fp.FMOV(gpr.R(MIPS_REG_VFPUCC), fpr.V(vs)); } else { - ADDI2R(SCRATCH1_64, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4, SCRATCH2); + ADDI2R(SCRATCH1_64, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + imm * 4, SCRATCH2); fp.STR(32, INDEX_UNSIGNED, fpr.V(vs), SCRATCH1_64, 0); } fpr.ReleaseSpillLocksAndDiscardTemps(); - if (imm - 128 == VFPU_CTRL_SPREFIX) { + if (imm == VFPU_CTRL_SPREFIX) { js.prefixSFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_TPREFIX) { + } else if (imm == VFPU_CTRL_TPREFIX) { js.prefixTFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_DPREFIX) { + } else if (imm == VFPU_CTRL_DPREFIX) { js.prefixDFlag = JitState::PREFIX_UNKNOWN; } } diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index c13ab20c72..84004f4641 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -426,11 +426,11 @@ namespace MIPSComp { void IRFrontend::Comp_VMatrixInit(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_XFER); MatrixSize sz = GetMtxSize(op); - if (sz != M_4x4) { + if (sz != M_4x4 || !js.HasNoPrefix()) { DISABLE; } - // Matrix init (no prefixes) + // Matrix init (weird prefixes) // d[N,M] = CONST[N,M] // Not really about trying here, it will work if enabled. @@ -960,7 +960,7 @@ namespace MIPSComp { MIPSGPReg rt = _RT; switch ((op >> 21) & 0x1f) { case 3: //mfv / mfvc - // rt = 0, imm = 255 appears to be used as a CPU interlock by some games. + // rt = 0, imm = 255 appears to be used as a CPU interlock by some games. if (rt != MIPS_REG_ZERO) { if (imm < 128) { //R(rt) = VI(imm); ir.Write(IROp::FMovToGPR, rt, vfpuBase + voffset[imm]); @@ -1021,9 +1021,9 @@ namespace MIPSComp { // D[0] = VFPU_CTRL[i] int vd = _VD; - int imm = (op >> 8) & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { - ir.Write(IROp::VfpuCtrlToReg, IRTEMP_0, imm - 128); + int imm = (op >> 8) & 0x7F; + if (imm < VFPU_CTRL_MAX) { + ir.Write(IROp::VfpuCtrlToReg, IRTEMP_0, imm); ir.Write(IROp::FMovFromGPR, vfpuBase + voffset[vd], IRTEMP_0); } else { INVALIDOP; @@ -1038,22 +1038,22 @@ namespace MIPSComp { int vs = _VS; int imm = op & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + if (imm < VFPU_CTRL_MAX) { u32 mask; - if (GetVFPUCtrlMask(imm - 128, &mask)) { + if (GetVFPUCtrlMask(imm, &mask)) { if (mask != 0xFFFFFFFF) { ir.Write(IROp::FMovToGPR, IRTEMP_0, vfpuBase + voffset[imm]); ir.Write(IROp::AndConst, IRTEMP_0, IRTEMP_0, ir.AddConstant(mask)); - ir.Write(IROp::SetCtrlVFPUReg, imm - 128, IRTEMP_0); + ir.Write(IROp::SetCtrlVFPUReg, imm, IRTEMP_0); } else { - ir.Write(IROp::SetCtrlVFPUFReg, imm - 128, vfpuBase + voffset[vs]); + ir.Write(IROp::SetCtrlVFPUFReg, imm, vfpuBase + voffset[vs]); } } - if (imm - 128 == VFPU_CTRL_SPREFIX) { + if (imm == VFPU_CTRL_SPREFIX) { js.prefixSFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_TPREFIX) { + } else if (imm == VFPU_CTRL_TPREFIX) { js.prefixTFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_DPREFIX) { + } else if (imm == VFPU_CTRL_DPREFIX) { js.prefixDFlag = JitState::PREFIX_UNKNOWN; } } else { @@ -1869,7 +1869,7 @@ namespace MIPSComp { void IRFrontend::Comp_Vsgn(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_VEC); - if (js.HasUnknownPrefix()) { + if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) { DISABLE; } diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index b9bb5e2d2e..2619ea7b76 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -317,24 +317,20 @@ namespace MIPSInt PC += 4; } - void Int_VMatrixInit(MIPSOpcode op) - { - static const float idt[16] = - { + void Int_VMatrixInit(MIPSOpcode op) { + static const float idt[16] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, }; - static const float zero[16] = - { + static const float zero[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, }; - static const float one[16] = - { + static const float one[16] = { 1,1,1,1, 1,1,1,1, 1,1,1,1, @@ -344,8 +340,7 @@ namespace MIPSInt MatrixSize sz = GetMtxSize(op); const float *m; - switch ((op >> 16) & 0xF) - { + switch ((op >> 16) & 0xF) { case 3: m=idt; break; //identity // vmidt case 6: m=zero; break; // vmzero case 7: m=one; break; // vmone @@ -356,7 +351,37 @@ namespace MIPSInt return; } - WriteMatrix(m, sz, vd); + // The S prefix generates constants, but only for the final (possibly transposed) row. + if (currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX] & 0xF0F00) { + float prefixed[16]; + memcpy(prefixed, m, sizeof(prefixed)); + + int off = GetMatrixSide(sz) - 1; + u32 sprefixRemove = VFPU_ANY_SWIZZLE(); + u32 sprefixAdd; + switch ((op >> 16) & 0xF) { + case 3: + { + VFPUConst constX = off == 0 ? VFPUConst::ONE : VFPUConst::ZERO; + VFPUConst constY = off == 1 ? VFPUConst::ONE : VFPUConst::ZERO; + VFPUConst constZ = off == 2 ? VFPUConst::ONE : VFPUConst::ZERO; + VFPUConst constW = off == 3 ? VFPUConst::ONE : VFPUConst::ZERO; + sprefixAdd = VFPU_MAKE_CONSTANTS(constX, constY, constZ, constW); + break; + } + case 6: + sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO); + break; + case 7: + sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE); + break; + } + ApplyPrefixST(&prefixed[off * 4], VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Quad); + WriteMatrix(prefixed, sz, vd); + } else { + // Write mask applies to the final (maybe transposed) row. Sat causes hang. + WriteMatrix(m, sz, vd); + } PC += 4; EatPrefixes(); } @@ -642,19 +667,30 @@ namespace MIPSInt EatPrefixes(); } - void Int_Vsgn(MIPSOpcode op) - { - float s[4], d[4]; + void Int_Vsgn(MIPSOpcode op) { + float s[4], t[4], d[4]; int vd = _VD; int vs = _VS; VectorSize sz = GetVecSize(op); ReadVector(s, sz, vs); - ApplySwizzleS(s, sz); - for (int i = 0; i < GetNumVectorElements(sz); i++) - { + + // Not sure who would do this, but using abs/neg allows a compare against 3 or -3. + u32 tprefixRemove = VFPU_ANY_SWIZZLE(); + u32 tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO); + ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz); + + int n = GetNumVectorElements(sz); + if (n < 4) { + // Compare with a swizzled value out of bounds always produces 0. + memcpy(&s[n], &t[n], sizeof(float) * (4 - n)); + } + ApplySwizzleS(s, V_Quad); + + for (int i = 0; i < n; i++) { + float diff = s[i] - t[i]; // To handle NaNs correctly, we do this with integer hackery u32 val; - memcpy(&val, &s[i], sizeof(u32)); + memcpy(&val, &diff, sizeof(u32)); if (val == 0 || val == 0x80000000) d[i] = 0.0f; else if ((val >> 31) == 0) @@ -1029,51 +1065,63 @@ namespace MIPSInt EatPrefixes(); } - void Int_VDot(MIPSOpcode op) - { - float s[4], t[4]; + void Int_VDot(MIPSOpcode op) { + float s[4]{}, t[4]{}; float d; int vd = _VD; int vs = _VS; int vt = _VT; VectorSize sz = GetVecSize(op); ReadVector(s, sz, vs); - ApplySwizzleS(s, sz); + ApplySwizzleS(s, V_Quad); ReadVector(t, sz, vt); - ApplySwizzleT(t, sz); - float sum = 0.0f; - int n = GetNumVectorElements(sz); - for (int i = 0; i < n; i++) - { - sum += s[i]*t[i]; + ApplySwizzleT(t, V_Quad); + d = 0.0f; + for (int i = 0; i < 4; i++) { + d += s[i] * t[i]; } - d = sum; - ApplyPrefixD(&d,V_Single); + ApplyPrefixD(&d, V_Single); WriteVector(&d, V_Single, vd); PC += 4; EatPrefixes(); } - void Int_VHdp(MIPSOpcode op) - { - float s[4], t[4]; + void Int_VHdp(MIPSOpcode op) { + float s[4]{}, t[4]{}; float d; int vd = _VD; int vs = _VS; int vt = _VT; VectorSize sz = GetVecSize(op); ReadVector(s, sz, vs); - ApplySwizzleS(s, sz); ReadVector(t, sz, vt); - ApplySwizzleT(t, sz); + ApplySwizzleT(t, V_Quad); + + // S prefix forces constant 1 for the last element (w for quad.) + // Otherwise it is the same as vdot. + u32 sprefixRemove; + u32 sprefixAdd; + if (sz == V_Quad) { + sprefixRemove = VFPU_SWIZZLE(0, 0, 0, 3); + sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::NONE, VFPUConst::NONE, VFPUConst::NONE, VFPUConst::ONE); + } else if (sz == V_Triple) { + sprefixRemove = VFPU_SWIZZLE(0, 0, 3, 0); + sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::NONE, VFPUConst::NONE, VFPUConst::ONE, VFPUConst::NONE); + } else if (sz == V_Pair) { + sprefixRemove = VFPU_SWIZZLE(0, 3, 0, 0); + sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::NONE, VFPUConst::ONE, VFPUConst::NONE, VFPUConst::NONE); + } else { + sprefixRemove = VFPU_SWIZZLE(3, 0, 0, 0); + sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::NONE, VFPUConst::NONE, VFPUConst::NONE); + } + ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Quad); + float sum = 0.0f; - int n = GetNumVectorElements(sz); - for (int i = 0; i < n; i++) - { - sum += (i == n - 1) ? t[i] : s[i]*t[i]; + for (int i = 0; i < 4; i++) { + sum += s[i] * t[i]; } d = my_isnan(sum) ? fabsf(sum) : sum; - ApplyPrefixD(&d,V_Single); + ApplyPrefixD(&d, V_Single); WriteVector(&d, V_Single, vd); PC += 4; EatPrefixes(); @@ -1549,20 +1597,22 @@ namespace MIPSInt void Int_Vmfvc(MIPSOpcode op) { int vd = _VD; - int imm = (op >> 8) & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { - VI(vd) = currentMIPS->vfpuCtrl[imm - 128]; + int imm = (op >> 8) & 0x7F; + if (imm < VFPU_CTRL_MAX) { + VI(vd) = currentMIPS->vfpuCtrl[imm]; + } else { + VI(vd) = 0; } PC += 4; } void Int_Vmtvc(MIPSOpcode op) { int vs = _VS; - int imm = op & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + int imm = op & 0x7F; + if (imm < VFPU_CTRL_MAX) { u32 mask; - if (GetVFPUCtrlMask(imm - 128, &mask)) { - currentMIPS->vfpuCtrl[imm - 128] = VI(vs) & mask; + if (GetVFPUCtrlMask(imm, &mask)) { + currentMIPS->vfpuCtrl[imm] = VI(vs) & mask; } } PC += 4; diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 88ae395642..73cd85c22a 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -2529,38 +2529,42 @@ void Jit::Comp_Mftv(MIPSOpcode op) { void Jit::Comp_Vmfvc(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_XFER); int vd = _VD; - int imm = (op >> 8) & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + int imm = (op >> 8) & 0x7F; + if (imm < VFPU_CTRL_MAX) { fpr.MapRegV(vd, MAP_DIRTY | MAP_NOINIT); - if (imm - 128 == VFPU_CTRL_CC) { + if (imm == VFPU_CTRL_CC) { gpr.MapReg(MIPS_REG_VFPUCC, true, false); MOVD_xmm(fpr.VX(vd), gpr.R(MIPS_REG_VFPUCC)); } else { - MOVSS(fpr.VX(vd), MIPSSTATE_VAR_ELEM32(vfpuCtrl[0], imm - 128)); + MOVSS(fpr.VX(vd), MIPSSTATE_VAR_ELEM32(vfpuCtrl[0], imm)); } fpr.ReleaseSpillLocks(); + } else { + fpr.MapRegV(vd, MAP_DIRTY | MAP_NOINIT); + XORPS(fpr.VX(vd), fpr.V(vd)); + fpr.ReleaseSpillLocks(); } } void Jit::Comp_Vmtvc(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_XFER); int vs = _VS; - int imm = op & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { + int imm = op & 0x7F; + if (imm < VFPU_CTRL_MAX) { fpr.MapRegV(vs, 0); - if (imm - 128 == VFPU_CTRL_CC) { + if (imm == VFPU_CTRL_CC) { gpr.MapReg(MIPS_REG_VFPUCC, false, true); MOVD_xmm(gpr.R(MIPS_REG_VFPUCC), fpr.VX(vs)); } else { - MOVSS(MIPSSTATE_VAR_ELEM32(vfpuCtrl[0], imm - 128), fpr.VX(vs)); + MOVSS(MIPSSTATE_VAR_ELEM32(vfpuCtrl[0], imm), fpr.VX(vs)); } fpr.ReleaseSpillLocks(); - if (imm - 128 == VFPU_CTRL_SPREFIX) { + if (imm == VFPU_CTRL_SPREFIX) { js.prefixSFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_TPREFIX) { + } else if (imm == VFPU_CTRL_TPREFIX) { js.prefixTFlag = JitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_DPREFIX) { + } else if (imm == VFPU_CTRL_DPREFIX) { js.prefixDFlag = JitState::PREFIX_UNKNOWN; } }