Add Sse Opt. for S/Umax_V, S/Umin_V, S/Uaddw_V, S/Usubw_V, Fabs_S/V, Fneg_S/V Inst.; for Fcvtl_V, Fcvtn_V Inst.; and for Fcmp_S Inst.. Add/Improve other Sse Opt.. Add Tests. (#496)
* Update CpuTest.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update InstEmitSimdCmp.cs * Update SoftFloat.cs * Update InstEmitAluHelper.cs * Update InstEmitSimdArithmetic.cs * Update InstEmitSimdHelper.cs * Update VectorHelper.cs * Update InstEmitSimdCvt.cs * Update InstEmitSimdArithmetic.cs * Update CpuTestSimd.cs * Update InstEmitSimdArithmetic.cs * Update OpCodeTable.cs * Update InstEmitSimdArithmetic.cs * Update InstEmitSimdCmp.cs * Update InstEmitSimdCvt.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Create CpuTestSimdFcond.cs * Update OpCodeTable.cs * Update InstEmitSimdMove.cs * Update CpuTestSimdIns.cs * Create CpuTestSimdExt.cs * Nit. * Update PackageReference.
This commit is contained in:
parent
b7613dd4b8
commit
e603b7afbc
16 changed files with 2049 additions and 337 deletions
|
@ -333,7 +333,6 @@ namespace Ryujinx.Tests.Cpu
|
|||
Assert.That(_thread.ThreadState.V29, Is.EqualTo(_unicornEmu.Q[29]));
|
||||
Assert.That(_thread.ThreadState.V30, Is.EqualTo(_unicornEmu.Q[30]));
|
||||
Assert.That(_thread.ThreadState.V31, Is.EqualTo(_unicornEmu.Q[31]));
|
||||
Assert.That(_thread.ThreadState.V31, Is.EqualTo(_unicornEmu.Q[31]));
|
||||
|
||||
Assert.That(_thread.ThreadState.Fpcr, Is.EqualTo(_unicornEmu.Fpcr));
|
||||
Assert.That(_thread.ThreadState.Fpsr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpsr & (int)fpsrMask));
|
||||
|
|
|
@ -39,6 +39,18 @@ namespace Ryujinx.Tests.Cpu
|
|||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _1S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x000000007FFFFFFFul,
|
||||
0x0000000080000000ul, 0x00000000FFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H2S1D_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
|
@ -244,6 +256,24 @@ namespace Ryujinx.Tests.Cpu
|
|||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _F_Cmp_Cmpe_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E202028u, // FCMP S1, #0.0
|
||||
0x1E202038u // FCMPE S1, #0.0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cmp_Cmpe_S_D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E602028u, // FCMP D1, #0.0
|
||||
0x1E602038u // FCMPE D1, #0.0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_S_SD_()
|
||||
{
|
||||
return new uint[]
|
||||
|
@ -336,37 +366,81 @@ namespace Ryujinx.Tests.Cpu
|
|||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Recpx_Sqrt_S_S_()
|
||||
private static uint[] _F_Abs_Neg_Recpx_Sqrt_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E20C020u, // FABS S0, S1
|
||||
0x1E214020u, // FNEG S0, S1
|
||||
0x5EA1F820u, // FRECPX S0, S1
|
||||
0x1E21C020u // FSQRT S0, S1
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Recpx_Sqrt_S_D_()
|
||||
private static uint[] _F_Abs_Neg_Recpx_Sqrt_S_D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E60C020u, // FABS D0, D1
|
||||
0x1E614020u, // FNEG D0, D1
|
||||
0x5EE1F820u, // FRECPX D0, D1
|
||||
0x1E61C020u // FSQRT D0, D1
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Sqrt_V_2S_4S_()
|
||||
private static uint[] _F_Abs_Neg_Sqrt_V_2S_4S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x2EA1F800u // FSQRT V0.2S, V0.2S
|
||||
0x0EA0F800u, // FABS V0.2S, V0.2S
|
||||
0x2EA0F800u, // FNEG V0.2S, V0.2S
|
||||
0x2EA1F800u // FSQRT V0.2S, V0.2S
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Sqrt_V_2D_()
|
||||
private static uint[] _F_Abs_Neg_Sqrt_V_2D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x6EE1F800u // FSQRT V0.2D, V0.2D
|
||||
0x4EE0F800u, // FABS V0.2D, V0.2D
|
||||
0x6EE0F800u, // FNEG V0.2D, V0.2D
|
||||
0x6EE1F800u // FSQRT V0.2D, V0.2D
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x5E21D820u, // SCVTF S0, S1
|
||||
0x7E21D820u // UCVTF S0, S1
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_S_D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x5E61D820u, // SCVTF D0, D1
|
||||
0x7E61D820u // UCVTF D0, D1
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_V_2S_4S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x0E21D800u, // SCVTF V0.2S, V0.2S
|
||||
0x2E21D800u // UCVTF V0.2S, V0.2S
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_V_2D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x4E61D800u, // SCVTF V0.2D, V0.2D
|
||||
0x6E61D800u // UCVTF V0.2D, V0.2D
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -889,6 +963,38 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cmp_Cmpe_S_S([ValueSource("_F_Cmp_Cmpe_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a)
|
||||
{
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cmp_Cmpe_S_D([ValueSource("_F_Cmp_Cmpe_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_F_")] ulong a)
|
||||
{
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_S_SD([ValueSource("_F_Cvt_S_SD_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a)
|
||||
|
@ -1070,12 +1176,12 @@ namespace Ryujinx.Tests.Cpu
|
|||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Recpx_Sqrt_S_S([ValueSource("_F_Recpx_Sqrt_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a)
|
||||
public void F_Abs_Neg_Recpx_Sqrt_S_S([ValueSource("_F_Abs_Neg_Recpx_Sqrt_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a)
|
||||
{
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, z);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
|
@ -1088,12 +1194,12 @@ namespace Ryujinx.Tests.Cpu
|
|||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Recpx_Sqrt_S_D([ValueSource("_F_Recpx_Sqrt_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_F_")] ulong a)
|
||||
public void F_Abs_Neg_Recpx_Sqrt_S_D([ValueSource("_F_Abs_Neg_Recpx_Sqrt_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_F_")] ulong a)
|
||||
{
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE1(z);
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, z);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
|
@ -1106,12 +1212,12 @@ namespace Ryujinx.Tests.Cpu
|
|||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Sqrt_V_2S_4S([ValueSource("_F_Sqrt_V_2S_4S_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_2S_F_")] ulong z,
|
||||
[ValueSource("_2S_F_")] ulong a,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
public void F_Abs_Neg_Sqrt_V_2S_4S([ValueSource("_F_Abs_Neg_Sqrt_V_2S_4S_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_2S_F_")] ulong z,
|
||||
[ValueSource("_2S_F_")] ulong a,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
@ -1130,11 +1236,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Sqrt_V_2D([ValueSource("_F_Sqrt_V_2D_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_1D_F_")] ulong z,
|
||||
[ValueSource("_1D_F_")] ulong a)
|
||||
public void F_Abs_Neg_Sqrt_V_2D([ValueSource("_F_Abs_Neg_Sqrt_V_2D_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_1D_F_")] ulong z,
|
||||
[ValueSource("_1D_F_")] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
|
@ -1460,6 +1566,68 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_S_S([ValueSource("_SU_Cvt_F_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_")] [Random(RndCnt)] ulong a)
|
||||
{
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_S_D([ValueSource("_SU_Cvt_F_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong a)
|
||||
{
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE1(z);
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_V_2S_4S([ValueSource("_SU_Cvt_F_V_2S_4S_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a * q);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_V_2D([ValueSource("_SU_Cvt_F_V_2D_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Sha1h_Sha1su1_V([ValueSource("_Sha1h_Sha1su1_V_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
|
|
73
Ryujinx.Tests/Cpu/CpuTestSimdExt.cs
Normal file
73
Ryujinx.Tests/Cpu/CpuTestSimdExt.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
#define SimdExt
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Runtime.Intrinsics;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdExt")]
|
||||
public sealed class CpuTestSimdExt : CpuTest
|
||||
{
|
||||
#if SimdExt
|
||||
|
||||
#region "ValueSource"
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("EXT <Vd>.8B, <Vn>.8B, <Vm>.8B, #<index>")]
|
||||
public void Ext_V_8B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong b,
|
||||
[Range(0u, 7u)] uint index)
|
||||
{
|
||||
uint imm4 = index & 0x7u;
|
||||
|
||||
uint opcode = 0x2E000000; // EXT V0.8B, V0.8B, V0.8B, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
Vector128<float> v2 = MakeVectorE0(b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EXT <Vd>.16B, <Vn>.16B, <Vm>.16B, #<index>")]
|
||||
public void Ext_V_16B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong b,
|
||||
[Range(0u, 15u)] uint index)
|
||||
{
|
||||
uint imm4 = index & 0xFu;
|
||||
|
||||
uint opcode = 0x6E000000; // EXT V0.16B, V0.16B, V0.16B, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
Vector128<float> v2 = MakeVectorE0E1(b, b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
178
Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs
Normal file
178
Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs
Normal file
|
@ -0,0 +1,178 @@
|
|||
#define SimdFcond
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Intrinsics;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdFcond")]
|
||||
public sealed class CpuTestSimdFcond : CpuTest
|
||||
{
|
||||
#if SimdFcond
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1D_F_()
|
||||
{
|
||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||
yield return 0x8010000000000000ul; // -Min Normal
|
||||
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||
yield return 0x0010000000000000ul; // +Min Normal
|
||||
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000000000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFFF0000000000000ul; // -Infinity
|
||||
yield return 0x7FF0000000000000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalD();
|
||||
ulong rnd2 = GenSubnormalD();
|
||||
|
||||
yield return rnd1;
|
||||
yield return rnd2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _F_Ccmp_Ccmpe_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E220420u, // FCCMP S1, S2, #0, EQ
|
||||
0x1E220430u // FCCMPE S1, S2, #0, EQ
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Ccmp_Ccmpe_S_D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E620420u, // FCCMP D1, D2, #0, EQ
|
||||
0x1E620430u // FCCMPE D1, D2, #0, EQ
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntNzcv = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Ccmp_Ccmpe_S_S([ValueSource("_F_Ccmp_Ccmpe_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a,
|
||||
[ValueSource("_1S_F_")] ulong b,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
opcodes |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
Vector128<float> v2 = MakeVectorE0(b);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, v2: v2, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Ccmp_Ccmpe_S_D([ValueSource("_F_Ccmp_Ccmpe_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_F_")] ulong a,
|
||||
[ValueSource("_1D_F_")] ulong b,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
opcodes |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
Vector128<float> v2 = MakeVectorE0(b);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, v2: v2, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -18,6 +18,24 @@ namespace Ryujinx.Tests.Cpu
|
|||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B4H_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
|
@ -89,6 +107,186 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP B0, V1.B[<index>]")]
|
||||
public void Dup_S_B([ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP H0, V1.H[<index>]")]
|
||||
public void Dup_S_H([ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP S0, V1.S[<index>]")]
|
||||
public void Dup_S_S([ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP D0, V1.D[<index>]")]
|
||||
public void Dup_S_D([ValueSource("_1D_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 1u)] uint index)
|
||||
{
|
||||
const int size = 3;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.B[<index>]")]
|
||||
public void Dup_V_8B_16B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 15u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.H[<index>]")]
|
||||
public void Dup_V_4H_8H([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_4H_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.S[<index>]")]
|
||||
public void Dup_V_2S_4S([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_2S_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 3u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.D[<index>]")]
|
||||
public void Dup_V_2D([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_1D_")] [Random(RndCnt)] ulong a,
|
||||
[Range(0u, 1u)] uint index,
|
||||
[Values(0b1u)] uint q) // <2D>
|
||||
{
|
||||
const int size = 3;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMOV <Wd>, <Vn>.<Ts>[<index>]")]
|
||||
public void Smov_S_W([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
|
|
|
@ -250,6 +250,24 @@ namespace Ryujinx.Tests.Cpu
|
|||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cmp_Cmpe_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E222020u, // FCMP S1, S2
|
||||
0x1E222030u // FCMPE S1, S2
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cmp_Cmpe_S_D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x1E622020u, // FCMP D1, D2
|
||||
0x1E622030u // FCMPE D1, D2
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Madd_Msub_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
|
@ -316,6 +334,24 @@ namespace Ryujinx.Tests.Cpu
|
|||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mla_Mls_V_2S_4S_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x0E20CC00u, // FMLA V0.2S, V0.2S, V0.2S
|
||||
0x0EA0CC00u // FMLS V0.2S, V0.2S, V0.2S
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mla_Mls_V_2D_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x4E60CC00u, // FMLA V0.2D, V0.2D, V0.2D
|
||||
0x4EE0CC00u // FMLS V0.2D, V0.2D, V0.2D
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Recps_Rsqrts_S_S_()
|
||||
{
|
||||
return new uint[]
|
||||
|
@ -372,6 +408,28 @@ namespace Ryujinx.Tests.Cpu
|
|||
0x5E006000u // SHA256SU1 V0.4S, V0.4S, V0.4S
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _S_Max_Min_P_V_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x0E206400u, // SMAX V0.8B, V0.8B, V0.8B
|
||||
0x0E20A400u, // SMAXP V0.8B, V0.8B, V0.8B
|
||||
0x0E206C00u, // SMIN V0.8B, V0.8B, V0.8B
|
||||
0x0E20AC00u // SMINP V0.8B, V0.8B, V0.8B
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _U_Max_Min_P_V_()
|
||||
{
|
||||
return new uint[]
|
||||
{
|
||||
0x2E206400u, // UMAX V0.8B, V0.8B, V0.8B
|
||||
0x2E20A400u, // UMAXP V0.8B, V0.8B, V0.8B
|
||||
0x2E206C00u, // UMIN V0.8B, V0.8B, V0.8B
|
||||
0x2E20AC00u // UMINP V0.8B, V0.8B, V0.8B
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
@ -1248,6 +1306,42 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc | Fpsr.Dzc | Fpsr.Idc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cmp_Cmpe_S_S([ValueSource("_F_Cmp_Cmpe_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a,
|
||||
[ValueSource("_1S_F_")] ulong b)
|
||||
{
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
Vector128<float> v2 = MakeVectorE0(b);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, v2: v2, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cmp_Cmpe_S_D([ValueSource("_F_Cmp_Cmpe_S_D_")] uint opcodes,
|
||||
[ValueSource("_1D_F_")] ulong a,
|
||||
[ValueSource("_1D_F_")] ulong b)
|
||||
{
|
||||
Vector128<float> v1 = MakeVectorE0(a);
|
||||
Vector128<float> v2 = MakeVectorE0(b);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, v2: v2, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Madd_Msub_S_S([ValueSource("_F_Madd_Msub_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a,
|
||||
|
@ -1384,6 +1478,58 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc | Fpsr.Idc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Mla_Mls_V_2S_4S([ValueSource("_F_Mla_Mls_V_2S_4S_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_2S_F_")] ulong z,
|
||||
[ValueSource("_2S_F_")] ulong a,
|
||||
[ValueSource("_2S_F_")] ulong b,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a * q);
|
||||
Vector128<float> v2 = MakeVectorE0E1(b, b * q);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(Fpsr.Ioc | Fpsr.Idc, FpSkips.IfUnderflow, FpTolerances.UpToOneUlpsS);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Mla_Mls_V_2D([ValueSource("_F_Mla_Mls_V_2D_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_1D_F_")] ulong z,
|
||||
[ValueSource("_1D_F_")] ulong a,
|
||||
[ValueSource("_1D_F_")] ulong b)
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a);
|
||||
Vector128<float> v2 = MakeVectorE0E1(b, b);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(Fpsr.Ioc | Fpsr.Idc, FpSkips.IfUnderflow, FpTolerances.UpToOneUlpsD);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Recps_Rsqrts_S_S([ValueSource("_F_Recps_Rsqrts_S_S_")] uint opcodes,
|
||||
[ValueSource("_1S_F_")] ulong a,
|
||||
|
@ -2036,6 +2182,30 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void S_Max_Min_P_V([ValueSource("_S_Max_Min_P_V_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size, // Q0: <8B, 4H, 2S>
|
||||
[Values(0b0u, 0b1u)] uint q) // Q1: <16B, 8H, 4S>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((size & 3) << 22);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a * q);
|
||||
Vector128<float> v2 = MakeVectorE0E1(b, b * q);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMLAL{2} <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Tb>")]
|
||||
public void Smlal_V_8B8H_4H4S_2S2D([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
|
@ -3068,6 +3238,30 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void U_Max_Min_P_V([ValueSource("_U_Max_Min_P_V_")] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong a,
|
||||
[ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size, // Q0: <8B, 4H, 2S>
|
||||
[Values(0b0u, 0b1u)] uint q) // Q1: <16B, 8H, 4S>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((size & 3) << 22);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
Vector128<float> v0 = MakeVectorE0E1(z, z);
|
||||
Vector128<float> v1 = MakeVectorE0E1(a, a * q);
|
||||
Vector128<float> v2 = MakeVectorE0E1(b, b * q);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMLAL{2} <Vd>.<Ta>, <Vn>.<Tb>, <Vm>.<Tb>")]
|
||||
public void Umlal_V_8B8H_4H4S_2S2D([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.0" />
|
||||
<PackageReference Include="System.Runtime.Intrinsics.Experimental" Version="4.5.0-rc1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue