aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Tests/Cpu/CpuTest.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Tests/Cpu/CpuTest.cs')
-rw-r--r--Ryujinx.Tests/Cpu/CpuTest.cs147
1 files changed, 102 insertions, 45 deletions
diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs
index 2c047248..4f5fba9d 100644
--- a/Ryujinx.Tests/Cpu/CpuTest.cs
+++ b/Ryujinx.Tests/Cpu/CpuTest.cs
@@ -12,10 +12,14 @@ namespace Ryujinx.Tests.Cpu
[TestFixture]
public class CpuTest
{
- private ulong _currAddress;
- private ulong _size;
+ protected const ulong Size = 0x1000;
+ protected const ulong CodeBaseAddress = 0x1000;
+ protected const ulong DataBaseAddress = CodeBaseAddress + Size;
+
+ private const bool Ignore_FpcrFz_FpcrDn = false;
+ private const bool IgnoreAllExcept_FpsrQc = false;
- private ulong _entryPoint;
+ private ulong _currAddress;
private MemoryBlock _ram;
@@ -28,6 +32,8 @@ namespace Ryujinx.Tests.Cpu
private static bool _unicornAvailable;
private UnicornAArch64 _unicornEmu;
+ private bool _usingMemory;
+
static CpuTest()
{
_unicornAvailable = UnicornAArch64.IsAvailable();
@@ -41,14 +47,11 @@ namespace Ryujinx.Tests.Cpu
[SetUp]
public void Setup()
{
- _currAddress = 0x1000;
- _size = 0x1000;
-
- _entryPoint = _currAddress;
+ _currAddress = CodeBaseAddress;
- _ram = new MemoryBlock(_size);
- _memory = new MemoryManager(_ram, 1UL << 16);
- _memory.Map(_currAddress, 0, _size);
+ _ram = new MemoryBlock(Size * 2);
+ _memory = new MemoryManager(_ram, 1ul << 16);
+ _memory.Map(CodeBaseAddress, 0, Size * 2);
_context = CpuContext.CreateExecutionContext();
@@ -57,8 +60,9 @@ namespace Ryujinx.Tests.Cpu
if (_unicornAvailable)
{
_unicornEmu = new UnicornAArch64();
- _unicornEmu.MemoryMap(_currAddress, _size, MemoryPermission.READ | MemoryPermission.EXEC);
- _unicornEmu.PC = _entryPoint;
+ _unicornEmu.MemoryMap(CodeBaseAddress, Size, MemoryPermission.READ | MemoryPermission.EXEC);
+ _unicornEmu.MemoryMap(DataBaseAddress, Size, MemoryPermission.READ | MemoryPermission.WRITE);
+ _unicornEmu.PC = CodeBaseAddress;
}
}
@@ -73,6 +77,8 @@ namespace Ryujinx.Tests.Cpu
_context = null;
_cpuContext = null;
_unicornEmu = null;
+
+ _usingMemory = false;
}
protected void Reset()
@@ -169,11 +175,11 @@ namespace Ryujinx.Tests.Cpu
protected void ExecuteOpcodes(bool runUnicorn = true)
{
- _cpuContext.Execute(_context, _entryPoint);
+ _cpuContext.Execute(_context, CodeBaseAddress);
if (_unicornAvailable && runUnicorn)
{
- _unicornEmu.RunForCount((_currAddress - _entryPoint - 4) / 4);
+ _unicornEmu.RunForCount((_currAddress - CodeBaseAddress - 4) / 4);
}
}
@@ -199,6 +205,11 @@ namespace Ryujinx.Tests.Cpu
int fpsr = 0,
bool runUnicorn = true)
{
+ if (Ignore_FpcrFz_FpcrDn)
+ {
+ fpcr &= ~((int)FPCR.Fz | (int)FPCR.Dn);
+ }
+
Opcode(opcode);
Opcode(0xD65F03C0); // RET
SetContext(x0, x1, x2, x3, x31, v0, v1, v2, v3, v4, v5, v30, v31, overflow, carry, zero, negative, fpcr, fpsr);
@@ -207,6 +218,30 @@ namespace Ryujinx.Tests.Cpu
return GetContext();
}
+ protected void SetWorkingMemory(ulong offset, byte[] data)
+ {
+ _memory.Write(DataBaseAddress + offset, data);
+
+ if (_unicornAvailable)
+ {
+ _unicornEmu.MemoryWrite(DataBaseAddress + offset, data);
+ }
+
+ _usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
+ }
+
+ protected void SetWorkingMemory(ulong offset, byte data)
+ {
+ _memory.Write(DataBaseAddress + offset, data);
+
+ if (_unicornAvailable)
+ {
+ _unicornEmu.MemoryWrite8(DataBaseAddress + offset, data);
+ }
+
+ _usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
+ }
+
/// <summary>Rounding Mode control field.</summary>
public enum RMode
{
@@ -284,15 +319,20 @@ namespace Ryujinx.Tests.Cpu
return;
}
+ if (IgnoreAllExcept_FpsrQc)
+ {
+ fpsrMask &= Fpsr.Qc;
+ }
+
if (fpSkips != FpSkips.None)
{
ManageFpSkips(fpSkips);
}
- Assert.That(_context.GetX(0), Is.EqualTo(_unicornEmu.X[0]));
- Assert.That(_context.GetX(1), Is.EqualTo(_unicornEmu.X[1]));
- Assert.That(_context.GetX(2), Is.EqualTo(_unicornEmu.X[2]));
- Assert.That(_context.GetX(3), Is.EqualTo(_unicornEmu.X[3]));
+ Assert.That(_context.GetX(0), Is.EqualTo(_unicornEmu.X[0]), "X0");
+ Assert.That(_context.GetX(1), Is.EqualTo(_unicornEmu.X[1]), "X1");
+ Assert.That(_context.GetX(2), Is.EqualTo(_unicornEmu.X[2]), "X2");
+ Assert.That(_context.GetX(3), Is.EqualTo(_unicornEmu.X[3]), "X3");
Assert.That(_context.GetX(4), Is.EqualTo(_unicornEmu.X[4]));
Assert.That(_context.GetX(5), Is.EqualTo(_unicornEmu.X[5]));
Assert.That(_context.GetX(6), Is.EqualTo(_unicornEmu.X[6]));
@@ -321,21 +361,21 @@ namespace Ryujinx.Tests.Cpu
Assert.That(_context.GetX(29), Is.EqualTo(_unicornEmu.X[29]));
Assert.That(_context.GetX(30), Is.EqualTo(_unicornEmu.X[30]));
- Assert.That(_context.GetX(31), Is.EqualTo(_unicornEmu.SP));
+ Assert.That(_context.GetX(31), Is.EqualTo(_unicornEmu.SP), "X31");
if (fpTolerances == FpTolerances.None)
{
- Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]));
+ Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]), "V0");
}
else
{
ManageFpTolerances(fpTolerances);
}
- Assert.That(V128ToSimdValue(_context.GetV(1)), Is.EqualTo(_unicornEmu.Q[1]));
- Assert.That(V128ToSimdValue(_context.GetV(2)), Is.EqualTo(_unicornEmu.Q[2]));
- Assert.That(V128ToSimdValue(_context.GetV(3)), Is.EqualTo(_unicornEmu.Q[3]));
- Assert.That(V128ToSimdValue(_context.GetV(4)), Is.EqualTo(_unicornEmu.Q[4]));
- Assert.That(V128ToSimdValue(_context.GetV(5)), Is.EqualTo(_unicornEmu.Q[5]));
+ Assert.That(V128ToSimdValue(_context.GetV(1)), Is.EqualTo(_unicornEmu.Q[1]), "V1");
+ Assert.That(V128ToSimdValue(_context.GetV(2)), Is.EqualTo(_unicornEmu.Q[2]), "V2");
+ Assert.That(V128ToSimdValue(_context.GetV(3)), Is.EqualTo(_unicornEmu.Q[3]), "V3");
+ Assert.That(V128ToSimdValue(_context.GetV(4)), Is.EqualTo(_unicornEmu.Q[4]), "V4");
+ Assert.That(V128ToSimdValue(_context.GetV(5)), Is.EqualTo(_unicornEmu.Q[5]), "V5");
Assert.That(V128ToSimdValue(_context.GetV(6)), Is.EqualTo(_unicornEmu.Q[6]));
Assert.That(V128ToSimdValue(_context.GetV(7)), Is.EqualTo(_unicornEmu.Q[7]));
Assert.That(V128ToSimdValue(_context.GetV(8)), Is.EqualTo(_unicornEmu.Q[8]));
@@ -360,16 +400,27 @@ namespace Ryujinx.Tests.Cpu
Assert.That(V128ToSimdValue(_context.GetV(27)), Is.EqualTo(_unicornEmu.Q[27]));
Assert.That(V128ToSimdValue(_context.GetV(28)), Is.EqualTo(_unicornEmu.Q[28]));
Assert.That(V128ToSimdValue(_context.GetV(29)), Is.EqualTo(_unicornEmu.Q[29]));
- Assert.That(V128ToSimdValue(_context.GetV(30)), Is.EqualTo(_unicornEmu.Q[30]));
- Assert.That(V128ToSimdValue(_context.GetV(31)), Is.EqualTo(_unicornEmu.Q[31]));
+ Assert.That(V128ToSimdValue(_context.GetV(30)), Is.EqualTo(_unicornEmu.Q[30]), "V30");
+ Assert.That(V128ToSimdValue(_context.GetV(31)), Is.EqualTo(_unicornEmu.Q[31]), "V31");
+
+ Assert.That((int)_context.Fpcr, Is.EqualTo(_unicornEmu.Fpcr), "Fpcr");
+ Assert.That((int)_context.Fpsr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpsr & (int)fpsrMask), "Fpsr");
- Assert.That((int)_context.Fpcr, Is.EqualTo(_unicornEmu.Fpcr));
- Assert.That((int)_context.Fpsr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpsr & (int)fpsrMask));
+ Assert.Multiple(() =>
+ {
+ Assert.That(_context.GetPstateFlag(PState.VFlag), Is.EqualTo(_unicornEmu.OverflowFlag), "VFlag");
+ Assert.That(_context.GetPstateFlag(PState.CFlag), Is.EqualTo(_unicornEmu.CarryFlag), "CFlag");
+ Assert.That(_context.GetPstateFlag(PState.ZFlag), Is.EqualTo(_unicornEmu.ZeroFlag), "ZFlag");
+ Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag), "NFlag");
+ });
+
+ if (_usingMemory)
+ {
+ byte[] mem = _memory.GetSpan(DataBaseAddress, (int)Size).ToArray();
+ byte[] unicornMem = _unicornEmu.MemoryRead(DataBaseAddress, Size);
- Assert.That(_context.GetPstateFlag(PState.VFlag), Is.EqualTo(_unicornEmu.OverflowFlag));
- Assert.That(_context.GetPstateFlag(PState.CFlag), Is.EqualTo(_unicornEmu.CarryFlag));
- Assert.That(_context.GetPstateFlag(PState.ZFlag), Is.EqualTo(_unicornEmu.ZeroFlag));
- Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag));
+ Assert.That(mem, Is.EqualTo(unicornMem), "Data");
+ }
}
private void ManageFpSkips(FpSkips fpSkips)
@@ -418,14 +469,17 @@ namespace Ryujinx.Tests.Cpu
if (IsNormalOrSubnormalS(_unicornEmu.Q[0].AsFloat()) &&
IsNormalOrSubnormalS(_context.GetV(0).As<float>()))
{
- Assert.That (_context.GetV(0).Extract<float>(0),
- Is.EqualTo(_unicornEmu.Q[0].GetFloat(0)).Within(1).Ulps);
- Assert.That (_context.GetV(0).Extract<float>(1),
- Is.EqualTo(_unicornEmu.Q[0].GetFloat(1)).Within(1).Ulps);
- Assert.That (_context.GetV(0).Extract<float>(2),
- Is.EqualTo(_unicornEmu.Q[0].GetFloat(2)).Within(1).Ulps);
- Assert.That (_context.GetV(0).Extract<float>(3),
- Is.EqualTo(_unicornEmu.Q[0].GetFloat(3)).Within(1).Ulps);
+ Assert.Multiple(() =>
+ {
+ Assert.That (_context.GetV(0).Extract<float>(0),
+ Is.EqualTo(_unicornEmu.Q[0].GetFloat(0)).Within(1).Ulps, "V0[0]");
+ Assert.That (_context.GetV(0).Extract<float>(1),
+ Is.EqualTo(_unicornEmu.Q[0].GetFloat(1)).Within(1).Ulps, "V0[1]");
+ Assert.That (_context.GetV(0).Extract<float>(2),
+ Is.EqualTo(_unicornEmu.Q[0].GetFloat(2)).Within(1).Ulps, "V0[2]");
+ Assert.That (_context.GetV(0).Extract<float>(3),
+ Is.EqualTo(_unicornEmu.Q[0].GetFloat(3)).Within(1).Ulps, "V0[3]");
+ });
Console.WriteLine(fpTolerances);
}
@@ -440,10 +494,13 @@ namespace Ryujinx.Tests.Cpu
if (IsNormalOrSubnormalD(_unicornEmu.Q[0].AsDouble()) &&
IsNormalOrSubnormalD(_context.GetV(0).As<double>()))
{
- Assert.That (_context.GetV(0).Extract<double>(0),
- Is.EqualTo(_unicornEmu.Q[0].GetDouble(0)).Within(1).Ulps);
- Assert.That (_context.GetV(0).Extract<double>(1),
- Is.EqualTo(_unicornEmu.Q[0].GetDouble(1)).Within(1).Ulps);
+ Assert.Multiple(() =>
+ {
+ Assert.That (_context.GetV(0).Extract<double>(0),
+ Is.EqualTo(_unicornEmu.Q[0].GetDouble(0)).Within(1).Ulps, "V0[0]");
+ Assert.That (_context.GetV(0).Extract<double>(1),
+ Is.EqualTo(_unicornEmu.Q[0].GetDouble(1)).Within(1).Ulps, "V0[1]");
+ });
Console.WriteLine(fpTolerances);
}