Convert misc CPU tests to xUnit

This commit is contained in:
TSR Berry 2023-07-09 00:05:26 +02:00
parent b16a539468
commit 7acf80b93d
No known key found for this signature in database
GPG key ID: 52353C0A4CCA15E2
2 changed files with 178 additions and 142 deletions

View file

@ -1,5 +1,8 @@
// #define Misc #define Misc
using ARMeilleure.State;
using System;
using System.Collections.Generic;
using Xunit; using Xunit;
namespace Ryujinx.Tests.Cpu namespace Ryujinx.Tests.Cpu
@ -43,7 +46,7 @@ namespace Ryujinx.Tests.Cpu
for (int cnt = 1; cnt <= RndCnt; cnt++) for (int cnt = 1; cnt <= RndCnt; cnt++)
{ {
ulong grbg = TestContext.CurrentContext.Random.NextUInt(); ulong grbg = Random.Shared.NextUInt();
ulong rnd1 = GenNormalS(); ulong rnd1 = GenNormalS();
ulong rnd2 = GenSubnormalS(); ulong rnd2 = GenSubnormalS();
@ -60,15 +63,44 @@ namespace Ryujinx.Tests.Cpu
private static readonly bool _noNaNs = false; private static readonly bool _noNaNs = false;
#region "AluImm & Csel" #region "AluImm & Csel"
[Test, Pairwise] private static readonly ulong[] _testDataXn =
public void Adds_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul, {
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn, 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
[Values(0u, 4095u)] uint imm, 0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul,
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12> };
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
private static readonly uint[] _testDataWn =
{
0x00000000u, 0x7FFFFFFFu,
0x80000000u, 0xFFFFFFFFu,
};
private static readonly uint[] _testDataImm =
{
0u, 4095u,
};
private static readonly uint[] _testDataShift =
{
0b00u, 0b01u,
};
private static readonly uint[] _testDataCond =
{
0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC, 0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT, 0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
0b1100u, 0b1101u)] uint cond) // GT, LE> 0b1100u, 0b1101u, // GT, LE>
};
public static readonly MatrixTheoryData<ulong, uint, uint, uint> TestMatrixData_64bit = new(_testDataXn, _testDataImm, _testDataShift, _testDataCond);
public static readonly MatrixTheoryData<uint, uint, uint, uint> TestMatrixData_32bit = new(_testDataWn, _testDataImm, _testDataShift, _testDataCond);
public static readonly RangeTheoryData<uint> TestRangeData = new(0u, 92u, 1u);
[Theory]
[MemberData(nameof(TestMatrixData_64bit))]
public void Adds_Csinc_64bit(ulong xn, uint imm, uint shift, uint cond)
{ {
uint opCmn = 0xB100001F; // ADDS X31, X0, #0, LSL #0 -> CMN X0, #0, LSL #0 uint opCmn = 0xB100001F; // ADDS X31, X0, #0, LSL #0 -> CMN X0, #0, LSL #0
uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE
@ -85,15 +117,9 @@ namespace Ryujinx.Tests.Cpu
CompareAgainstUnicorn(); CompareAgainstUnicorn();
} }
[Test, Pairwise] [Theory]
public void Adds_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu, [MemberData(nameof(TestMatrixData_32bit))]
0x80000000u, 0xFFFFFFFFu)] uint wn, public void Adds_Csinc_32bit(uint wn, uint imm, uint shift, uint cond)
[Values(0u, 4095u)] uint imm,
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
[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)] uint cond) // GT, LE>
{ {
uint opCmn = 0x3100001F; // ADDS W31, W0, #0, LSL #0 -> CMN W0, #0, LSL #0 uint opCmn = 0x3100001F; // ADDS W31, W0, #0, LSL #0 -> CMN W0, #0, LSL #0
uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE
@ -110,15 +136,9 @@ namespace Ryujinx.Tests.Cpu
CompareAgainstUnicorn(); CompareAgainstUnicorn();
} }
[Test, Pairwise] [Theory]
public void Subs_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul, [MemberData(nameof(TestMatrixData_64bit))]
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn, public void Subs_Csinc_64bit(ulong xn, uint imm, uint shift, uint cond)
[Values(0u, 4095u)] uint imm,
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
[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)] uint cond) // GT, LE>
{ {
uint opCmp = 0xF100001F; // SUBS X31, X0, #0, LSL #0 -> CMP X0, #0, LSL #0 uint opCmp = 0xF100001F; // SUBS X31, X0, #0, LSL #0 -> CMP X0, #0, LSL #0
uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE
@ -135,15 +155,9 @@ namespace Ryujinx.Tests.Cpu
CompareAgainstUnicorn(); CompareAgainstUnicorn();
} }
[Test, Pairwise] [Theory]
public void Subs_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu, [MemberData(nameof(TestMatrixData_32bit))]
0x80000000u, 0xFFFFFFFFu)] uint wn, public void Subs_Csinc_32bit(uint wn, uint imm, uint shift, uint cond)
[Values(0u, 4095u)] uint imm,
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
[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)] uint cond) // GT, LE>
{ {
uint opCmp = 0x7100001F; // SUBS W31, W0, #0, LSL #0 -> CMP W0, #0, LSL #0 uint opCmp = 0x7100001F; // SUBS W31, W0, #0, LSL #0 -> CMP W0, #0, LSL #0
uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE
@ -162,9 +176,9 @@ namespace Ryujinx.Tests.Cpu
#endregion #endregion
// Roots. // Roots.
[Explicit] [Theory]
[TestCase(0xFFFFFFFDu)] [InlineData(0xFFFFFFFDu)]
[TestCase(0x00000005u)] [InlineData(0x00000005u)]
public void Misc1(uint a) public void Misc1(uint a)
{ {
// ((a + 3) * (a - 5)) / ((a + 5) * (a - 3)) = 0 // ((a + 3) * (a - 5)) / ((a + 5) * (a - 3)) = 0
@ -191,29 +205,29 @@ namespace Ryujinx.Tests.Cpu
Opcode(0xD65F03C0); Opcode(0xD65F03C0);
ExecuteOpcodes(); ExecuteOpcodes();
Assert.That(GetContext().GetX(0), Is.Zero); Assert.Equal(0ul, GetContext().GetX(0));
} }
// 18 integer solutions. // 18 integer solutions.
[Explicit] [Theory]
[TestCase(-20f, -5f)] [InlineData(-20f, -5f)]
[TestCase(-12f, -6f)] [InlineData(-12f, -6f)]
[TestCase(-12f, 3f)] [InlineData(-12f, 3f)]
[TestCase(-8f, -8f)] [InlineData(-8f, -8f)]
[TestCase(-6f, -12f)] [InlineData(-6f, -12f)]
[TestCase(-5f, -20f)] [InlineData(-5f, -20f)]
[TestCase(-4f, 2f)] [InlineData(-4f, 2f)]
[TestCase(-3f, 12f)] [InlineData(-3f, 12f)]
[TestCase(-2f, 4f)] [InlineData(-2f, 4f)]
[TestCase(2f, -4f)] [InlineData(2f, -4f)]
[TestCase(3f, -12f)] [InlineData(3f, -12f)]
[TestCase(4f, -2f)] [InlineData(4f, -2f)]
[TestCase(5f, 20f)] [InlineData(5f, 20f)]
[TestCase(6f, 12f)] [InlineData(6f, 12f)]
[TestCase(8f, 8f)] [InlineData(8f, 8f)]
[TestCase(12f, -3f)] [InlineData(12f, -3f)]
[TestCase(12f, 6f)] [InlineData(12f, 6f)]
[TestCase(20f, 5f)] [InlineData(20f, 5f)]
public void Misc2(float a, float b) public void Misc2(float a, float b)
{ {
// 1 / ((1 / a + 1 / b) ^ 2) = 16 // 1 / ((1 / a + 1 / b) ^ 2) = 16
@ -238,29 +252,29 @@ namespace Ryujinx.Tests.Cpu
Opcode(0xD65F03C0); Opcode(0xD65F03C0);
ExecuteOpcodes(); ExecuteOpcodes();
Assert.That(GetContext().GetV(0).As<float>(), Is.EqualTo(16f)); Assert.Equal(16f, GetContext().GetV(0).As<float>());
} }
// 18 integer solutions. // 18 integer solutions.
[Explicit] [Theory]
[TestCase(-20d, -5d)] [InlineData(-20d, -5d)]
[TestCase(-12d, -6d)] [InlineData(-12d, -6d)]
[TestCase(-12d, 3d)] [InlineData(-12d, 3d)]
[TestCase(-8d, -8d)] [InlineData(-8d, -8d)]
[TestCase(-6d, -12d)] [InlineData(-6d, -12d)]
[TestCase(-5d, -20d)] [InlineData(-5d, -20d)]
[TestCase(-4d, 2d)] [InlineData(-4d, 2d)]
[TestCase(-3d, 12d)] [InlineData(-3d, 12d)]
[TestCase(-2d, 4d)] [InlineData(-2d, 4d)]
[TestCase(2d, -4d)] [InlineData(2d, -4d)]
[TestCase(3d, -12d)] [InlineData(3d, -12d)]
[TestCase(4d, -2d)] [InlineData(4d, -2d)]
[TestCase(5d, 20d)] [InlineData(5d, 20d)]
[TestCase(6d, 12d)] [InlineData(6d, 12d)]
[TestCase(8d, 8d)] [InlineData(8d, 8d)]
[TestCase(12d, -3d)] [InlineData(12d, -3d)]
[TestCase(12d, 6d)] [InlineData(12d, 6d)]
[TestCase(20d, 5d)] [InlineData(20d, 5d)]
public void Misc3(double a, double b) public void Misc3(double a, double b)
{ {
// 1 / ((1 / a + 1 / b) ^ 2) = 16 // 1 / ((1 / a + 1 / b) ^ 2) = 16
@ -285,11 +299,12 @@ namespace Ryujinx.Tests.Cpu
Opcode(0xD65F03C0); Opcode(0xD65F03C0);
ExecuteOpcodes(); ExecuteOpcodes();
Assert.That(GetContext().GetV(0).As<double>(), Is.EqualTo(16d)); Assert.Equal(16d, GetContext().GetV(0).As<double>());
} }
[Test, Ignore("The Tester supports only one return point.")] [Theory(Skip = "The Tester supports only one return point.")]
public void MiscF([Range(0u, 92u, 1u)] uint a) [MemberData(nameof(TestRangeData))]
public void MiscF(uint a)
{ {
static ulong Fn(uint n) static ulong Fn(uint n)
{ {
@ -352,11 +367,11 @@ namespace Ryujinx.Tests.Cpu
Opcode(0xD65F03C0); Opcode(0xD65F03C0);
ExecuteOpcodes(); ExecuteOpcodes();
Assert.That(GetContext().GetX(0), Is.EqualTo(Fn(a))); Assert.Equal(Fn(a), GetContext().GetX(0));
} }
[Explicit] // This test used to be skipped unless explicitly executed
[Test] [Fact]
public void MiscR() public void MiscR()
{ {
const ulong Result = 5; const ulong Result = 5;
@ -374,7 +389,7 @@ namespace Ryujinx.Tests.Cpu
Opcode(0xD65F03C0); Opcode(0xD65F03C0);
ExecuteOpcodes(); ExecuteOpcodes();
Assert.That(GetContext().GetX(0), Is.EqualTo(Result)); Assert.Equal(Result, GetContext().GetX(0));
Reset(); Reset();
@ -391,57 +406,67 @@ namespace Ryujinx.Tests.Cpu
Opcode(0xD65F03C0); Opcode(0xD65F03C0);
ExecuteOpcodes(); ExecuteOpcodes();
Assert.That(GetContext().GetX(0), Is.EqualTo(Result)); Assert.Equal(Result, GetContext().GetX(0));
} }
[Explicit] // This test used to be skipped unless explicitly executed
[TestCase(0ul)] [Theory]
[TestCase(1ul)] [InlineData(0ul)]
[TestCase(2ul)] [InlineData(1ul)]
[TestCase(42ul)] [InlineData(2ul)]
[InlineData(42ul)]
public void SanityCheck(ulong a) public void SanityCheck(ulong a)
{ {
uint opcode = 0xD503201F; // NOP uint opcode = 0xD503201F; // NOP
ExecutionContext context = SingleOpcode(opcode, x0: a); ExecutionContext context = SingleOpcode(opcode, x0: a);
Assert.That(context.GetX(0), Is.EqualTo(a)); Assert.Equal(a, context.GetX(0));
} }
[Explicit] private static readonly ulong[] _testDataMisc4Displacement =
[Test, Pairwise]
public void Misc4([ValueSource(nameof(_1S_F_))] ulong a,
[ValueSource(nameof(_1S_F_))] ulong b,
[ValueSource(nameof(_1S_F_))] ulong c,
[Values(0ul, 1ul, 2ul, 3ul)] ulong displacement)
{ {
if (!BitConverter.IsLittleEndian) 0ul, 1ul, 2ul, 3ul,
};
public static readonly MatrixTheoryData<ulong, ulong, ulong, ulong> TestDataMisc4 = new(_1S_F_(), _1S_F_(), _1S_F_(), _testDataMisc4Displacement);
// This test used to be skipped unless explicitly executed
[SkippableTheory]
[MemberData(nameof(TestDataMisc4))]
public void Misc4(ulong a, ulong b, ulong c, ulong displacement)
{ {
Assert.Ignore(); Skip.IfNot(BitConverter.IsLittleEndian);
}
byte[] data = new byte[1];
for (ulong gapOffset = 0; gapOffset < displacement; gapOffset++) for (ulong gapOffset = 0; gapOffset < displacement; gapOffset++)
{ {
SetWorkingMemory(gapOffset, TestContext.CurrentContext.Random.NextByte()); Random.Shared.NextBytes(data);
SetWorkingMemory(gapOffset, data[0]);
} }
SetWorkingMemory(0x0 + displacement, BitConverter.GetBytes((uint)b)); SetWorkingMemory(0x0 + displacement, BitConverter.GetBytes((uint)b));
SetWorkingMemory(0x4 + displacement, BitConverter.GetBytes((uint)c)); SetWorkingMemory(0x4 + displacement, BitConverter.GetBytes((uint)c));
SetWorkingMemory(0x8 + displacement, TestContext.CurrentContext.Random.NextByte()); Random.Shared.NextBytes(data);
SetWorkingMemory(0x9 + displacement, TestContext.CurrentContext.Random.NextByte()); SetWorkingMemory(0x8 + displacement, data[0]);
SetWorkingMemory(0xA + displacement, TestContext.CurrentContext.Random.NextByte()); Random.Shared.NextBytes(data);
SetWorkingMemory(0xB + displacement, TestContext.CurrentContext.Random.NextByte()); SetWorkingMemory(0x9 + displacement, data[0]);
Random.Shared.NextBytes(data);
SetWorkingMemory(0xA + displacement, data[0]);
Random.Shared.NextBytes(data);
SetWorkingMemory(0xB + displacement, data[0]);
SetContext( SetContext(
x0: DataBaseAddress + displacement, x0: DataBaseAddress + displacement,
v0: MakeVectorE0E1(a, TestContext.CurrentContext.Random.NextULong()), v0: MakeVectorE0E1(a, Random.Shared.NextULong()),
v1: MakeVectorE0E1(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()), v1: MakeVectorE0E1(Random.Shared.NextULong(), Random.Shared.NextULong()),
v2: MakeVectorE0E1(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()), v2: MakeVectorE0E1(Random.Shared.NextULong(), Random.Shared.NextULong()),
overflow: TestContext.CurrentContext.Random.NextBool(), overflow: Random.Shared.NextBool(),
carry: TestContext.CurrentContext.Random.NextBool(), carry: Random.Shared.NextBool(),
zero: TestContext.CurrentContext.Random.NextBool(), zero: Random.Shared.NextBool(),
negative: TestContext.CurrentContext.Random.NextBool()); negative: Random.Shared.NextBool());
Opcode(0xBD400001); // LDR S1, [X0,#0] Opcode(0xBD400001); // LDR S1, [X0,#0]
Opcode(0xBD400402); // LDR S2, [X0,#4] Opcode(0xBD400402); // LDR S2, [X0,#4]
@ -455,17 +480,20 @@ namespace Ryujinx.Tests.Cpu
CompareAgainstUnicorn(); CompareAgainstUnicorn();
} }
[Explicit] public static readonly EnumerableTheoryData<ulong> TestDataMisc5 = new(_1S_F_());
[Test]
public void Misc5([ValueSource(nameof(_1S_F_))] ulong a) // This test used to be skipped unless explicitly executed
[Theory]
[MemberData(nameof(TestDataMisc5))]
public void Misc5(ulong a)
{ {
SetContext( SetContext(
v0: MakeVectorE0E1(a, TestContext.CurrentContext.Random.NextULong()), v0: MakeVectorE0E1(a, Random.Shared.NextULong()),
v1: MakeVectorE0E1(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()), v1: MakeVectorE0E1(Random.Shared.NextULong(), Random.Shared.NextULong()),
overflow: TestContext.CurrentContext.Random.NextBool(), overflow: Random.Shared.NextBool(),
carry: TestContext.CurrentContext.Random.NextBool(), carry: Random.Shared.NextBool(),
zero: TestContext.CurrentContext.Random.NextBool(), zero: Random.Shared.NextBool(),
negative: TestContext.CurrentContext.Random.NextBool()); negative: Random.Shared.NextBool());
Opcode(0x1E202008); // FCMP S0, #0.0 Opcode(0x1E202008); // FCMP S0, #0.0
Opcode(0x1E2E1001); // FMOV S1, #1.0 Opcode(0x1E2E1001); // FMOV S1, #1.0

View file

@ -1,5 +1,8 @@
// #define Misc32 #define Misc32
using ARMeilleure.State;
using System;
using System.Collections.Generic;
using Xunit; using Xunit;
namespace Ryujinx.Tests.Cpu namespace Ryujinx.Tests.Cpu
@ -43,7 +46,7 @@ namespace Ryujinx.Tests.Cpu
for (int cnt = 1; cnt <= RndCnt; cnt++) for (int cnt = 1; cnt <= RndCnt; cnt++)
{ {
ulong grbg = TestContext.CurrentContext.Random.NextUInt(); ulong grbg = Random.Shared.NextUInt();
ulong rnd1 = GenNormalS(); ulong rnd1 = GenNormalS();
ulong rnd2 = GenSubnormalS(); ulong rnd2 = GenSubnormalS();
@ -59,28 +62,33 @@ namespace Ryujinx.Tests.Cpu
private static readonly bool _noInfs = false; private static readonly bool _noInfs = false;
private static readonly bool _noNaNs = false; private static readonly bool _noNaNs = false;
[Test, Pairwise] private static readonly bool[] _testData_bool =
public void Vmsr_Vcmp_Vmrs([ValueSource(nameof(_1S_F_))] ulong a, {
[ValueSource(nameof(_1S_F_))] ulong b, false,
[Values] bool mode1, true,
[Values] bool mode2, };
[Values] bool mode3)
public static readonly MatrixTheoryData<ulong, ulong, bool, bool, bool> TestData = new(_1S_F_(), _1S_F_(), _testData_bool, _testData_bool, _testData_bool);
[Theory]
[MemberData(nameof(TestData))]
public void Vmsr_Vcmp_Vmrs(ulong a, ulong b, bool mode1, bool mode2, bool mode3)
{ {
V128 v4 = MakeVectorE0(a); V128 v4 = MakeVectorE0(a);
V128 v5 = MakeVectorE0(b); V128 v5 = MakeVectorE0(b);
uint r0 = mode1 uint r0 = mode1
? TestContext.CurrentContext.Random.NextUInt(0xf) << 28 ? Random.Shared.NextUInt(0xf) << 28
: TestContext.CurrentContext.Random.NextUInt(); : Random.Shared.NextUInt();
bool v = mode3 && TestContext.CurrentContext.Random.NextBool(); bool v = mode3 && Random.Shared.NextBool();
bool c = mode3 && TestContext.CurrentContext.Random.NextBool(); bool c = mode3 && Random.Shared.NextBool();
bool z = mode3 && TestContext.CurrentContext.Random.NextBool(); bool z = mode3 && Random.Shared.NextBool();
bool n = mode3 && TestContext.CurrentContext.Random.NextBool(); bool n = mode3 && Random.Shared.NextBool();
int fpscr = mode1 int fpscr = mode1
? (int)TestContext.CurrentContext.Random.NextUInt() ? (int)Random.Shared.NextUInt()
: (int)TestContext.CurrentContext.Random.NextUInt(0xf) << 28; : (int)Random.Shared.NextUInt(0xf) << 28;
SetContext(r0: r0, v4: v4, v5: v5, overflow: v, carry: c, zero: z, negative: n, fpscr: fpscr); SetContext(r0: r0, v4: v4, v5: v5, overflow: v, carry: c, zero: z, negative: n, fpscr: fpscr);