diff --git a/.travis.yml b/.travis.yml index 15c55336c..9c6ca236b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,3 +6,4 @@ dotnet: 2.0.0 script: - dotnet restore - dotnet build + - cd Ryujinx.Tests && dotnet test diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs new file mode 100644 index 000000000..75d8e6b99 --- /dev/null +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -0,0 +1,73 @@ +using ChocolArm64; +using ChocolArm64.Memory; +using ChocolArm64.State; +using NUnit.Framework; +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Ryujinx.Tests.Cpu +{ + [TestFixture] + public partial class CpuTest + { + IntPtr Ram; + AMemoryAlloc Allocator; + AMemory Memory; + + [SetUp] + public void Setup() + { + Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize); + Allocator = new AMemoryAlloc(); + Memory = new AMemory(Ram, Allocator); + Memory.Manager.MapPhys(0x1000, 0x1000, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute); + } + + [TearDown] + public void Teardown() + { + Marshal.FreeHGlobal(Ram); + } + + private void Execute(AThread Thread) + { + AutoResetEvent Wait = new AutoResetEvent(false); + Thread.Registers.Break += (sender, e) => Thread.StopExecution(); + Thread.WorkFinished += (sender, e) => Wait.Set(); + + Wait.Reset(); + Thread.Execute(); + Wait.WaitOne(); + } + + private ARegisters SingleOpcode(uint Opcode, + ulong X0 = 0, ulong X1 = 0, ulong X2 = 0, + AVec V0 = new AVec(), AVec V1 = new AVec(), AVec V2 = new AVec()) + { + Memory.WriteUInt32(0x1000, Opcode); + Memory.WriteUInt32(0x1004, 0xD4200000); // BRK #0 + Memory.WriteUInt32(0x1008, 0xD65F03C0); // RET + + AThread Thread = new AThread(Memory, ThreadPriority.Normal, 0x1000); + Thread.Registers.X0 = X0; + Thread.Registers.X1 = X1; + Thread.Registers.X2 = X2; + Thread.Registers.V0 = V0; + Thread.Registers.V1 = V1; + Thread.Registers.V2 = V2; + Execute(Thread); + return Thread.Registers; + } + + [Test] + public void SanityCheck() + { + uint Opcode = 0xD503201F; // NOP + Assert.AreEqual(SingleOpcode(Opcode, X0: 0).X0, 0); + Assert.AreEqual(SingleOpcode(Opcode, X0: 1).X0, 1); + Assert.AreEqual(SingleOpcode(Opcode, X0: 2).X0, 2); + Assert.AreEqual(SingleOpcode(Opcode, X0: 42).X0, 42); + } + } +} diff --git a/Ryujinx.Tests/Cpu/CpuTestAlu.cs b/Ryujinx.Tests/Cpu/CpuTestAlu.cs new file mode 100644 index 000000000..3b82d7599 --- /dev/null +++ b/Ryujinx.Tests/Cpu/CpuTestAlu.cs @@ -0,0 +1,65 @@ +using ChocolArm64.State; +using NUnit.Framework; + +namespace Ryujinx.Tests.Cpu +{ + [TestFixture] + public partial class CpuTest + { + [Test] + public void Add() + { + // ADD X0, X1, X2 + ARegisters Registers = SingleOpcode(0x8B020020, X1: 1, X2: 2); + Assert.AreEqual(3, Registers.X0); + } + + [Test] + public void Ands() + { + // ANDS W0, W1, W2 + uint Opcode = 0x6A020020; + var tests = new[] + { + new { W1 = 0xFFFFFFFFul, W2 = 0xFFFFFFFFul, Result = 0xFFFFFFFFul, Negative = true, Zero = false }, + new { W1 = 0xFFFFFFFFul, W2 = 0x00000000ul, Result = 0x00000000ul, Negative = false, Zero = true }, + new { W1 = 0x12345678ul, W2 = 0x7324A993ul, Result = 0x12240010ul, Negative = false, Zero = false }, + }; + + foreach (var test in tests) + { + ARegisters Registers = SingleOpcode(Opcode, X1: test.W1, X2: test.W2); + Assert.AreEqual(test.Result, Registers.X0); + Assert.AreEqual(test.Negative, Registers.Negative); + Assert.AreEqual(test.Zero, Registers.Zero); + } + } + + [Test] + public void OrrBitmasks() + { + // ORR W0, WZR, #0x01010101 + Assert.AreEqual(0x01010101, SingleOpcode(0x3200C3E0).X0); + // ORR W1, WZR, #0x00F000F0 + Assert.AreEqual(0x00F000F0, SingleOpcode(0x320C8FE1).X1); + // ORR W2, WZR, #1 + Assert.AreEqual(0x00000001, SingleOpcode(0x320003E2).X2); + } + + [Test] + public void RevX0X0() + { + // REV X0, X0 + ARegisters Registers = SingleOpcode(0xDAC00C00, X0: 0xAABBCCDDEEFF1100); + Assert.AreEqual(0x0011FFEEDDCCBBAA, Registers.X0); + } + + [Test] + public void RevW1W1() + { + // REV W1, W1 + ARegisters Registers = SingleOpcode(0x5AC00821, X1: 0x12345678); + Assert.AreEqual(0x78563412, Registers.X1); + } + } +} diff --git a/Ryujinx.Tests/Ryujinx.Tests.csproj b/Ryujinx.Tests/Ryujinx.Tests.csproj new file mode 100644 index 000000000..f8b430e62 --- /dev/null +++ b/Ryujinx.Tests/Ryujinx.Tests.csproj @@ -0,0 +1,17 @@ + + + netcoreapp2.0 + false + + + false + + + + + + + + + + diff --git a/Ryujinx.sln b/Ryujinx.sln index c75364f71..777539885 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26730.8 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx", "Ryujinx\Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Tests", "Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {074045D4-3ED2-4711-9169-E385F2BFB5A0}.Debug|Any CPU.Build.0 = Debug|Any CPU {074045D4-3ED2-4711-9169-E385F2BFB5A0}.Release|Any CPU.ActiveCfg = Release|Any CPU {074045D4-3ED2-4711-9169-E385F2BFB5A0}.Release|Any CPU.Build.0 = Release|Any CPU + {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Ryujinx/Cpu/AThread.cs b/Ryujinx/Cpu/AThread.cs index 93331825c..400e700dd 100644 --- a/Ryujinx/Cpu/AThread.cs +++ b/Ryujinx/Cpu/AThread.cs @@ -5,7 +5,7 @@ using System.Threading; namespace ChocolArm64 { - class AThread + public class AThread { public ARegisters Registers { get; private set; } public AMemory Memory { get; private set; } diff --git a/Ryujinx.conf b/Ryujinx/Ryujinx.conf similarity index 100% rename from Ryujinx.conf rename to Ryujinx/Ryujinx.conf diff --git a/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj similarity index 100% rename from Ryujinx.csproj rename to Ryujinx/Ryujinx.csproj diff --git a/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs similarity index 100% rename from GLScreen.cs rename to Ryujinx/Ui/GLScreen.cs diff --git a/Program.cs b/Ryujinx/Ui/Program.cs similarity index 100% rename from Program.cs rename to Ryujinx/Ui/Program.cs