mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'vfpu' into TemporaryHackishBranch
This commit is contained in:
commit
c0d5b4be7e
8 files changed
+1165
-760
No files matched your search
@@ -100,7 +100,7 @@ namespace MIPSComp
|
||||
js.prefixTFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
case 2: // D
|
||||
js.prefixD = data;
|
||||
js.prefixD = data & 0x00000FFF;
|
||||
js.prefixDFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
default:
|
||||
@@ -1333,18 +1333,21 @@ namespace MIPSComp
|
||||
NEON_IF_AVAILABLE(CompNEON_Vmtvc);
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
fpr.MapRegV(vs);
|
||||
if (imm - 128 == VFPU_CTRL_CC) {
|
||||
int vd = _VD;
|
||||
int imm = (op >> 8) & 0x7F;
|
||||
if (imm < VFPU_CTRL_MAX) {
|
||||
fpr.MapRegV(vd);
|
||||
if (imm == VFPU_CTRL_CC) {
|
||||
gpr.MapReg(MIPS_REG_VFPUCC, 0);
|
||||
VMOV(fpr.V(vs), gpr.R(MIPS_REG_VFPUCC));
|
||||
VMOV(fpr.V(vd), gpr.R(MIPS_REG_VFPUCC));
|
||||
} else {
|
||||
ADDI2R(SCRATCHREG1, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4, SCRATCHREG2);
|
||||
VLDR(fpr.V(vs), SCRATCHREG1, 0);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace MIPSComp {
|
||||
js.prefixTFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
case 2: // D
|
||||
js.prefixD = data;
|
||||
js.prefixD = data & 0x00000FFF;
|
||||
js.prefixDFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
default:
|
||||
@@ -1066,18 +1066,21 @@ namespace MIPSComp {
|
||||
void Arm64Jit::Comp_Vmfvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
fpr.MapRegV(vs);
|
||||
if (imm - 128 == VFPU_CTRL_CC) {
|
||||
int vd = _VD;
|
||||
int imm = (op >> 8) & 0x7F;
|
||||
if (imm < VFPU_CTRL_MAX) {
|
||||
fpr.MapRegV(vd);
|
||||
if (imm == VFPU_CTRL_CC) {
|
||||
gpr.MapReg(MIPS_REG_VFPUCC, 0);
|
||||
fp.FMOV(fpr.V(vs), gpr.R(MIPS_REG_VFPUCC));
|
||||
fp.FMOV(fpr.V(vd), gpr.R(MIPS_REG_VFPUCC));
|
||||
} else {
|
||||
ADDI2R(SCRATCH1_64, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4, SCRATCH2);
|
||||
fp.LDR(32, INDEX_UNSIGNED, fpr.V(vs), SCRATCH1_64, 0);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+134
-64
@@ -108,8 +108,28 @@ namespace MIPSComp {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsPrefixWithinSize(u32 prefix, VectorSize sz) {
|
||||
int n = GetNumVectorElements(sz);
|
||||
for (int i = n; i < 4; i++) {
|
||||
int regnum = (prefix >> (i * 2)) & 3;
|
||||
int abs = (prefix >> (8 + i)) & 1;
|
||||
int negate = (prefix >> (16 + i)) & 1;
|
||||
int constants = (prefix >> (12 + i)) & 1;
|
||||
if (regnum < n || abs || negate || constants) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsPrefixWithinSize(u32 prefix, MIPSOpcode op) {
|
||||
return IsPrefixWithinSize(prefix, GetVecSize(op));
|
||||
}
|
||||
|
||||
void IRFrontend::Comp_VPFX(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
// This is how prefixes are typically set.
|
||||
int data = op & 0xFFFFF;
|
||||
int regnum = (op >> 24) & 3;
|
||||
switch (regnum) {
|
||||
@@ -122,7 +142,7 @@ namespace MIPSComp {
|
||||
js.prefixTFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
case 2: // D
|
||||
js.prefixD = data;
|
||||
js.prefixD = data & 0x00000FFF;
|
||||
js.prefixDFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
default:
|
||||
@@ -183,14 +203,10 @@ namespace MIPSComp {
|
||||
// This puts the value into a temp reg, so we won't write the modified value back.
|
||||
vregs[i] = tempReg + i;
|
||||
if (!constants) {
|
||||
// Prefix may say "z, z, z, z" but if this is a pair, we force to x.
|
||||
// TODO: But some ops seem to use const 0 instead?
|
||||
if (regnum >= n) {
|
||||
WARN_LOG(CPU, "JIT: Invalid VFPU swizzle: %08x : %d / %d at PC = %08x (%s)", prefix, regnum, n, GetCompilerPC(), MIPSDisasmAt(GetCompilerPC()));
|
||||
regnum = 0;
|
||||
}
|
||||
|
||||
if (abs) {
|
||||
// Depends on the op, but often zero.
|
||||
ir.Write(IROp::SetConstF, vregs[i], ir.AddConstantFloat(0.0f));
|
||||
} else if (abs) {
|
||||
ir.Write(IROp::FAbs, vregs[i], origV[regnum]);
|
||||
if (negate)
|
||||
ir.Write(IROp::FNeg, vregs[i], vregs[i]);
|
||||
@@ -343,12 +359,13 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VVectorInit(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || js.HasSPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector init
|
||||
// d[N] = CONST[N]
|
||||
// Note: probably implemented as vmov with prefix hack.
|
||||
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int type = (op >> 16) & 0xF;
|
||||
@@ -369,12 +386,13 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VIdt(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || js.HasSPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector identity row
|
||||
// d[N] = IDENTITY[N,m]
|
||||
// Note: probably implemented as vmov with prefix hack.
|
||||
|
||||
int vd = _VD;
|
||||
VectorSize sz = GetVecSize(op);
|
||||
@@ -408,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.
|
||||
@@ -448,18 +466,22 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VHdp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector homogenous dot product
|
||||
// d[0] = s[0 .. n-2] dot t[0 .. n-2] + t[n-1]
|
||||
// Note: s[n-1] is ignored / treated as 1.
|
||||
// Note: s[n-1] is ignored / treated as 1 via prefix override.
|
||||
|
||||
int vd = _VD;
|
||||
int vs = _VS;
|
||||
int vt = _VT;
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int n = GetNumVectorElements(sz);
|
||||
|
||||
if (js.prefixS & (0x0101 << (8 + n - 1)))
|
||||
DISABLE;
|
||||
|
||||
// TODO: Force read one of them into regs? probably not.
|
||||
u8 sregs[4], tregs[4], dregs[1];
|
||||
@@ -469,9 +491,7 @@ namespace MIPSComp {
|
||||
|
||||
ir.Write(IROp::FMul, IRVTEMP_0, sregs[0], tregs[0]);
|
||||
|
||||
int n = GetNumVectorElements(sz);
|
||||
for (int i = 1; i < n; i++) {
|
||||
// sum += s[i]*t[i];
|
||||
if (i == n - 1) {
|
||||
ir.Write(IROp::FAdd, IRVTEMP_0, IRVTEMP_0, tregs[i]);
|
||||
} else {
|
||||
@@ -488,14 +508,15 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vhoriz(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector horizontal add
|
||||
// d[0] = s[0] + ... s[n-1]
|
||||
// Vector horizontal average
|
||||
// d[0] = (s[0] + ... s[n-1]) / n
|
||||
// d[0] = s[0] / n + ... s[n-1] / n
|
||||
// Note: Both are implemented as dot products against generated constants.
|
||||
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int n = GetNumVectorElements(sz);
|
||||
@@ -525,7 +546,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VDot(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -563,8 +584,9 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VecDo3(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector arithmetic
|
||||
// d[N] = OP(s[N], t[N]) (see below)
|
||||
@@ -576,7 +598,11 @@ namespace MIPSComp {
|
||||
switch ((op >> 23) & 7) {
|
||||
case 0: // d[i] = s[i] + t[i]; break; //vadd
|
||||
case 1: // d[i] = s[i] - t[i]; break; //vsub
|
||||
break;
|
||||
case 7: // d[i] = s[i] / t[i]; break; //vdiv
|
||||
if (!js.HasNoPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
INVALIDOP;
|
||||
@@ -722,7 +748,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VV2Op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op))
|
||||
DISABLE;
|
||||
|
||||
// Vector unary operation
|
||||
@@ -731,8 +757,17 @@ namespace MIPSComp {
|
||||
int vs = _VS;
|
||||
int vd = _VD;
|
||||
|
||||
int optype = (op >> 16) & 0x1f;
|
||||
if (optype >= 16 && !js.HasNoPrefix()) {
|
||||
DISABLE;
|
||||
} else if ((optype == 1 || optype == 2) && js.HasSPrefix()) {
|
||||
DISABLE;
|
||||
} else if (optype == 5 && js.HasDPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Pre-processing: Eliminate silly no-op VMOVs, common in Wipeout Pure
|
||||
if (((op >> 16) & 0x1f) == 0 && vs == vd && js.HasNoPrefix()) {
|
||||
if (optype == 0 && vs == vd && js.HasNoPrefix()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -756,7 +791,7 @@ namespace MIPSComp {
|
||||
|
||||
bool canSIMD = false;
|
||||
// Some can be SIMD'd.
|
||||
switch ((op >> 16) & 0x1f) {
|
||||
switch (optype) {
|
||||
case 0: // vmov
|
||||
case 1: // vabs
|
||||
case 2: // vneg
|
||||
@@ -765,7 +800,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
if (canSIMD && !usingTemps && IsConsecutive4(sregs) && IsConsecutive4(dregs)) {
|
||||
switch ((op >> 16) & 0x1f) {
|
||||
switch (optype) {
|
||||
case 0: // vmov
|
||||
ir.Write(IROp::Vec4Mov, dregs[0], sregs[0]);
|
||||
break;
|
||||
@@ -781,7 +816,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
switch ((op >> 16) & 0x1f) {
|
||||
switch (optype) {
|
||||
case 0: // d[i] = s[i]; break; //vmov
|
||||
// Probably for swizzle.
|
||||
ir.Write(IROp::FMov, tempregs[i], sregs[i]);
|
||||
@@ -848,7 +883,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vi2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op)) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -895,6 +930,9 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vh2f(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op)) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector expand half to float
|
||||
// d[N*2] = float(lowerhalf(s[N])), d[N*2+1] = float(upperhalf(s[N]))
|
||||
@@ -904,6 +942,9 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vf2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || (js.prefixD & 0xFF) != 0) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector float to integer
|
||||
// d[N] = int(S[N] * mult)
|
||||
@@ -919,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]);
|
||||
@@ -944,7 +985,15 @@ namespace MIPSComp {
|
||||
if (imm < 128) {
|
||||
ir.Write(IROp::FMovFromGPR, vfpuBase + voffset[imm], rt);
|
||||
} else if ((imm - 128) < VFPU_CTRL_MAX) {
|
||||
ir.Write(IROp::SetCtrlVFPU, imm - 128, rt);
|
||||
u32 mask;
|
||||
if (GetVFPUCtrlMask(imm - 128, &mask)) {
|
||||
if (mask != 0xFFFFFFFF) {
|
||||
ir.Write(IROp::AndConst, IRTEMP_0, rt, ir.AddConstant(mask));
|
||||
ir.Write(IROp::SetCtrlVFPUReg, imm - 128, IRTEMP_0);
|
||||
} else {
|
||||
ir.Write(IROp::SetCtrlVFPU, imm - 128, rt);
|
||||
}
|
||||
}
|
||||
|
||||
if (imm - 128 == VFPU_CTRL_SPREFIX) {
|
||||
js.prefixSFlag = JitState::PREFIX_UNKNOWN;
|
||||
@@ -969,13 +1018,13 @@ namespace MIPSComp {
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
|
||||
// Vector Move from vector control reg (no prefixes)
|
||||
// S[0] = VFPU_CTRL[i]
|
||||
// D[0] = VFPU_CTRL[i]
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
ir.Write(IROp::VfpuCtrlToReg, IRTEMP_0, imm - 128);
|
||||
ir.Write(IROp::FMovFromGPR, vfpuBase + voffset[vs], IRTEMP_0);
|
||||
int vd = _VD;
|
||||
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;
|
||||
}
|
||||
@@ -989,13 +1038,22 @@ namespace MIPSComp {
|
||||
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
ir.Write(IROp::SetCtrlVFPUFReg, imm - 128, vfpuBase + voffset[vs]);
|
||||
if (imm - 128 == VFPU_CTRL_SPREFIX) {
|
||||
if (imm < VFPU_CTRL_MAX) {
|
||||
u32 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, IRTEMP_0);
|
||||
} else {
|
||||
ir.Write(IROp::SetCtrlVFPUFReg, imm, vfpuBase + voffset[vs]);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
@@ -1005,8 +1063,11 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vmmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (!js.HasNoPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Matrix move (no prefixes)
|
||||
// Matrix move (weird prefixes)
|
||||
// D[N,M] = S[N,M]
|
||||
|
||||
int vs = _VS;
|
||||
@@ -1062,9 +1123,13 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vmscl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (!js.HasNoPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Matrix scale, matrix by scalar (no prefixes)
|
||||
// Matrix scale, matrix by scalar (weird prefixes)
|
||||
// d[N,M] = s[N,M] * t[0]
|
||||
// Note: behaves just slightly differently than a series of vscls.
|
||||
|
||||
int vs = _VS;
|
||||
int vd = _VD;
|
||||
@@ -1100,7 +1165,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VScl(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -1178,7 +1243,7 @@ namespace MIPSComp {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Matrix multiply (wierd prefixes)
|
||||
// Matrix multiply (weird prefixes)
|
||||
// D[0 .. N, 0 .. M] = S[0 .. N, 0 .. M]' * T[0 .. N, 0 .. M]
|
||||
// Note: Behaves as if it's implemented through a series of vdots.
|
||||
// Important: this is a matrix multiply with a pre-transposed S.
|
||||
@@ -1262,10 +1327,14 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vtfm(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_MTX);
|
||||
if (!js.HasNoPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vertex transform, vector by matrix (no prefixes)
|
||||
// Vertex transform, vector by matrix (weird prefixes)
|
||||
// d[N] = s[N*m .. N*m + n-1] dot t[0 .. n-1]
|
||||
// Homogenous means t[n-1] is treated as 1.
|
||||
// Note: this might be implemented as a series of vdots with special prefixes.
|
||||
|
||||
VectorSize sz = GetVecSize(op);
|
||||
MatrixSize msz = GetMtxSize(op);
|
||||
@@ -1281,7 +1350,7 @@ namespace MIPSComp {
|
||||
}
|
||||
// Otherwise, n should already be ins + 1.
|
||||
else if (n != ins + 1) {
|
||||
INVALIDOP;
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
u8 sregs[16], dregs[4], tregs[4];
|
||||
@@ -1364,7 +1433,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VCrs(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || js.HasSPrefix() || js.HasTPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -1378,7 +1447,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_VDet(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || (js.prefixT & 0x000CFCF0) != 0x000E0) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -1391,8 +1460,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vi2x(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || js.HasSPrefix())
|
||||
DISABLE;
|
||||
|
||||
int bits = ((op >> 16) & 2) == 0 ? 8 : 16; // vi2uc/vi2c (0/1), vi2us/vi2s (2/3)
|
||||
@@ -1476,8 +1544,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vx2i(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || js.HasSPrefix())
|
||||
DISABLE;
|
||||
|
||||
int bits = ((op >> 16) & 2) == 0 ? 8 : 16; // vuc2i/vc2i (0/1), vus2i/vs2i (2/3)
|
||||
@@ -1576,13 +1643,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]
|
||||
|
||||
@@ -1622,19 +1688,21 @@ 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) {
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector compare
|
||||
// VFPU_CC[N] = COMPARE(s[N], t[N])
|
||||
@@ -1657,7 +1725,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vcmov(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_COMP);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -1803,7 +1871,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;
|
||||
}
|
||||
|
||||
@@ -1841,7 +1909,7 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vocp(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix()) {
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix() || (js.prefixS & VFPU_NEGATE(1, 1, 1, 1)) != 0) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
@@ -1887,8 +1955,9 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_ColorConv(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector color conversion
|
||||
// d[N] = ConvertTo16(s[N*2]) | (ConvertTo16(s[N*2+1]) << 16)
|
||||
@@ -1898,8 +1967,9 @@ namespace MIPSComp {
|
||||
|
||||
void IRFrontend::Comp_Vbfy(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_VEC);
|
||||
if (js.HasUnknownPrefix())
|
||||
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
|
||||
// Vector butterfly operation
|
||||
// vbfy2: d[0] = s[0] + s[2], d[1] = s[1] + s[3], d[2] = s[0] - s[2], d[3] = s[1] - s[3]
|
||||
@@ -1926,7 +1996,7 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
int subop = (op >> 16) & 0x1F;
|
||||
if (subop == 3) {
|
||||
if (subop == 3 && n == 4) {
|
||||
// vbfy2
|
||||
ir.Write(IROp::FAdd, tempregs[0], sregs[0], sregs[2]);
|
||||
ir.Write(IROp::FAdd, tempregs[1], sregs[1], sregs[3]);
|
||||
|
||||
@@ -99,13 +99,23 @@ namespace MIPSComp {
|
||||
prefixDFlag = PREFIX_UNKNOWN;
|
||||
}
|
||||
|
||||
bool HasSPrefix() const {
|
||||
return (prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4;
|
||||
}
|
||||
|
||||
bool HasTPrefix() const {
|
||||
return (prefixTFlag & PREFIX_KNOWN) == 0 || prefixT != 0xE4;
|
||||
}
|
||||
|
||||
bool HasDPrefix() const {
|
||||
return (prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0;
|
||||
}
|
||||
|
||||
bool MayHavePrefix() const {
|
||||
if (HasUnknownPrefix()) {
|
||||
return true;
|
||||
} else if (prefixS != 0xE4 || prefixT != 0xE4 || prefixD != 0) {
|
||||
return true;
|
||||
} else if (VfpuWriteMask() != 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -118,22 +128,19 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
bool HasNoPrefix() const {
|
||||
return (prefixDFlag & PREFIX_KNOWN) && (prefixSFlag & PREFIX_KNOWN) && (prefixTFlag & PREFIX_KNOWN) && (prefixS == 0xE4 && prefixT == 0xE4 && prefixD == 0);
|
||||
return !HasSPrefix() && !HasTPrefix() && !HasDPrefix();
|
||||
}
|
||||
|
||||
void EatPrefix() {
|
||||
if ((prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4) {
|
||||
if (HasSPrefix())
|
||||
prefixSFlag = PREFIX_KNOWN_DIRTY;
|
||||
prefixS = 0xE4;
|
||||
}
|
||||
if ((prefixTFlag & PREFIX_KNOWN) == 0 || prefixT != 0xE4) {
|
||||
prefixS = 0xE4;
|
||||
if (HasTPrefix())
|
||||
prefixTFlag = PREFIX_KNOWN_DIRTY;
|
||||
prefixT = 0xE4;
|
||||
}
|
||||
if ((prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0) {
|
||||
prefixT = 0xE4;
|
||||
if (HasDPrefix())
|
||||
prefixDFlag = PREFIX_KNOWN_DIRTY;
|
||||
prefixD = 0x0;
|
||||
}
|
||||
prefixD = 0x0;
|
||||
}
|
||||
|
||||
u8 VfpuWriteMask() const {
|
||||
|
||||
+842
-604
File diff suppressed because it is too large.
Load diff
+83
-33
@@ -57,16 +57,16 @@ void GetMatrixRegs(u8 regs[16], MatrixSize N, int matrixReg) {
|
||||
|
||||
int row = 0;
|
||||
int side = 0;
|
||||
int transpose = (matrixReg >> 5) & 1;
|
||||
|
||||
switch (N) {
|
||||
case M_2x2: row = (matrixReg>>5)&2; side = 2; break;
|
||||
case M_3x3: row = (matrixReg>>6)&1; side = 3; break;
|
||||
case M_4x4: row = (matrixReg>>5)&2; side = 4; break;
|
||||
case M_1x1: transpose = 0; row = (matrixReg >> 5) & 3; side = 1; break;
|
||||
case M_2x2: row = (matrixReg >> 5) & 2; side = 2; break;
|
||||
case M_3x3: row = (matrixReg >> 6) & 1; side = 3; break;
|
||||
case M_4x4: row = (matrixReg >> 5) & 2; side = 4; break;
|
||||
default: _assert_msg_(JIT, 0, "%s: Bad matrix size", __FUNCTION__);
|
||||
}
|
||||
|
||||
int transpose = (matrixReg>>5) & 1;
|
||||
|
||||
for (int i = 0; i < side; i++) {
|
||||
for (int j = 0; j < side; j++) {
|
||||
int index = mtx * 4;
|
||||
@@ -176,19 +176,27 @@ void ReadVector(float *rd, VectorSize size, int reg) {
|
||||
}
|
||||
|
||||
void WriteVector(const float *rd, VectorSize size, int reg) {
|
||||
if (size == V_Single) {
|
||||
// Optimize the common case.
|
||||
if (!currentMIPS->VfpuWriteMask(0)) {
|
||||
V(reg) = rd[0];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const int mtx = (reg>>2)&7;
|
||||
const int col = reg & 3;
|
||||
int transpose = (reg>>5)&1;
|
||||
int row = 0;
|
||||
int length = 0;
|
||||
|
||||
switch (size) {
|
||||
case V_Single: V(reg) = rd[0]; return; // transpose = 0; row=(reg>>5)&3; length = 1; break;
|
||||
case V_Single: _dbg_assert_(JIT, 0); return; // transpose = 0; row=(reg>>5)&3; length = 1; break;
|
||||
case V_Pair: row=(reg>>5)&2; length = 2; break;
|
||||
case V_Triple: row=(reg>>6)&1; length = 3; break;
|
||||
case V_Quad: row=(reg>>5)&2; length = 4; break;
|
||||
default: _assert_msg_(JIT, 0, "%s: Bad vector size", __FUNCTION__);
|
||||
}
|
||||
const int mtx = (reg>>2)&7;
|
||||
const int col = reg & 3;
|
||||
int transpose = (reg>>5)&1;
|
||||
|
||||
if (currentMIPS->VfpuWriteMask() == 0) {
|
||||
if (transpose) {
|
||||
@@ -214,30 +222,35 @@ void WriteVector(const float *rd, VectorSize size, int reg) {
|
||||
}
|
||||
}
|
||||
|
||||
u32 VFPURewritePrefix(int ctrl, u32 remove, u32 add) {
|
||||
u32 prefix = currentMIPS->vfpuCtrl[ctrl];
|
||||
return (prefix & ~remove) | add;
|
||||
}
|
||||
|
||||
void ReadMatrix(float *rd, MatrixSize size, int reg) {
|
||||
int mtx = (reg >> 2) & 7;
|
||||
int col = reg & 3;
|
||||
|
||||
int row = 0;
|
||||
int side = 0;
|
||||
int transpose = (reg >> 5) & 1;
|
||||
|
||||
switch (size) {
|
||||
case M_2x2: row = (reg>>5)&2; side = 2; break;
|
||||
case M_3x3: row = (reg>>6)&1; side = 3; break;
|
||||
case M_4x4: row = (reg>>5)&2; side = 4; break;
|
||||
case M_1x1: transpose = 0; row = (reg >> 5) & 3; side = 1; break;
|
||||
case M_2x2: row = (reg >> 5) & 2; side = 2; break;
|
||||
case M_3x3: row = (reg >> 6) & 1; side = 3; break;
|
||||
case M_4x4: row = (reg >> 5) & 2; side = 4; break;
|
||||
default: _assert_msg_(JIT, 0, "%s: Bad matrix size", __FUNCTION__);
|
||||
}
|
||||
|
||||
int transpose = (reg>>5) & 1;
|
||||
|
||||
for (int i = 0; i < side; i++) {
|
||||
for (int j = 0; j < side; j++) {
|
||||
int index = mtx * 4;
|
||||
int index = mtx * 4;
|
||||
if (transpose)
|
||||
index += ((row+i)&3) + ((col+j)&3)*32;
|
||||
else
|
||||
index += ((col+j)&3) + ((row+i)&3)*32;
|
||||
rd[j*4 + i] = V(index);
|
||||
index += ((row+i)&3) + ((col+j)&3)*32;
|
||||
else
|
||||
index += ((col+j)&3) + ((row+i)&3)*32;
|
||||
rd[j*4 + i] = V(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,15 +261,16 @@ void WriteMatrix(const float *rd, MatrixSize size, int reg) {
|
||||
|
||||
int row = 0;
|
||||
int side = 0;
|
||||
int transpose = (reg >> 5) & 1;
|
||||
|
||||
switch (size) {
|
||||
case M_2x2: row = (reg>>5)&2; side = 2; break;
|
||||
case M_3x3: row = (reg>>6)&1; side = 3; break;
|
||||
case M_4x4: row = (reg>>5)&2; side = 4; break;
|
||||
case M_1x1: transpose = 0; row = (reg >> 5) & 3; side = 1; break;
|
||||
case M_2x2: row = (reg >> 5) & 2; side = 2; break;
|
||||
case M_3x3: row = (reg >> 6) & 1; side = 3; break;
|
||||
case M_4x4: row = (reg >> 5) & 2; side = 4; break;
|
||||
default: _assert_msg_(JIT, 0, "%s: Bad matrix size", __FUNCTION__);
|
||||
}
|
||||
|
||||
int transpose = (reg>>5)&1;
|
||||
if (currentMIPS->VfpuWriteMask() != 0) {
|
||||
ERROR_LOG_REPORT(CPU, "Write mask used with vfpu matrix instruction.");
|
||||
}
|
||||
@@ -352,6 +366,7 @@ VectorSize GetVecSize(MIPSOpcode op) {
|
||||
|
||||
VectorSize GetVectorSizeSafe(MatrixSize sz) {
|
||||
switch (sz) {
|
||||
case M_1x1: return V_Single;
|
||||
case M_2x2: return V_Pair;
|
||||
case M_3x3: return V_Triple;
|
||||
case M_4x4: return V_Quad;
|
||||
@@ -367,7 +382,7 @@ VectorSize GetVectorSize(MatrixSize sz) {
|
||||
|
||||
MatrixSize GetMatrixSizeSafe(VectorSize sz) {
|
||||
switch (sz) {
|
||||
case V_Single: return M_Invalid;
|
||||
case V_Single: return M_1x1;
|
||||
case V_Pair: return M_2x2;
|
||||
case V_Triple: return M_3x3;
|
||||
case V_Quad: return M_4x4;
|
||||
@@ -386,7 +401,7 @@ MatrixSize GetMtxSizeSafe(MIPSOpcode op) {
|
||||
int b = (op >> 15) & 1;
|
||||
a += (b << 1);
|
||||
switch (a) {
|
||||
case 0: return M_4x4; // This happens in disassembly of junk
|
||||
case 0: return M_1x1; // This happens in disassembly of junk, but has predictable behavior.
|
||||
case 1: return M_2x2;
|
||||
case 2: return M_3x3;
|
||||
case 3: return M_4x4;
|
||||
@@ -402,6 +417,7 @@ MatrixSize GetMtxSize(MIPSOpcode op) {
|
||||
|
||||
VectorSize MatrixVectorSizeSafe(MatrixSize sz) {
|
||||
switch (sz) {
|
||||
case M_1x1: return V_Single;
|
||||
case M_2x2: return V_Pair;
|
||||
case M_3x3: return V_Triple;
|
||||
case M_4x4: return V_Quad;
|
||||
@@ -417,6 +433,7 @@ VectorSize MatrixVectorSize(MatrixSize sz) {
|
||||
|
||||
int GetMatrixSideSafe(MatrixSize sz) {
|
||||
switch (sz) {
|
||||
case M_1x1: return 1;
|
||||
case M_2x2: return 2;
|
||||
case M_3x3: return 3;
|
||||
case M_4x4: return 4;
|
||||
@@ -425,7 +442,7 @@ int GetMatrixSideSafe(MatrixSize sz) {
|
||||
}
|
||||
|
||||
int GetMatrixSide(MatrixSize sz) {
|
||||
int res = MatrixVectorSizeSafe(sz);
|
||||
int res = GetMatrixSideSafe(sz);
|
||||
_assert_msg_(JIT, res != 0, "%s: Bad matrix size", __FUNCTION__);
|
||||
return res;
|
||||
}
|
||||
@@ -509,6 +526,41 @@ const char *GetMatrixNotation(int reg, MatrixSize size)
|
||||
return hej[yo];
|
||||
}
|
||||
|
||||
bool GetVFPUCtrlMask(int reg, u32 *mask) {
|
||||
switch (reg) {
|
||||
case VFPU_CTRL_SPREFIX:
|
||||
case VFPU_CTRL_TPREFIX:
|
||||
*mask = 0x000FFFFF;
|
||||
return true;
|
||||
case VFPU_CTRL_DPREFIX:
|
||||
*mask = 0x00000FFF;
|
||||
return true;
|
||||
case VFPU_CTRL_CC:
|
||||
*mask = 0x0000003F;
|
||||
return true;
|
||||
case VFPU_CTRL_INF4:
|
||||
*mask = 0xFFFFFFFF;
|
||||
return true;
|
||||
case VFPU_CTRL_RSV5:
|
||||
case VFPU_CTRL_RSV6:
|
||||
case VFPU_CTRL_REV:
|
||||
// Don't change anything, these regs are read only.
|
||||
return false;
|
||||
case VFPU_CTRL_RCX0:
|
||||
case VFPU_CTRL_RCX1:
|
||||
case VFPU_CTRL_RCX2:
|
||||
case VFPU_CTRL_RCX3:
|
||||
case VFPU_CTRL_RCX4:
|
||||
case VFPU_CTRL_RCX5:
|
||||
case VFPU_CTRL_RCX6:
|
||||
case VFPU_CTRL_RCX7:
|
||||
*mask = 0x3FFFFFFF;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float Float16ToFloat32(unsigned short l)
|
||||
{
|
||||
union float2int {
|
||||
@@ -521,19 +573,17 @@ float Float16ToFloat32(unsigned short l)
|
||||
int exponent = (float16 >> VFPU_SH_FLOAT16_EXP) & VFPU_MASK_FLOAT16_EXP;
|
||||
unsigned int fraction = float16 & VFPU_MASK_FLOAT16_FRAC;
|
||||
|
||||
float signf = (sign == 1) ? -1.0f : 1.0f;
|
||||
|
||||
float f;
|
||||
if (exponent == VFPU_FLOAT16_EXP_MAX)
|
||||
{
|
||||
if (fraction == 0)
|
||||
f = std::numeric_limits<float>::infinity(); //(*info->fprintf_func) (info->stream, "%cInf", signchar);
|
||||
else
|
||||
f = std::numeric_limits<float>::quiet_NaN(); //(*info->fprintf_func) (info->stream, "%cNaN", signchar);
|
||||
float2int.i = sign << 31;
|
||||
float2int.i |= 255 << 23;
|
||||
float2int.i |= fraction;
|
||||
f = float2int.f;
|
||||
}
|
||||
else if (exponent == 0 && fraction == 0)
|
||||
{
|
||||
f = 0.0f * signf;
|
||||
f = sign == 1 ? -0.0f : 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ inline int Xpose(int v) {
|
||||
|
||||
// Some games depend on exact values, but sinf() and cosf() aren't always precise.
|
||||
// Stepping down to [0, 2pi) helps, but we also check common exact-result values.
|
||||
// TODO: cos(2) and sin(1) should be -0.0, but doing that gives wrong results (possibly from floorf.)
|
||||
|
||||
inline float vfpu_sin(float angle) {
|
||||
angle -= floorf(angle * 0.25f) * 4.f;
|
||||
@@ -113,12 +114,39 @@ enum VectorSize {
|
||||
};
|
||||
|
||||
enum MatrixSize {
|
||||
M_1x1 = 1,
|
||||
M_2x2 = 2,
|
||||
M_3x3 = 3,
|
||||
M_4x4 = 4,
|
||||
M_Invalid = -1
|
||||
};
|
||||
|
||||
static u32 VFPU_SWIZZLE(int x, int y, int z, int w) {
|
||||
return (x << 0) | (y << 2) | (z << 4) | (w << 6);
|
||||
}
|
||||
|
||||
static u32 VFPU_MASK(int x, int y, int z, int w) {
|
||||
return (x << 0) | (y << 1) | (z << 2) | (w << 3);
|
||||
}
|
||||
|
||||
static u32 VFPU_ANY_SWIZZLE() {
|
||||
return 0x000000FF;
|
||||
}
|
||||
|
||||
static u32 VFPU_ABS(int x, int y, int z, int w) {
|
||||
return VFPU_MASK(x, y, z, w) << 8;
|
||||
}
|
||||
|
||||
static u32 VFPU_CONST(int x, int y, int z, int w) {
|
||||
return VFPU_MASK(x, y, z, w) << 12;
|
||||
}
|
||||
|
||||
static u32 VFPU_NEGATE(int x, int y, int z, int w) {
|
||||
return VFPU_MASK(x, y, z, w) << 16;
|
||||
}
|
||||
|
||||
u32 VFPURewritePrefix(int ctrl, u32 remove, u32 add);
|
||||
|
||||
void ReadMatrix(float *rd, MatrixSize size, int reg);
|
||||
void WriteMatrix(const float *rs, MatrixSize size, int reg);
|
||||
|
||||
@@ -184,4 +212,6 @@ inline int TransposeMatrixReg(int matrixReg) {
|
||||
}
|
||||
int GetVectorOverlap(int reg1, VectorSize size1, int reg2, VectorSize size2);
|
||||
|
||||
bool GetVFPUCtrlMask(int reg, u32 *mask);
|
||||
|
||||
float Float16ToFloat32(unsigned short l);
|
||||
+19
-15
@@ -87,7 +87,7 @@ void Jit::Comp_VPFX(MIPSOpcode op)
|
||||
js.prefixTFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
case 2: // D
|
||||
js.prefixD = data;
|
||||
js.prefixD = data & 0x00000FFF;
|
||||
js.prefixDFlag = JitState::PREFIX_KNOWN_DIRTY;
|
||||
break;
|
||||
}
|
||||
@@ -2528,39 +2528,43 @@ void Jit::Comp_Mftv(MIPSOpcode op) {
|
||||
|
||||
void Jit::Comp_Vmfvc(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE(VFPU_XFER);
|
||||
int vs = _VS;
|
||||
int imm = op & 0xFF;
|
||||
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
||||
fpr.MapRegV(vs, MAP_DIRTY | MAP_NOINIT);
|
||||
if (imm - 128 == VFPU_CTRL_CC) {
|
||||
int vd = _VD;
|
||||
int imm = (op >> 8) & 0x7F;
|
||||
if (imm < VFPU_CTRL_MAX) {
|
||||
fpr.MapRegV(vd, MAP_DIRTY | MAP_NOINIT);
|
||||
if (imm == VFPU_CTRL_CC) {
|
||||
gpr.MapReg(MIPS_REG_VFPUCC, true, false);
|
||||
MOVD_xmm(fpr.VX(vs), gpr.R(MIPS_REG_VFPUCC));
|
||||
MOVD_xmm(fpr.VX(vd), gpr.R(MIPS_REG_VFPUCC));
|
||||
} else {
|
||||
MOVSS(fpr.VX(vs), 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user