From c9ef25681dc05ff87c6fb7d0da9d555964e201c1 Mon Sep 17 00:00:00 2001
From: MS-DOS1999 <mgnjulien@gmail.com>
Date: Mon, 5 Mar 2018 13:21:19 +0100
Subject: [PATCH] Add Frintx_S, ASRV test, update ADCS, use Assert.Multiple and
 indent (#44)

* add 'ADC 32bit and Overflow' test

* Add WZR/WSP tests

* fix ADC and ADDS

* add ADCS test

* add SBCS test

* indent my code and delete comment

* '/' <- i hate you x)

* remove spacebar char

* remove false tab

* add frintx_S test

* update frintx_S test

* add ASRV test

* fix new line

* fix PR

* fix indent
---
 Ryujinx.Tests/Cpu/CpuTest.cs               |   7 +-
 Ryujinx.Tests/Cpu/CpuTestAlu.cs            | 111 ++++++++++++++-------
 Ryujinx.Tests/Cpu/CpuTestMisc.cs           |   7 +-
 Ryujinx.Tests/Cpu/CpuTestScalar.cs         |   6 +-
 Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs |  78 +++++++++++++++
 5 files changed, 165 insertions(+), 44 deletions(-)
 create mode 100644 Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs

diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs
index a56eeb728..a4a3b33fc 100644
--- a/Ryujinx.Tests/Cpu/CpuTest.cs
+++ b/Ryujinx.Tests/Cpu/CpuTest.cs
@@ -57,7 +57,7 @@ namespace Ryujinx.Tests.Cpu
 
         protected void SetThreadState(ulong X0 = 0, ulong X1 = 0, ulong X2 = 0, ulong X31 = 0,
                                       AVec V0 = default(AVec), AVec V1 = default(AVec), AVec V2 = default(AVec),
-                                      bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false)
+                                      bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false, int Fpcr = 0x0)
         {
             Thread.ThreadState.X0 = X0;
             Thread.ThreadState.X1 = X1;
@@ -70,6 +70,7 @@ namespace Ryujinx.Tests.Cpu
             Thread.ThreadState.Carry = Carry;
             Thread.ThreadState.Zero = Zero;
             Thread.ThreadState.Negative = Negative;
+            Thread.ThreadState.Fpcr = Fpcr;
         }
 
         protected void ExecuteOpcodes()
@@ -92,12 +93,12 @@ namespace Ryujinx.Tests.Cpu
         protected AThreadState SingleOpcode(uint Opcode,
                                             ulong X0 = 0, ulong X1 = 0, ulong X2 = 0, ulong X31 = 0,
                                             AVec V0 = default(AVec), AVec V1 = default(AVec), AVec V2 = default(AVec),
-                                            bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false)
+                                            bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false, int Fpcr = 0x0)
         {
             this.Opcode(Opcode);
             this.Opcode(0xD4200000); // BRK #0
             this.Opcode(0xD65F03C0); // RET
-            SetThreadState(X0, X1, X2, X31, V0, V1, V2, Overflow, Carry, Zero, Negative);
+            SetThreadState(X0, X1, X2, X31, V0, V1, V2, Overflow, Carry, Zero, Negative, Fpcr);
             ExecuteOpcodes();
 
             return GetThreadState();
diff --git a/Ryujinx.Tests/Cpu/CpuTestAlu.cs b/Ryujinx.Tests/Cpu/CpuTestAlu.cs
index 0445c97ab..8116fc7c7 100644
--- a/Ryujinx.Tests/Cpu/CpuTestAlu.cs
+++ b/Ryujinx.Tests/Cpu/CpuTestAlu.cs
@@ -17,20 +17,24 @@ namespace Ryujinx.Tests.Cpu
             Assert.AreEqual(Result, ThreadState.X0);
         }
 
-        [TestCase(0x3A020020u, 2u,          3u,   false, false, false, 5u)]
-        [TestCase(0x3A020020u, 2u,          3u,   true,  false, false, 6u)]
-        [TestCase(0xBA020020u, 2u,          3u,   false, false, false, 5u)]
-        [TestCase(0xBA020020u, 2u,          3u,   true,  false, false, 6u)]
-        [TestCase(0x3A020020u, 0xFFFFFFFEu, 0x1u, true,  true,  true,  0x0u)]
-        public void Adcs(uint Opcode, uint A, uint B, bool CarryState, bool Zero, bool Carry, uint Result)
+        [TestCase(0x3A020020u, 2u,          3u,          false, false, false, false, 5u)]
+        [TestCase(0x3A020020u, 2u,          3u,          true,  false, false, false, 6u)]
+        [TestCase(0xBA020020u, 2u,          3u,          false, false, false, false, 5u)]
+        [TestCase(0xBA020020u, 2u,          3u,          true,  false, false, false, 6u)]
+        [TestCase(0x3A020020u, 0xFFFFFFFEu, 0x1u,        true,  false, true,  true,  0x0u)]
+        [TestCase(0x3A020020u, 0xFFFFFFFFu, 0xFFFFFFFFu, true,  true,  false, true,  0xFFFFFFFFu)]
+        public void Adcs(uint Opcode, uint A, uint B, bool CarryState, bool Negative, bool Zero, bool Carry, uint Result)
         {
             //ADCS (X0/W0), (X1, W1), (X2/W2)
             AThreadState ThreadState = SingleOpcode(Opcode, X1: A, X2: B, Carry: CarryState);
-            Assert.IsFalse(ThreadState.Negative);
-            Assert.IsFalse(ThreadState.Overflow);
-            Assert.AreEqual(Zero, ThreadState.Zero);
-            Assert.AreEqual(Carry, ThreadState.Carry);
-            Assert.AreEqual(Result, ThreadState.X0);
+            Assert.Multiple(() =>
+            {
+                Assert.IsFalse(ThreadState.Overflow);
+                Assert.AreEqual(Negative, ThreadState.Negative);
+                Assert.AreEqual(Zero,     ThreadState.Zero);
+                Assert.AreEqual(Carry,    ThreadState.Carry);
+                Assert.AreEqual(Result,   ThreadState.X0);
+            });
         }
     
         [Test]
@@ -50,11 +54,14 @@ namespace Ryujinx.Tests.Cpu
         {
             //ADDS WZR, WSP, #5
             AThreadState ThreadState = SingleOpcode(0x310017FF, X31: A);
-            Assert.IsFalse(ThreadState.Negative);
-            Assert.AreEqual(Zero, ThreadState.Zero);
-            Assert.AreEqual(Carry, ThreadState.Carry);
-            Assert.IsFalse(ThreadState.Overflow);
-            Assert.AreEqual(A, ThreadState.X31);
+            Assert.Multiple(() =>
+            {
+                Assert.IsFalse(ThreadState.Negative);
+                Assert.IsFalse(ThreadState.Overflow);
+                Assert.AreEqual(Zero,  ThreadState.Zero);
+                Assert.AreEqual(Carry, ThreadState.Carry);
+                Assert.AreEqual(A,     ThreadState.X31);
+            });
         }
 
         [TestCase(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFul, true,  false)]
@@ -65,26 +72,55 @@ namespace Ryujinx.Tests.Cpu
             // ANDS W0, W1, W2
             uint Opcode = 0x6A020020;
             AThreadState ThreadState = SingleOpcode(Opcode, X1: A, X2: B);
-            Assert.AreEqual(Result,   ThreadState.X0);
-            Assert.AreEqual(Negative, ThreadState.Negative);
-            Assert.AreEqual(Zero,     ThreadState.Zero);
+            Assert.Multiple(() =>
+            {
+                Assert.AreEqual(Result,   ThreadState.X0);
+                Assert.AreEqual(Negative, ThreadState.Negative);
+                Assert.AreEqual(Zero,     ThreadState.Zero);
+            });
         }
 
-        [Test]
-        public void OrrBitmasks()
+        [TestCase(0x0000FF44u, 0x00000004u, 0x00000FF4u)]
+        [TestCase(0x00000000u, 0x00000004u, 0x00000000u)]
+        [TestCase(0x0000FF44u, 0x00000008u, 0x000000FFu)]
+        [TestCase(0xFFFFFFFFu, 0x00000004u, 0xFFFFFFFFu)]
+        [TestCase(0xFFFFFFFFu, 0x00000008u, 0xFFFFFFFFu)]
+        [TestCase(0xFFFFFFFFu, 0x00000020u, 0xFFFFFFFFu)]
+        [TestCase(0x0FFFFFFFu, 0x0000001Cu, 0x00000000u)]
+        [TestCase(0x80000000u, 0x0000001Fu, 0xFFFFFFFFu)]
+        [TestCase(0xCAFE0000u, 0x00000020u, 0xCAFE0000u)]
+        public void Asrv32(uint A, uint ShiftValue, uint Result)
         {
-            // ORR W0, WZR, #0x01010101
-            Assert.AreEqual(0x01010101, SingleOpcode(0x3200C3E0).X0);
+            // ASRV W0, W1, W2
+            AThreadState ThreadState = SingleOpcode(0x1AC22820, X1: A, X2: ShiftValue);
+            Assert.AreEqual(Result, ThreadState.X0);
+        }
 
-            Reset();
+        [TestCase(0x000000000000FF44ul, 0x00000004u, 0x0000000000000FF4ul)]
+        [TestCase(0x0000000000000000ul, 0x00000004u, 0x0000000000000000ul)]
+        [TestCase(0x000000000000FF44ul, 0x00000008u, 0x00000000000000FFul)]
+        [TestCase(0x00000000FFFFFFFFul, 0x00000004u, 0x000000000FFFFFFFul)]
+        [TestCase(0x00000000FFFFFFFFul, 0x00000008u, 0x0000000000FFFFFFul)]
+        [TestCase(0x00000000FFFFFFFFul, 0x00000020u, 0x0000000000000000ul)]
+        [TestCase(0x000000000FFFFFFFul, 0x0000001Cu, 0x0000000000000000ul)]
+        [TestCase(0x000CC4488FFFFFFFul, 0x0000001Cu, 0x0000000000CC4488ul)]
+        [TestCase(0xFFFFFFFFFFFFFFFFul, 0x0000001Cu, 0xFFFFFFFFFFFFFFFFul)]
+        [TestCase(0x8000000000000000ul, 0x0000003Fu, 0xFFFFFFFFFFFFFFFFul)]
+        [TestCase(0xCAFE000000000000ul, 0x00000040u, 0xCAFE000000000000ul)]
+        public void Asrv64(ulong A, uint ShiftValue, ulong Result)
+        {
+            // ASRV X0, X1, X2
+            AThreadState ThreadState = SingleOpcode(0x9AC22820, X1: A, X2: ShiftValue);
+            Assert.AreEqual(Result, ThreadState.X0);
+        }
 
-            // ORR W1, WZR, #0x00F000F0
-            Assert.AreEqual(0x00F000F0, SingleOpcode(0x320C8FE1).X1);
-
-            Reset();
-
-            // ORR W2, WZR, #1
-            Assert.AreEqual(0x00000001, SingleOpcode(0x320003E2).X2);
+        [TestCase(0x01010101u, 0x3200C3E2u)]
+        [TestCase(0x00F000F0u, 0x320C8FE2u)]
+        [TestCase(0x00000001u, 0x320003E2u)]
+        public void OrrBitmasks(uint Bitmask, uint Opcode)
+        {
+            // ORR W2, WZR, #Bitmask
+            Assert.AreEqual(Bitmask, SingleOpcode(Opcode).X2);
         }
 
         [Test]
@@ -113,11 +149,14 @@ namespace Ryujinx.Tests.Cpu
         {
             //SBCS (X0/W0), (X1, W1), (X2/W2)
             AThreadState ThreadState = SingleOpcode(Opcode, X1: A, X2: B, Carry: CarryState);
-            Assert.AreEqual(Negative, ThreadState.Negative);
-            Assert.IsFalse(ThreadState.Overflow);
-            Assert.AreEqual(Zero, ThreadState.Zero);
-            Assert.AreEqual(Carry, ThreadState.Carry);
-            Assert.AreEqual(Result, ThreadState.X0);
+            Assert.Multiple(() =>
+            {
+                Assert.IsFalse(ThreadState.Overflow);
+                Assert.AreEqual(Negative, ThreadState.Negative);
+                Assert.AreEqual(Zero,     ThreadState.Zero);
+                Assert.AreEqual(Carry,    ThreadState.Carry);
+                Assert.AreEqual(Result,   ThreadState.X0);
+            });
         }
     }
 }
diff --git a/Ryujinx.Tests/Cpu/CpuTestMisc.cs b/Ryujinx.Tests/Cpu/CpuTestMisc.cs
index 97947b9a9..3a995fe26 100644
--- a/Ryujinx.Tests/Cpu/CpuTestMisc.cs
+++ b/Ryujinx.Tests/Cpu/CpuTestMisc.cs
@@ -197,8 +197,11 @@ namespace Ryujinx.Tests.Cpu
             Opcode(0xD4200000);
             Opcode(0xD65F03C0);
             ExecuteOpcodes();
-            Assert.AreEqual(0, GetThreadState().X0);
-            Assert.IsTrue(GetThreadState().Zero);
+            Assert.Multiple(() =>
+            {
+                Assert.AreEqual(0, GetThreadState().X0);
+                Assert.IsTrue(GetThreadState().Zero);
+            });
         }
 
         [Test]
diff --git a/Ryujinx.Tests/Cpu/CpuTestScalar.cs b/Ryujinx.Tests/Cpu/CpuTestScalar.cs
index ffe01a299..a178be272 100644
--- a/Ryujinx.Tests/Cpu/CpuTestScalar.cs
+++ b/Ryujinx.Tests/Cpu/CpuTestScalar.cs
@@ -14,9 +14,9 @@ namespace Ryujinx.Tests.Cpu
         [TestCase(0x7F7FFFFFu, 0x807FFFFFu, 0x7F7FFFFFu)]
         [TestCase(0x7FC00000u, 0x3F800000u, 0x7FC00000u)]
         [TestCase(0x3F800000u, 0x7FC00000u, 0x7FC00000u)]
-        [TestCase(0x7F800001u, 0x7FC00042u, 0x7FC00001u, Ignore = "NaN test.")]
-        [TestCase(0x7FC00042u, 0x7F800001u, 0x7FC00001u, Ignore = "NaN test.")]
-        [TestCase(0x7FC0000Au, 0x7FC0000Bu, 0x7FC0000Au, Ignore = "NaN test.")]
+        [TestCase(0x7F800001u, 0x7FC00042u, 0x7FC00001u)]
+        [TestCase(0x7FC00042u, 0x7F800001u, 0x7FC00001u)]
+        [TestCase(0x7FC0000Au, 0x7FC0000Bu, 0x7FC0000Au)]
         public void Fmax_S(uint A, uint B, uint Result)
         {
             // FMAX S0, S1, S2
diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs
new file mode 100644
index 000000000..56aaef488
--- /dev/null
+++ b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs
@@ -0,0 +1,78 @@
+using ChocolArm64.State;
+using NUnit.Framework;
+
+namespace Ryujinx.Tests.Cpu
+{
+    public class CpuTestSimdArithmetic : CpuTest
+    {
+    	[TestCase(0x3FE66666u, 'N', false, 0x40000000u)]
+    	[TestCase(0x3F99999Au, 'N', false, 0x3F800000u)]
+    	[TestCase(0x404CCCCDu, 'P', false, 0x40800000u)]
+    	[TestCase(0x40733333u, 'P', false, 0x40800000u)]
+    	[TestCase(0x404CCCCDu, 'M', false, 0x40400000u)]
+    	[TestCase(0x40733333u, 'M', false, 0x40400000u)]
+    	[TestCase(0x3F99999Au, 'Z', false, 0x3F800000u)]
+    	[TestCase(0x3FE66666u, 'Z', false, 0x3F800000u)]
+    	[TestCase(0x00000000u, 'N', false, 0x00000000u)]
+    	[TestCase(0x00000000u, 'P', false, 0x00000000u)]
+    	[TestCase(0x00000000u, 'M', false, 0x00000000u)]
+    	[TestCase(0x00000000u, 'Z', false, 0x00000000u)]
+    	[TestCase(0x80000000u, 'N', false, 0x80000000u)]
+    	[TestCase(0x80000000u, 'P', false, 0x80000000u)]
+    	[TestCase(0x80000000u, 'M', false, 0x80000000u)]
+    	[TestCase(0x80000000u, 'Z', false, 0x80000000u)]
+    	[TestCase(0x7F800000u, 'N', false, 0x7F800000u)]
+    	[TestCase(0x7F800000u, 'P', false, 0x7F800000u)]
+    	[TestCase(0x7F800000u, 'M', false, 0x7F800000u)]
+    	[TestCase(0x7F800000u, 'Z', false, 0x7F800000u)]
+    	[TestCase(0xFF800000u, 'N', false, 0xFF800000u)]
+    	[TestCase(0xFF800000u, 'P', false, 0xFF800000u)]
+    	[TestCase(0xFF800000u, 'M', false, 0xFF800000u)]
+    	[TestCase(0xFF800000u, 'Z', false, 0xFF800000u)]
+    	[TestCase(0xFF800001u, 'N', false, 0xFFC00001u)]
+    	[TestCase(0xFF800001u, 'P', false, 0xFFC00001u)]
+    	[TestCase(0xFF800001u, 'M', false, 0xFFC00001u)]
+    	[TestCase(0xFF800001u, 'Z', false, 0xFFC00001u)]
+    	[TestCase(0xFF800001u, 'N', true,  0x7FC00000u)]
+    	[TestCase(0xFF800001u, 'P', true,  0x7FC00000u)]
+    	[TestCase(0xFF800001u, 'M', true,  0x7FC00000u)]
+    	[TestCase(0xFF800001u, 'Z', true,  0x7FC00000u)]
+    	[TestCase(0x7FC00002u, 'N', false, 0x7FC00002u)]
+    	[TestCase(0x7FC00002u, 'P', false, 0x7FC00002u)]
+    	[TestCase(0x7FC00002u, 'M', false, 0x7FC00002u)]
+    	[TestCase(0x7FC00002u, 'Z', false, 0x7FC00002u)]
+    	[TestCase(0x7FC00002u, 'N', true,  0x7FC00000u)]
+    	[TestCase(0x7FC00002u, 'P', true,  0x7FC00000u)]
+    	[TestCase(0x7FC00002u, 'M', true,  0x7FC00000u)]
+    	[TestCase(0x7FC00002u, 'Z', true,  0x7FC00000u)]
+    	public void Frintx_S(uint A, char RoundType, bool DefaultNaN, uint Result)
+    	{
+        	int FpcrTemp = 0x0;
+        	switch(RoundType)
+        	{
+        		case 'N':
+        		FpcrTemp = 0x0;
+        		break;
+
+        		case 'P':
+        		FpcrTemp = 0x400000;
+        		break;
+
+        		case 'M':
+        		FpcrTemp = 0x800000;
+        		break;
+
+        		case 'Z':
+        		FpcrTemp = 0xC00000;
+        		break;
+        	}
+        	if(DefaultNaN)
+        	{
+        		FpcrTemp |= 1 << 25;
+        	}
+        	AVec V1 = new AVec { X0 = A };
+        	AThreadState ThreadState = SingleOpcode(0x1E274020, V1: V1, Fpcr: FpcrTemp);
+        	Assert.AreEqual(Result, ThreadState.V0.X0);
+        }
+    }
+}