From 2cb8bd7006e6e22798a6e44881f3e03d2fe637c5 Mon Sep 17 00:00:00 2001
From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>
Date: Tue, 1 Sep 2020 01:48:21 +0200
Subject: [PATCH] CPU (A64): Add Scvtf_S_Fixed & Ucvtf_S_Fixed with Tests.
 (#1492)

---
 ARMeilleure/Decoders/OpCodeTable.cs         |  2 +
 ARMeilleure/Instructions/InstEmitSimdCvt.cs | 52 +++++++++++---------
 ARMeilleure/Instructions/InstName.cs        |  2 +
 Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs       | 54 +++++++++++++++++++++
 4 files changed, 88 insertions(+), 22 deletions(-)

diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs
index 4daccfdbf4..c43c9aac8d 100644
--- a/ARMeilleure/Decoders/OpCodeTable.cs
+++ b/ARMeilleure/Decoders/OpCodeTable.cs
@@ -454,6 +454,7 @@ namespace ARMeilleure.Decoders
             SetA64("x00111100x100010000000xxxxxxxxxx", InstName.Scvtf_Gp,        InstEmit.Scvtf_Gp,        typeof(OpCodeSimdCvt));
             SetA64(">00111100x000010>xxxxxxxxxxxxxxx", InstName.Scvtf_Gp_Fixed,  InstEmit.Scvtf_Gp_Fixed,  typeof(OpCodeSimdCvt));
             SetA64("010111100x100001110110xxxxxxxxxx", InstName.Scvtf_S,         InstEmit.Scvtf_S,         typeof(OpCodeSimd));
+            SetA64("010111110>>xxxxx111001xxxxxxxxxx", InstName.Scvtf_S_Fixed,   InstEmit.Scvtf_S_Fixed,   typeof(OpCodeSimdShImm));
             SetA64("0>0011100<100001110110xxxxxxxxxx", InstName.Scvtf_V,         InstEmit.Scvtf_V,         typeof(OpCodeSimd));
             SetA64("0x001111001xxxxx111001xxxxxxxxxx", InstName.Scvtf_V_Fixed,   InstEmit.Scvtf_V_Fixed,   typeof(OpCodeSimdShImm));
             SetA64("0100111101xxxxxx111001xxxxxxxxxx", InstName.Scvtf_V_Fixed,   InstEmit.Scvtf_V_Fixed,   typeof(OpCodeSimdShImm));
@@ -576,6 +577,7 @@ namespace ARMeilleure.Decoders
             SetA64("x00111100x100011000000xxxxxxxxxx", InstName.Ucvtf_Gp,        InstEmit.Ucvtf_Gp,        typeof(OpCodeSimdCvt));
             SetA64(">00111100x000011>xxxxxxxxxxxxxxx", InstName.Ucvtf_Gp_Fixed,  InstEmit.Ucvtf_Gp_Fixed,  typeof(OpCodeSimdCvt));
             SetA64("011111100x100001110110xxxxxxxxxx", InstName.Ucvtf_S,         InstEmit.Ucvtf_S,         typeof(OpCodeSimd));
+            SetA64("011111110>>xxxxx111001xxxxxxxxxx", InstName.Ucvtf_S_Fixed,   InstEmit.Ucvtf_S_Fixed,   typeof(OpCodeSimdShImm));
             SetA64("0>1011100<100001110110xxxxxxxxxx", InstName.Ucvtf_V,         InstEmit.Ucvtf_V,         typeof(OpCodeSimd));
             SetA64("0x101111001xxxxx111001xxxxxxxxxx", InstName.Ucvtf_V_Fixed,   InstEmit.Ucvtf_V_Fixed,   typeof(OpCodeSimdShImm));
             SetA64("0110111101xxxxxx111001xxxxxxxxxx", InstName.Ucvtf_V_Fixed,   InstEmit.Ucvtf_V_Fixed,   typeof(OpCodeSimdShImm));
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
index 9696fa2876..edcf35d5ad 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
@@ -494,15 +494,19 @@ namespace ARMeilleure.Instructions
             }
             else
             {
-                OpCodeSimd op = (OpCodeSimd)context.CurrOp;
+                EmitCvtf(context, signed: true, scalar: true);
+            }
+        }
 
-                int sizeF = op.Size & 1;
-
-                Operand res = EmitVectorLongExtract(context, op.Rn, 0, sizeF + 2);
-
-                res = EmitFPConvert(context, res, op.Size, signed: true);
-
-                context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
+        public static void Scvtf_S_Fixed(ArmEmitterContext context)
+        {
+            if (Optimizations.UseSse2)
+            {
+                EmitSse2ScvtfOp(context, scalar: true);
+            }
+            else
+            {
+                EmitCvtf(context, signed: true, scalar: true);
             }
         }
 
@@ -514,7 +518,7 @@ namespace ARMeilleure.Instructions
             }
             else
             {
-                EmitVectorCvtf(context, signed: true);
+                EmitCvtf(context, signed: true, scalar: false);
             }
         }
 
@@ -526,7 +530,7 @@ namespace ARMeilleure.Instructions
             }
             else
             {
-                EmitVectorCvtf(context, signed: true);
+                EmitCvtf(context, signed: true, scalar: false);
             }
         }
 
@@ -562,15 +566,19 @@ namespace ARMeilleure.Instructions
             }
             else
             {
-                OpCodeSimd op = (OpCodeSimd)context.CurrOp;
+                EmitCvtf(context, signed: false, scalar: true);
+            }
+        }
 
-                int sizeF = op.Size & 1;
-
-                Operand ne = EmitVectorLongExtract(context, op.Rn, 0, sizeF + 2);
-
-                Operand res = EmitFPConvert(context, ne, sizeF, signed: false);
-
-                context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
+        public static void Ucvtf_S_Fixed(ArmEmitterContext context)
+        {
+            if (Optimizations.UseSse2)
+            {
+                EmitSse2UcvtfOp(context, scalar: true);
+            }
+            else
+            {
+                EmitCvtf(context, signed: false, scalar: true);
             }
         }
 
@@ -582,7 +590,7 @@ namespace ARMeilleure.Instructions
             }
             else
             {
-                EmitVectorCvtf(context, signed: false);
+                EmitCvtf(context, signed: false, scalar: false);
             }
         }
 
@@ -594,7 +602,7 @@ namespace ARMeilleure.Instructions
             }
             else
             {
-                EmitVectorCvtf(context, signed: false);
+                EmitCvtf(context, signed: false, scalar: false);
             }
         }
 
@@ -742,7 +750,7 @@ namespace ARMeilleure.Instructions
             SetIntOrZR(context, op.Rd, res);
         }
 
-        private static void EmitVectorCvtf(ArmEmitterContext context, bool signed)
+        private static void EmitCvtf(ArmEmitterContext context, bool signed, bool scalar)
         {
             OpCodeSimd op = (OpCodeSimd)context.CurrOp;
 
@@ -753,7 +761,7 @@ namespace ARMeilleure.Instructions
 
             int fBits = GetFBits(context);
 
-            int elems = op.GetBytesCount() >> sizeI;
+            int elems = !scalar ? op.GetBytesCount() >> sizeI : 1;
 
             for (int index = 0; index < elems; index++)
             {
diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs
index 9e820f6b6a..0d0c12645a 100644
--- a/ARMeilleure/Instructions/InstName.cs
+++ b/ARMeilleure/Instructions/InstName.cs
@@ -315,6 +315,7 @@ namespace ARMeilleure.Instructions
         Scvtf_Gp,
         Scvtf_Gp_Fixed,
         Scvtf_S,
+        Scvtf_S_Fixed,
         Scvtf_V,
         Scvtf_V_Fixed,
         Sha1c_V,
@@ -414,6 +415,7 @@ namespace ARMeilleure.Instructions
         Ucvtf_Gp,
         Ucvtf_Gp_Fixed,
         Ucvtf_S,
+        Ucvtf_S_Fixed,
         Ucvtf_V,
         Ucvtf_V_Fixed,
         Uhadd_V,
diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs
index 1d208d6958..6c28a92da9 100644
--- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs
+++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs
@@ -195,6 +195,24 @@ namespace Ryujinx.Tests.Cpu
             };
         }
 
+        private static uint[] _SU_Cvt_F_S_Fixed_S_()
+        {
+            return new uint[]
+            {
+                0x5F20E420u, // SCVTF S0, S1, #32
+                0x7F20E420u  // UCVTF S0, S1, #32
+            };
+        }
+
+        private static uint[] _SU_Cvt_F_S_Fixed_D_()
+        {
+            return new uint[]
+            {
+                0x5F40E420u, // SCVTF D0, D1, #64
+                0x7F40E420u  // UCVTF D0, D1, #64
+            };
+        }
+
         private static uint[] _SU_Cvt_F_V_Fixed_2S_4S_()
         {
             return new uint[]
@@ -523,6 +541,42 @@ namespace Ryujinx.Tests.Cpu
             CompareAgainstUnicorn();
         }
 
+        [Test, Pairwise] [Explicit]
+        public void SU_Cvt_F_S_Fixed_S([ValueSource("_SU_Cvt_F_S_Fixed_S_")] uint opcodes,
+                                       [ValueSource("_1S_")] [Random(RndCnt)] ulong a,
+                                       [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits)
+        {
+            uint immHb = (64 - fBits) & 0x7F;
+
+            opcodes |= (immHb << 16);
+
+            ulong z = TestContext.CurrentContext.Random.NextULong();
+            V128 v0 = MakeVectorE0E1(z, z);
+            V128 v1 = MakeVectorE0(a);
+
+            SingleOpcode(opcodes, v0: v0, v1: v1);
+
+            CompareAgainstUnicorn();
+        }
+
+        [Test, Pairwise] [Explicit]
+        public void SU_Cvt_F_S_Fixed_D([ValueSource("_SU_Cvt_F_S_Fixed_D_")] uint opcodes,
+                                       [ValueSource("_1D_")] [Random(RndCnt)] ulong a,
+                                       [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits)
+        {
+            uint immHb = (128 - fBits) & 0x7F;
+
+            opcodes |= (immHb << 16);
+
+            ulong z = TestContext.CurrentContext.Random.NextULong();
+            V128 v0 = MakeVectorE1(z);
+            V128 v1 = MakeVectorE0(a);
+
+            SingleOpcode(opcodes, v0: v0, v1: v1);
+
+            CompareAgainstUnicorn();
+        }
+
         [Test, Pairwise] [Explicit]
         public void SU_Cvt_F_V_Fixed_2S_4S([ValueSource("_SU_Cvt_F_V_Fixed_2S_4S_")] uint opcodes,
                                            [Values(0u)]     uint rd,