Kaynağa Gözat

Add SQADD, UQADD, SQSUB, UQSUB, SUQADD, USQADD, SQABS, SQNEG (Scalar, Vector) instructions; add 24 Tests. Most saturation instructions now on ASoftFallback. (#314)

* Update AOpCodeTable.cs

* Update AInstEmitSimdHelper.cs

* Update AInstEmitSimdArithmetic.cs

* Update Pseudocode.cs

* Update Instructions.cs

* Update CpuTestSimd.cs

* Update CpuTestSimdReg.cs

* Update AInstEmitSimdHelper.cs

* Update AInstEmitSimdHelper.cs

* Update AInstEmitSimdHelper.cs

* Update AInstEmitSimdHelper.cs

* Update ASoftFallback.cs

* Update AInstEmitSimdHelper.cs

* Update ASoftFallback.cs

* Update AInstEmitSimdHelper.cs

* Update CpuTestSimd.cs

* Update CpuTestSimdReg.cs

* Update ASoftFallback.cs

* Update AInstEmitSimdHelper.cs

* Opt. (retest).
LDj3SNuD 7 yıl önce
ebeveyn
işleme
5f34353dce

+ 16 - 0
ChocolArm64/AOpCodeTable.cs

@@ -374,7 +374,15 @@ namespace ChocolArm64
             SetA64("0x001110<<1xxxxx100000xxxxxxxxxx", AInstEmit.Smlal_V,       typeof(AOpCodeSimdReg));
             SetA64("0x001110<<1xxxxx101000xxxxxxxxxx", AInstEmit.Smlsl_V,       typeof(AOpCodeSimdReg));
             SetA64("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V,       typeof(AOpCodeSimdReg));
+            SetA64("01011110xx100000011110xxxxxxxxxx", AInstEmit.Sqabs_S,       typeof(AOpCodeSimd));
+            SetA64("0>001110<<100000011110xxxxxxxxxx", AInstEmit.Sqabs_V,       typeof(AOpCodeSimd));
+            SetA64("01011110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_S,       typeof(AOpCodeSimdReg));
+            SetA64("0>001110<<1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_V,       typeof(AOpCodeSimdReg));
+            SetA64("01111110xx100000011110xxxxxxxxxx", AInstEmit.Sqneg_S,       typeof(AOpCodeSimd));
+            SetA64("0>101110<<100000011110xxxxxxxxxx", AInstEmit.Sqneg_V,       typeof(AOpCodeSimd));
             SetA64("0x00111100>>>xxx100111xxxxxxxxxx", AInstEmit.Sqrshrn_V,     typeof(AOpCodeSimdShImm));
+            SetA64("01011110xx1xxxxx001011xxxxxxxxxx", AInstEmit.Sqsub_S,       typeof(AOpCodeSimdReg));
+            SetA64("0>001110<<1xxxxx001011xxxxxxxxxx", AInstEmit.Sqsub_V,       typeof(AOpCodeSimdReg));
             SetA64("01011110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_S,       typeof(AOpCodeSimd));
             SetA64("0x001110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_V,       typeof(AOpCodeSimd));
             SetA64("01111110<<100001001010xxxxxxxxxx", AInstEmit.Sqxtun_S,      typeof(AOpCodeSimd));
@@ -402,6 +410,8 @@ namespace ChocolArm64
             SetA64("01111110111xxxxx100001xxxxxxxxxx", AInstEmit.Sub_S,         typeof(AOpCodeSimdReg));
             SetA64("0>101110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_V,         typeof(AOpCodeSimdReg));
             SetA64("0x001110<<1xxxxx011000xxxxxxxxxx", AInstEmit.Subhn_V,       typeof(AOpCodeSimdReg));
+            SetA64("01011110xx100000001110xxxxxxxxxx", AInstEmit.Suqadd_S,      typeof(AOpCodeSimd));
+            SetA64("0>001110<<100000001110xxxxxxxxxx", AInstEmit.Suqadd_V,      typeof(AOpCodeSimd));
             SetA64("0x001110000xxxxx0xx000xxxxxxxxxx", AInstEmit.Tbl_V,         typeof(AOpCodeSimdTbl));
             SetA64("0>001110<<0xxxxx001010xxxxxxxxxx", AInstEmit.Trn1_V,        typeof(AOpCodeSimdReg));
             SetA64("0>001110<<0xxxxx011010xxxxxxxxxx", AInstEmit.Trn2_V,        typeof(AOpCodeSimdReg));
@@ -423,6 +433,10 @@ namespace ChocolArm64
             SetA64("0x101110<<1xxxxx101011xxxxxxxxxx", AInstEmit.Uminp_V,       typeof(AOpCodeSimdReg));
             SetA64("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S,        typeof(AOpCodeSimdIns));
             SetA64("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V,       typeof(AOpCodeSimdReg));
+            SetA64("01111110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_S,       typeof(AOpCodeSimdReg));
+            SetA64("0>101110<<1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_V,       typeof(AOpCodeSimdReg));
+            SetA64("01111110xx1xxxxx001011xxxxxxxxxx", AInstEmit.Uqsub_S,       typeof(AOpCodeSimdReg));
+            SetA64("0>101110<<1xxxxx001011xxxxxxxxxx", AInstEmit.Uqsub_V,       typeof(AOpCodeSimdReg));
             SetA64("01111110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_S,       typeof(AOpCodeSimd));
             SetA64("0x101110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_V,       typeof(AOpCodeSimd));
             SetA64("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V,        typeof(AOpCodeSimdReg));
@@ -430,6 +444,8 @@ namespace ChocolArm64
             SetA64("0111111101xxxxxx000001xxxxxxxxxx", AInstEmit.Ushr_S,        typeof(AOpCodeSimdShImm));
             SetA64("0x10111100>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V,        typeof(AOpCodeSimdShImm));
             SetA64("0110111101xxxxxx000001xxxxxxxxxx", AInstEmit.Ushr_V,        typeof(AOpCodeSimdShImm));
+            SetA64("01111110xx100000001110xxxxxxxxxx", AInstEmit.Usqadd_S,      typeof(AOpCodeSimd));
+            SetA64("0>101110<<100000001110xxxxxxxxxx", AInstEmit.Usqadd_V,      typeof(AOpCodeSimd));
             SetA64("0x10111100>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V,        typeof(AOpCodeSimdShImm));
             SetA64("0110111101xxxxxx000101xxxxxxxxxx", AInstEmit.Usra_V,        typeof(AOpCodeSimdShImm));
             SetA64("0x101110<<1xxxxx001100xxxxxxxxxx", AInstEmit.Usubw_V,       typeof(AOpCodeSimdReg));

+ 80 - 0
ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs

@@ -1052,6 +1052,46 @@ namespace ChocolArm64.Instruction
             EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul));
         }
 
+        public static void Sqabs_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingUnaryOpSx(Context, () => EmitAbs(Context));
+        }
+
+        public static void Sqabs_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingUnaryOpSx(Context, () => EmitAbs(Context));
+        }
+
+        public static void Sqadd_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Add);
+        }
+
+        public static void Sqadd_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Add);
+        }
+
+        public static void Sqneg_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
+        }
+
+        public static void Sqneg_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
+        }
+
+        public static void Sqsub_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Sub);
+        }
+
+        public static void Sqsub_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Sub);
+        }
+
         public static void Sqxtn_S(AILEmitterCtx Context)
         {
             EmitScalarSaturatingNarrowOpSxSx(Context, () => { });
@@ -1099,6 +1139,16 @@ namespace ChocolArm64.Instruction
             EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: false);
         }
 
+        public static void Suqadd_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Accumulate);
+        }
+
+        public static void Suqadd_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Accumulate);
+        }
+
         public static void Uaba_V(AILEmitterCtx Context)
         {
             EmitVectorTernaryOpZx(Context, () =>
@@ -1221,6 +1271,26 @@ namespace ChocolArm64.Instruction
             EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
         }
 
+        public static void Uqadd_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Add);
+        }
+
+        public static void Uqadd_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Add);
+        }
+
+        public static void Uqsub_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Sub);
+        }
+
+        public static void Uqsub_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Sub);
+        }
+
         public static void Uqxtn_S(AILEmitterCtx Context)
         {
             EmitScalarSaturatingNarrowOpZxZx(Context, () => { });
@@ -1231,6 +1301,16 @@ namespace ChocolArm64.Instruction
             EmitVectorSaturatingNarrowOpZxZx(Context, () => { });
         }
 
+        public static void Usqadd_S(AILEmitterCtx Context)
+        {
+            EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
+        }
+
+        public static void Usqadd_V(AILEmitterCtx Context)
+        {
+            EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
+        }
+
         public static void Usubw_V(AILEmitterCtx Context)
         {
             EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));

+ 321 - 57
ChocolArm64/Instruction/AInstEmitSimdHelper.cs

@@ -336,17 +336,21 @@ namespace ChocolArm64.Instruction
         {
             AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
 
-            if (Opers.HasFlag(OperFlags.Rd))
+            bool Rd = (Opers & OperFlags.Rd) != 0;
+            bool Rn = (Opers & OperFlags.Rn) != 0;
+            bool Rm = (Opers & OperFlags.Rm) != 0;
+
+            if (Rd)
             {
                 EmitVectorExtract(Context, Op.Rd, 0, Op.Size, Signed);
             }
 
-             if (Opers.HasFlag(OperFlags.Rn))
+            if (Rn)
             {
                 EmitVectorExtract(Context, Op.Rn, 0, Op.Size, Signed);
             }
 
-            if (Opers.HasFlag(OperFlags.Rm))
+            if (Rm)
             {
                 EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed);
             }
@@ -377,17 +381,21 @@ namespace ChocolArm64.Instruction
 
             int SizeF = Op.Size & 1;
 
-            if (Opers.HasFlag(OperFlags.Ra))
+            bool Ra = (Opers & OperFlags.Ra) != 0;
+            bool Rn = (Opers & OperFlags.Rn) != 0;
+            bool Rm = (Opers & OperFlags.Rm) != 0;
+
+            if (Ra)
             {
                 EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Ra, 0, SizeF);
             }
 
-            if (Opers.HasFlag(OperFlags.Rn))
+            if (Rn)
             {
                 EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
             }
 
-            if (Opers.HasFlag(OperFlags.Rm))
+            if (Rm)
             {
                 EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, 0, SizeF);
             }
@@ -769,7 +777,7 @@ namespace ChocolArm64.Instruction
                 Emit();
 
                 EmitVectorInsertTmp(Context, Pairs + Index, Op.Size);
-                EmitVectorInsertTmp(Context, Index,         Op.Size);
+                EmitVectorInsertTmp(Context,         Index, Op.Size);
             }
 
             Context.EmitLdvectmp();
@@ -781,56 +789,241 @@ namespace ChocolArm64.Instruction
             }
         }
 
+        [Flags]
+        public enum SaturatingFlags
+        {
+            Scalar = 1 << 0,
+            Signed = 1 << 1,
+
+            Add = 1 << 2,
+            Sub = 1 << 3,
+
+            Accumulate = 1 << 4,
+
+            ScalarSx = Scalar | Signed,
+            ScalarZx = Scalar,
+
+            VectorSx = Signed,
+            VectorZx = 0,
+        }
+
+        public static void EmitScalarSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit)
+        {
+            EmitSaturatingUnaryOpSx(Context, Emit, SaturatingFlags.ScalarSx);
+        }
+
+        public static void EmitVectorSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit)
+        {
+            EmitSaturatingUnaryOpSx(Context, Emit, SaturatingFlags.VectorSx);
+        }
+
+        public static void EmitSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit, SaturatingFlags Flags)
+        {
+            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+            bool Scalar = (Flags & SaturatingFlags.Scalar) != 0;
+
+            int Bytes = Op.GetBitsCount() >> 3;
+            int Elems = !Scalar ? Bytes >> Op.Size : 1;
+
+            if (Scalar)
+            {
+                EmitVectorZeroLowerTmp(Context);
+            }
+
+            for (int Index = 0; Index < Elems; Index++)
+            {
+                EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size);
+
+                Emit();
+
+                EmitUnarySignedSatQAbsOrNeg(Context, Op.Size);
+
+                EmitVectorInsertTmp(Context, Index, Op.Size);
+            }
+
+            Context.EmitLdvectmp();
+            Context.EmitStvec(Op.Rd);
+
+            if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
+            {
+                EmitVectorZeroUpper(Context, Op.Rd);
+            }
+        }
+
+        public static void EmitScalarSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags)
+        {
+            EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarSx | Flags);
+        }
+
+        public static void EmitScalarSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags)
+        {
+            EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarZx | Flags);
+        }
+
+        public static void EmitVectorSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags)
+        {
+            EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorSx | Flags);
+        }
+
+        public static void EmitVectorSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags)
+        {
+            EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorZx | Flags);
+        }
+
+        public static void EmitSaturatingBinaryOp(AILEmitterCtx Context, SaturatingFlags Flags)
+        {
+            AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+            bool Scalar = (Flags & SaturatingFlags.Scalar) != 0;
+            bool Signed = (Flags & SaturatingFlags.Signed) != 0;
+
+            bool Add = (Flags & SaturatingFlags.Add) != 0;
+            bool Sub = (Flags & SaturatingFlags.Sub) != 0;
+
+            bool Accumulate = (Flags & SaturatingFlags.Accumulate) != 0;
+
+            int Bytes = Op.GetBitsCount() >> 3;
+            int Elems = !Scalar ? Bytes >> Op.Size : 1;
+
+            if (Scalar)
+            {
+                EmitVectorZeroLowerTmp(Context);
+            }
+
+            if (Add || Sub)
+            {
+                for (int Index = 0; Index < Elems; Index++)
+                {
+                    EmitVectorExtract(Context,                   Op.Rn, Index, Op.Size, Signed);
+                    EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed);
+
+                    if (Op.Size <= 2)
+                    {
+                        Context.Emit(Add ? OpCodes.Add : OpCodes.Sub);
+
+                        EmitSatQ(Context, Op.Size, true, Signed);
+                    }
+                    else /* if (Op.Size == 3) */
+                    {
+                        if (Add)
+                        {
+                            EmitBinarySatQAdd(Context, Signed);
+                        }
+                        else /* if (Sub) */
+                        {
+                            EmitBinarySatQSub(Context, Signed);
+                        }
+                    }
+
+                    EmitVectorInsertTmp(Context, Index, Op.Size);
+                }
+            }
+            else if (Accumulate)
+            {
+                for (int Index = 0; Index < Elems; Index++)
+                {
+                    EmitVectorExtract(Context, Op.Rn, Index, Op.Size, !Signed);
+                    EmitVectorExtract(Context, Op.Rd, Index, Op.Size,  Signed);
+
+                    if (Op.Size <= 2)
+                    {
+                        Context.Emit(OpCodes.Add);
+
+                        EmitSatQ(Context, Op.Size, true, Signed);
+                    }
+                    else /* if (Op.Size == 3) */
+                    {
+                        EmitBinarySatQAccumulate(Context, Signed);
+                    }
+
+                    EmitVectorInsertTmp(Context, Index, Op.Size);
+                }
+            }
+
+            Context.EmitLdvectmp();
+            Context.EmitStvec(Op.Rd);
+
+            if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
+            {
+                EmitVectorZeroUpper(Context, Op.Rd);
+            }
+        }
+
+        [Flags]
+        public enum SaturatingNarrowFlags
+        {
+            Scalar    = 1 << 0,
+            SignedSrc = 1 << 1,
+            SignedDst = 1 << 2,
+
+            ScalarSxSx = Scalar | SignedSrc | SignedDst,
+            ScalarSxZx = Scalar | SignedSrc,
+            ScalarZxSx = Scalar | SignedDst,
+            ScalarZxZx = Scalar,
+
+            VectorSxSx = SignedSrc | SignedDst,
+            VectorSxZx = SignedSrc,
+            VectorZxSx = SignedDst,
+            VectorZxZx = 0
+        }
+
         public static void EmitScalarSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit)
         {
-            EmitSaturatingNarrowOp(Context, Emit, true, true, true);
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarSxSx);
         }
 
         public static void EmitScalarSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit)
         {
-            EmitSaturatingNarrowOp(Context, Emit, true, false, true);
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarSxZx);
+        }
+
+        public static void EmitScalarSaturatingNarrowOpZxSx(AILEmitterCtx Context, Action Emit)
+        {
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarZxSx);
         }
 
         public static void EmitScalarSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit)
         {
-            EmitSaturatingNarrowOp(Context, Emit, false, false, true);
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarZxZx);
         }
 
         public static void EmitVectorSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit)
         {
-            EmitSaturatingNarrowOp(Context, Emit, true, true, false);
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorSxSx);
         }
 
         public static void EmitVectorSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit)
         {
-            EmitSaturatingNarrowOp(Context, Emit, true, false, false);
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorSxZx);
+        }
+
+        public static void EmitVectorSaturatingNarrowOpZxSx(AILEmitterCtx Context, Action Emit)
+        {
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorZxSx);
         }
 
         public static void EmitVectorSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit)
         {
-            EmitSaturatingNarrowOp(Context, Emit, false, false, false);
+            EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorZxZx);
         }
 
-        public static void EmitSaturatingNarrowOp(
-            AILEmitterCtx Context,
-            Action        Emit,
-            bool          SignedSrc,
-            bool          SignedDst,
-            bool          Scalar)
+        public static void EmitSaturatingNarrowOp(AILEmitterCtx Context, Action Emit, SaturatingNarrowFlags Flags)
         {
             AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
 
-            int Elems = !Scalar ? 8 >> Op.Size : 1;
+            bool Scalar    = (Flags & SaturatingNarrowFlags.Scalar)    != 0;
+            bool SignedSrc = (Flags & SaturatingNarrowFlags.SignedSrc) != 0;
+            bool SignedDst = (Flags & SaturatingNarrowFlags.SignedDst) != 0;
 
-            int ESize = 8 << Op.Size;
+            int Elems = !Scalar ? 8 >> Op.Size : 1;
 
             int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0;
 
-            long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (long)(~0UL >> (64 - ESize));
-            long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0;
-
-            Context.EmitLdc_I8(0L);
-            Context.EmitSttmp();
+            if (Scalar)
+            {
+                EmitVectorZeroLowerTmp(Context);
+            }
 
             if (Part != 0)
             {
@@ -840,65 +1033,136 @@ namespace ChocolArm64.Instruction
 
             for (int Index = 0; Index < Elems; Index++)
             {
-                AILLabel LblLe    = new AILLabel();
-                AILLabel LblGeEnd = new AILLabel();
-
                 EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc);
 
                 Emit();
 
-                Context.Emit(OpCodes.Dup);
+                EmitSatQ(Context, Op.Size, SignedSrc, SignedDst);
+
+                EmitVectorInsertTmp(Context, Part + Index, Op.Size);
+            }
+
+            Context.EmitLdvectmp();
+            Context.EmitStvec(Op.Rd);
+
+            if (Part == 0)
+            {
+                EmitVectorZeroUpper(Context, Op.Rd);
+            }
+        }
+
+        // TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned).
+        public static void EmitSatQ(
+            AILEmitterCtx Context,
+            int  SizeDst,
+            bool SignedSrc,
+            bool SignedDst)
+        {
+            if (SizeDst > 2)
+            {
+                throw new ArgumentOutOfRangeException(nameof(SizeDst));
+            }
 
-                Context.EmitLdc_I8(TMaxValue);
+            Context.EmitLdc_I4(SizeDst);
+            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
 
-                Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe);
+            if (SignedSrc)
+            {
+                ASoftFallback.EmitCall(Context, SignedDst
+                    ? nameof(ASoftFallback.SignedSrcSignedDstSatQ)
+                    : nameof(ASoftFallback.SignedSrcUnsignedDstSatQ));
+            }
+            else
+            {
+                ASoftFallback.EmitCall(Context, SignedDst
+                    ? nameof(ASoftFallback.UnsignedSrcSignedDstSatQ)
+                    : nameof(ASoftFallback.UnsignedSrcUnsignedDstSatQ));
+            }
+        }
 
-                Context.Emit(OpCodes.Pop);
+        // TSrc (8bit, 16bit, 32bit, 64bit) == TDst (8bit, 16bit, 32bit, 64bit); signed.
+        public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context, int Size)
+        {
+            int ESize = 8 << Size;
 
-                Context.EmitLdc_I8(TMaxValue);
-                Context.EmitLdc_I8(0x8000000L);
-                Context.EmitSttmp();
+            long TMaxValue =  (1L << (ESize - 1)) - 1L;
+            long TMinValue = -(1L << (ESize - 1));
 
-                Context.Emit(OpCodes.Br_S, LblGeEnd);
+            AILLabel LblFalse = new AILLabel();
 
-                Context.MarkLabel(LblLe);
+            Context.Emit(OpCodes.Dup);
+            Context.Emit(OpCodes.Neg);
+            Context.EmitLdc_I8(TMinValue);
+            Context.Emit(OpCodes.Ceq);
+            Context.Emit(OpCodes.Brfalse_S, LblFalse);
 
-                Context.Emit(OpCodes.Dup);
+            Context.Emit(OpCodes.Pop);
 
-                Context.EmitLdc_I8(TMinValue);
+            EmitSetFpsrQCFlag(Context);
 
-                Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd);
+            Context.EmitLdc_I8(TMaxValue);
 
-                Context.Emit(OpCodes.Pop);
+            Context.MarkLabel(LblFalse);
+        }
 
-                Context.EmitLdc_I8(TMinValue);
-                Context.EmitLdc_I8(0x8000000L);
-                Context.EmitSttmp();
+        // TSrcs (64bit) == TDst (64bit); signed, unsigned.
+        public static void EmitBinarySatQAdd(AILEmitterCtx Context, bool Signed)
+        {
+            if (((AOpCodeSimdReg)Context.CurrOp).Size < 3)
+            {
+                throw new InvalidOperationException();
+            }
 
-                Context.MarkLabel(LblGeEnd);
+            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
 
-                if (Scalar)
-                {
-                    EmitVectorZeroLowerTmp(Context);
-                }
+            ASoftFallback.EmitCall(Context, Signed
+                ? nameof(ASoftFallback.BinarySignedSatQAdd)
+                : nameof(ASoftFallback.BinaryUnsignedSatQAdd));
+        }
 
-                EmitVectorInsertTmp(Context, Part + Index, Op.Size);
+        // TSrcs (64bit) == TDst (64bit); signed, unsigned.
+        public static void EmitBinarySatQSub(AILEmitterCtx Context, bool Signed)
+        {
+            if (((AOpCodeSimdReg)Context.CurrOp).Size < 3)
+            {
+                throw new InvalidOperationException();
             }
 
-            Context.EmitLdvectmp();
-            Context.EmitStvec(Op.Rd);
+            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
 
-            if (Part == 0)
+            ASoftFallback.EmitCall(Context, Signed
+                ? nameof(ASoftFallback.BinarySignedSatQSub)
+                : nameof(ASoftFallback.BinaryUnsignedSatQSub));
+        }
+
+        // TSrcs (64bit) == TDst (64bit); signed, unsigned.
+        public static void EmitBinarySatQAccumulate(AILEmitterCtx Context, bool Signed)
+        {
+            if (((AOpCodeSimd)Context.CurrOp).Size < 3)
             {
-                EmitVectorZeroUpper(Context, Op.Rd);
+                throw new InvalidOperationException();
             }
 
             Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+
+            ASoftFallback.EmitCall(Context, Signed
+                ? nameof(ASoftFallback.BinarySignedSatQAcc)
+                : nameof(ASoftFallback.BinaryUnsignedSatQAcc));
+        }
+
+        public static void EmitSetFpsrQCFlag(AILEmitterCtx Context)
+        {
+            const int QCFlagBit = 27;
+
+            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+
             Context.EmitLdarg(ATranslatedSub.StateArgIdx);
             Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr));
-            Context.EmitLdtmp();
-            Context.Emit(OpCodes.Conv_I4);
+
+            Context.EmitLdc_I4(1 << QCFlagBit);
+
             Context.Emit(OpCodes.Or);
+
             Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr));
         }
 

+ 268 - 0
ChocolArm64/Instruction/ASoftFallback.cs

@@ -1,3 +1,4 @@
+using ChocolArm64.State;
 using ChocolArm64.Translation;
 using System;
 
@@ -10,6 +11,273 @@ namespace ChocolArm64.Instruction
             Context.EmitCall(typeof(ASoftFallback), MthdName);
         }
 
+        public static long BinarySignedSatQAdd(long op1, long op2, AThreadState State)
+        {
+            long Add = op1 + op2;
+
+            if ((~(op1 ^ op2) & (op1 ^ Add)) < 0L)
+            {
+                SetFpsrQCFlag(State);
+
+                if (op1 < 0L)
+                {
+                    return long.MinValue;
+                }
+                else
+                {
+                    return long.MaxValue;
+                }
+            }
+            else
+            {
+                return Add;
+            }
+        }
+
+        public static ulong BinaryUnsignedSatQAdd(ulong op1, ulong op2, AThreadState State)
+        {
+            ulong Add = op1 + op2;
+
+            if ((Add < op1) && (Add < op2))
+            {
+                SetFpsrQCFlag(State);
+
+                return ulong.MaxValue;
+            }
+            else
+            {
+                return Add;
+            }
+        }
+
+        public static long BinarySignedSatQSub(long op1, long op2, AThreadState State)
+        {
+            long Sub = op1 - op2;
+
+            if (((op1 ^ op2) & (op1 ^ Sub)) < 0L)
+            {
+                SetFpsrQCFlag(State);
+
+                if (op1 < 0L)
+                {
+                    return long.MinValue;
+                }
+                else
+                {
+                    return long.MaxValue;
+                }
+            }
+            else
+            {
+                return Sub;
+            }
+        }
+
+        public static ulong BinaryUnsignedSatQSub(ulong op1, ulong op2, AThreadState State)
+        {
+            ulong Sub = op1 - op2;
+
+            if (op1 < op2)
+            {
+                SetFpsrQCFlag(State);
+
+                return ulong.MinValue;
+            }
+            else
+            {
+                return Sub;
+            }
+        }
+
+        public static long BinarySignedSatQAcc(ulong op1, long op2, AThreadState State)
+        {
+            if (op1 <= (ulong)long.MaxValue)
+            {
+                // op1 from ulong.MinValue to (ulong)long.MaxValue
+                // op2 from long.MinValue to long.MaxValue
+
+                long Add = (long)op1 + op2;
+
+                if ((~op2 & Add) < 0L)
+                {
+                    SetFpsrQCFlag(State);
+
+                    return long.MaxValue;
+                }
+                else
+                {
+                    return Add;
+                }
+            }
+            else if (op2 >= 0L)
+            {
+                // op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue
+                // op2 from (long)ulong.MinValue to long.MaxValue
+
+                SetFpsrQCFlag(State);
+
+                return long.MaxValue;
+            }
+            else
+            {
+                // op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue
+                // op2 from long.MinValue to (long)ulong.MinValue - 1L
+
+                ulong Add = op1 + (ulong)op2;
+
+                if (Add > (ulong)long.MaxValue)
+                {
+                    SetFpsrQCFlag(State);
+
+                    return long.MaxValue;
+                }
+                else
+                {
+                    return (long)Add;
+                }
+            }
+        }
+
+        public static ulong BinaryUnsignedSatQAcc(long op1, ulong op2, AThreadState State)
+        {
+            if (op1 >= 0L)
+            {
+                // op1 from (long)ulong.MinValue to long.MaxValue
+                // op2 from ulong.MinValue to ulong.MaxValue
+
+                ulong Add = (ulong)op1 + op2;
+
+                if ((Add < (ulong)op1) && (Add < op2))
+                {
+                    SetFpsrQCFlag(State);
+
+                    return ulong.MaxValue;
+                }
+                else
+                {
+                    return Add;
+                }
+            }
+            else if (op2 > (ulong)long.MaxValue)
+            {
+                // op1 from long.MinValue to (long)ulong.MinValue - 1L
+                // op2 from (ulong)long.MaxValue + 1UL to ulong.MaxValue
+
+                return (ulong)op1 + op2;
+            }
+            else
+            {
+                // op1 from long.MinValue to (long)ulong.MinValue - 1L
+                // op2 from ulong.MinValue to (ulong)long.MaxValue
+
+                long Add = op1 + (long)op2;
+
+                if (Add < (long)ulong.MinValue)
+                {
+                    SetFpsrQCFlag(State);
+
+                    return ulong.MinValue;
+                }
+                else
+                {
+                    return (ulong)Add;
+                }
+            }
+        }
+
+        public static long SignedSrcSignedDstSatQ(long op, int Size, AThreadState State)
+        {
+            int ESize = 8 << Size;
+
+            long TMaxValue =  (1L << (ESize - 1)) - 1L;
+            long TMinValue = -(1L << (ESize - 1));
+
+            if (op > TMaxValue)
+            {
+                SetFpsrQCFlag(State);
+
+                return TMaxValue;
+            }
+            else if (op < TMinValue)
+            {
+                SetFpsrQCFlag(State);
+
+                return TMinValue;
+            }
+            else
+            {
+                return op;
+            }
+        }
+
+        public static ulong SignedSrcUnsignedDstSatQ(long op, int Size, AThreadState State)
+        {
+            int ESize = 8 << Size;
+
+            ulong TMaxValue = (1UL << ESize) - 1UL;
+            ulong TMinValue =  0UL;
+
+            if (op > (long)TMaxValue)
+            {
+                SetFpsrQCFlag(State);
+
+                return TMaxValue;
+            }
+            else if (op < (long)TMinValue)
+            {
+                SetFpsrQCFlag(State);
+
+                return TMinValue;
+            }
+            else
+            {
+                return (ulong)op;
+            }
+        }
+
+        public static long UnsignedSrcSignedDstSatQ(ulong op, int Size, AThreadState State)
+        {
+            int ESize = 8 << Size;
+
+            long TMaxValue = (1L << (ESize - 1)) - 1L;
+
+            if (op > (ulong)TMaxValue)
+            {
+                SetFpsrQCFlag(State);
+
+                return TMaxValue;
+            }
+            else
+            {
+                return (long)op;
+            }
+        }
+
+        public static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int Size, AThreadState State)
+        {
+            int ESize = 8 << Size;
+
+            ulong TMaxValue = (1UL << ESize) - 1UL;
+
+            if (op > TMaxValue)
+            {
+                SetFpsrQCFlag(State);
+
+                return TMaxValue;
+            }
+            else
+            {
+                return op;
+            }
+        }
+
+        private static void SetFpsrQCFlag(AThreadState State)
+        {
+            const int QCFlagBit = 27;
+
+            State.Fpsr |= 1 << QCFlagBit;
+        }
+
         public static ulong CountLeadingSigns(ulong Value, int Size)
         {
             Value ^= Value >> 1;

+ 428 - 18
Ryujinx.Tests/Cpu/CpuTestSimd.cs

@@ -22,6 +22,17 @@ namespace Ryujinx.Tests.Cpu
         }
 
 #region "ValueSource"
+        private static ulong[] _1B1H1S1D_()
+        {
+            return new ulong[] { 0x0000000000000000ul, 0x000000000000007Ful,
+                                 0x0000000000000080ul, 0x00000000000000FFul,
+                                 0x0000000000007FFFul, 0x0000000000008000ul,
+                                 0x000000000000FFFFul, 0x000000007FFFFFFFul,
+                                 0x0000000080000000ul, 0x00000000FFFFFFFFul,
+                                 0x7FFFFFFFFFFFFFFFul, 0x8000000000000000ul,
+                                 0xFFFFFFFFFFFFFFFFul };
+        }
+
         private static ulong[] _1D_()
         {
             return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
@@ -1126,6 +1137,192 @@ namespace Ryujinx.Tests.Cpu
             });
         }
 
+        [Test, Description("SQABS <V><d>, <V><n>")]
+        public void Sqabs_S_B_H_S_D([Values(0u)] uint Rd,
+                                    [Values(1u, 0u)] uint Rn,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                    [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x5E207800; // SQABS B0, B0
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqabs_S(Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SQABS <Vd>.<T>, <Vn>.<T>")]
+        public void Sqabs_V_8B_4H_2S([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                     [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x0E207800; // SQABS V0.8B, V0.8B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqabs_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SQABS <Vd>.<T>, <Vn>.<T>")]
+        public void Sqabs_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                         [Values(1u, 0u)] uint Rn,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                         [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x4E207800; // SQABS V0.16B, V0.16B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqabs_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SQNEG <V><d>, <V><n>")]
+        public void Sqneg_S_B_H_S_D([Values(0u)] uint Rd,
+                                    [Values(1u, 0u)] uint Rn,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                    [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x7E207800; // SQNEG B0, B0
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqneg_S(Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SQNEG <Vd>.<T>, <Vn>.<T>")]
+        public void Sqneg_V_8B_4H_2S([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                     [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x2E207800; // SQNEG V0.8B, V0.8B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqneg_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SQNEG <Vd>.<T>, <Vn>.<T>")]
+        public void Sqneg_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                         [Values(1u, 0u)] uint Rn,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                         [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x6E207800; // SQNEG V0.16B, V0.16B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqneg_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
         [Test, Description("SQXTN <Vb><d>, <Va><n>")]
         public void Sqxtn_S_HB_SH_DS([Values(0u)] uint Rd,
                                      [Values(1u, 0u)] uint Rn,
@@ -1138,12 +1335,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0(A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Sqxtn_S(Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1151,7 +1351,7 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("SQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
@@ -1166,12 +1366,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0E1(A, A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Sqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1179,7 +1382,7 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("SQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
@@ -1194,12 +1397,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0E1(A, A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Sqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1207,7 +1413,7 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("SQXTUN <Vb><d>, <Va><n>")]
@@ -1222,12 +1428,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0(A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Sqxtun_S(Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1235,7 +1444,7 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("SQXTUN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
@@ -1250,12 +1459,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0E1(A, A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Sqxtun_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1263,7 +1475,7 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("SQXTUN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
@@ -1278,12 +1490,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0E1(A, A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Sqxtun_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1291,7 +1506,100 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SUQADD <V><d>, <V><n>")]
+        public void Suqadd_S_B_H_S_D([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                     [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x5E203800; // SUQADD B0, B0
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Suqadd_S(Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SUQADD <Vd>.<T>, <Vn>.<T>")]
+        public void Suqadd_V_8B_4H_2S([Values(0u)] uint Rd,
+                                      [Values(1u, 0u)] uint Rn,
+                                      [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                      [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                      [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x0E203800; // SUQADD V0.8B, V0.8B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Suqadd_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("SUQADD <Vd>.<T>, <Vn>.<T>")]
+        public void Suqadd_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                          [Values(1u, 0u)] uint Rn,
+                                          [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                          [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                          [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x4E203800; // SUQADD V0.16B, V0.16B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Suqadd_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("UQXTN <Vb><d>, <Va><n>")]
@@ -1306,12 +1614,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0(A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Uqxtn_S(Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1319,7 +1630,7 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("UQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
@@ -1334,12 +1645,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0E1(A, A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Uqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1347,7 +1661,7 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("UQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
@@ -1362,12 +1676,15 @@ namespace Ryujinx.Tests.Cpu
             Opcode |= ((size & 3) << 22);
             Bits Op = new Bits(Opcode);
 
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
             Vector128<float> V0 = MakeVectorE0E1(Z, Z);
             Vector128<float> V1 = MakeVectorE0E1(A, A);
-            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
 
             AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
             AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
             SimdFp.Uqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
 
             Assert.Multiple(() =>
@@ -1375,7 +1692,100 @@ namespace Ryujinx.Tests.Cpu
                 Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
                 Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
             });
-            Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27]));
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("USQADD <V><d>, <V><n>")]
+        public void Usqadd_S_B_H_S_D([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                     [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x7E203800; // USQADD B0, B0
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Usqadd_S(Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("USQADD <Vd>.<T>, <Vn>.<T>")]
+        public void Usqadd_V_8B_4H_2S([Values(0u)] uint Rd,
+                                      [Values(1u, 0u)] uint Rn,
+                                      [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                      [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                      [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x2E203800; // USQADD V0.8B, V0.8B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Usqadd_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Description("USQADD <Vd>.<T>, <Vn>.<T>")]
+        public void Usqadd_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                          [Values(1u, 0u)] uint Rn,
+                                          [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                          [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                          [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x6E203800; // USQADD V0.16B, V0.16B
+            Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Usqadd_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
         }
 
         [Test, Description("XTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]

+ 431 - 0
Ryujinx.Tests/Cpu/CpuTestSimdReg.cs

@@ -22,6 +22,17 @@ namespace Ryujinx.Tests.Cpu
         }
 
 #region "ValueSource"
+        private static ulong[] _1B1H1S1D_()
+        {
+            return new ulong[] { 0x0000000000000000ul, 0x000000000000007Ful,
+                                 0x0000000000000080ul, 0x00000000000000FFul,
+                                 0x0000000000007FFFul, 0x0000000000008000ul,
+                                 0x000000000000FFFFul, 0x000000007FFFFFFFul,
+                                 0x0000000080000000ul, 0x00000000FFFFFFFFul,
+                                 0x7FFFFFFFFFFFFFFFul, 0x8000000000000000ul,
+                                 0xFFFFFFFFFFFFFFFFul };
+        }
+
         private static ulong[] _1D_()
         {
             return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
@@ -1721,6 +1732,216 @@ namespace Ryujinx.Tests.Cpu
             });
         }
 
+        [Test, Pairwise, Description("SQADD <V><d>, <V><n>, <V><m>")]
+        public void Sqadd_S_B_H_S_D([Values(0u)] uint Rd,
+                                    [Values(1u, 0u)] uint Rn,
+                                    [Values(2u, 0u)] uint Rm,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong B,
+                                    [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x5E200C00; // SQADD B0, B0, B0
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqadd_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("SQADD <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Sqadd_V_8B_4H_2S([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [Values(2u, 0u)] uint Rm,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong B,
+                                     [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x0E200C00; // SQADD V0.8B, V0.8B, V0.8B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqadd_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("SQADD <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Sqadd_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                         [Values(1u, 0u)] uint Rn,
+                                         [Values(2u, 0u)] uint Rm,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong B,
+                                         [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x4E200C00; // SQADD V0.16B, V0.16B, V0.16B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            Vector128<float> V2 = MakeVectorE0E1(B, B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            AArch64.Vpart(2, 0, new Bits(B)); AArch64.Vpart(2, 1, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqadd_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("SQSUB <V><d>, <V><n>, <V><m>")]
+        public void Sqsub_S_B_H_S_D([Values(0u)] uint Rd,
+                                    [Values(1u, 0u)] uint Rn,
+                                    [Values(2u, 0u)] uint Rm,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong B,
+                                    [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x5E202C00; // SQSUB B0, B0, B0
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqsub_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("SQSUB <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Sqsub_V_8B_4H_2S([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [Values(2u, 0u)] uint Rm,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong B,
+                                     [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x0E202C00; // SQSUB V0.8B, V0.8B, V0.8B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqsub_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("SQSUB <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Sqsub_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                         [Values(1u, 0u)] uint Rn,
+                                         [Values(2u, 0u)] uint Rm,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong B,
+                                         [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x4E202C00; // SQSUB V0.16B, V0.16B, V0.16B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            Vector128<float> V2 = MakeVectorE0E1(B, B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            AArch64.Vpart(2, 0, new Bits(B)); AArch64.Vpart(2, 1, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Sqsub_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
         [Test, Pairwise, Description("SSUBW{2} <Vd>.<Ta>, <Vn>.<Ta>, <Vm>.<Tb>")]
         public void Ssubw_V_8B8H8H_4H4S4S_2S2D2D([Values(0u)] uint Rd,
                                                  [Values(1u, 0u)] uint Rn,
@@ -2370,6 +2591,216 @@ namespace Ryujinx.Tests.Cpu
             });
         }
 
+        [Test, Pairwise, Description("UQADD <V><d>, <V><n>, <V><m>")]
+        public void Uqadd_S_B_H_S_D([Values(0u)] uint Rd,
+                                    [Values(1u, 0u)] uint Rn,
+                                    [Values(2u, 0u)] uint Rm,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong B,
+                                    [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x7E200C00; // UQADD B0, B0, B0
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Uqadd_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("UQADD <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Uqadd_V_8B_4H_2S([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [Values(2u, 0u)] uint Rm,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong B,
+                                     [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x2E200C00; // UQADD V0.8B, V0.8B, V0.8B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Uqadd_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("UQADD <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Uqadd_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                         [Values(1u, 0u)] uint Rn,
+                                         [Values(2u, 0u)] uint Rm,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong B,
+                                         [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x6E200C00; // UQADD V0.16B, V0.16B, V0.16B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            Vector128<float> V2 = MakeVectorE0E1(B, B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            AArch64.Vpart(2, 0, new Bits(B)); AArch64.Vpart(2, 1, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Uqadd_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("UQSUB <V><d>, <V><n>, <V><m>")]
+        public void Uqsub_S_B_H_S_D([Values(0u)] uint Rd,
+                                    [Values(1u, 0u)] uint Rn,
+                                    [Values(2u, 0u)] uint Rm,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong Z,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong A,
+                                    [ValueSource("_1B1H1S1D_")] [Random(RndCnt)] ulong B,
+                                    [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <B, H, S, D>
+        {
+            uint Opcode = 0x7E202C00; // UQSUB B0, B0, B0
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Uqsub_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("UQSUB <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Uqsub_V_8B_4H_2S([Values(0u)] uint Rd,
+                                     [Values(1u, 0u)] uint Rn,
+                                     [Values(2u, 0u)] uint Rm,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong Z,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong A,
+                                     [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong B,
+                                     [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S>
+        {
+            uint Opcode = 0x2E202C00; // UQSUB V0.8B, V0.8B, V0.8B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0(A);
+            Vector128<float> V2 = MakeVectorE0(B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.V(1, new Bits(A));
+            AArch64.V(2, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Uqsub_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
+        [Test, Pairwise, Description("UQSUB <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
+        public void Uqsub_V_16B_8H_4S_2D([Values(0u)] uint Rd,
+                                         [Values(1u, 0u)] uint Rn,
+                                         [Values(2u, 0u)] uint Rm,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong Z,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong A,
+                                         [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong B,
+                                         [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D>
+        {
+            uint Opcode = 0x6E202C00; // UQSUB V0.16B, V0.16B, V0.16B
+            Opcode |= ((Rm & 31) << 16) | ((Rn & 31) << 5) | ((Rd & 31) << 0);
+            Opcode |= ((size & 3) << 22);
+            Bits Op = new Bits(Opcode);
+
+            int Fpsr = (int)TestContext.CurrentContext.Random.NextUInt();
+
+            Vector128<float> V0 = MakeVectorE0E1(Z, Z);
+            Vector128<float> V1 = MakeVectorE0E1(A, A);
+            Vector128<float> V2 = MakeVectorE0E1(B, B);
+            AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2, Fpsr: Fpsr);
+
+            AArch64.Vpart(0, 0, new Bits(Z)); AArch64.Vpart(0, 1, new Bits(Z));
+            AArch64.Vpart(1, 0, new Bits(A)); AArch64.Vpart(1, 1, new Bits(A));
+            AArch64.Vpart(2, 0, new Bits(B)); AArch64.Vpart(2, 1, new Bits(B));
+            Shared.FPSR = new Bits((uint)Fpsr);
+            SimdFp.Uqsub_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
+
+            Assert.Multiple(() =>
+            {
+                Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 0).ToUInt64()));
+                Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
+            });
+            Assert.That(ThreadState.Fpsr, Is.EqualTo((int)Shared.FPSR.ToUInt32()));
+        }
+
         [Test, Pairwise, Description("USUBW{2} <Vd>.<Ta>, <Vn>.<Ta>, <Vm>.<Tb>")]
         public void Usubw_V_8B8H8H_4H4S4S_2S2D2D([Values(0u)] uint Rd,
                                                  [Values(1u, 0u)] uint Rn,

+ 860 - 84
Ryujinx.Tests/Cpu/Tester/Instructions.cs

@@ -3060,6 +3060,210 @@ namespace Ryujinx.Tests.Cpu.Tester
             V(d, result);
         }
 
+        // sqabs_advsimd.html#SQABS_asisdmisc_R
+        public static void Sqabs_S(Bits size, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+
+            /* Decode Scalar */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = esize;
+            int elements = 1;
+
+            bool neg = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(datasize, n);
+            BigInteger element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = SInt(Elem(operand, e, esize));
+
+                if (neg)
+                {
+                    element = -element;
+                }
+                else
+                {
+                    element = Abs(element);
+                }
+
+                (Bits _result, bool _sat) = SignedSatQ(element, esize);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
+        // sqabs_advsimd.html#SQABS_asimdmisc_R
+        public static void Sqabs_V(bool Q, Bits size, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+
+            /* Decode Vector */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
+            /* if size:Q == '110' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = (Q ? 128 : 64);
+            int elements = datasize / esize;
+
+            bool neg = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(datasize, n);
+            BigInteger element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = SInt(Elem(operand, e, esize));
+
+                if (neg)
+                {
+                    element = -element;
+                }
+                else
+                {
+                    element = Abs(element);
+                }
+
+                (Bits _result, bool _sat) = SignedSatQ(element, esize);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
+        // sqneg_advsimd.html#SQNEG_asisdmisc_R
+        public static void Sqneg_S(Bits size, Bits Rn, Bits Rd)
+        {
+            const bool U = true;
+
+            /* Decode Scalar */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = esize;
+            int elements = 1;
+
+            bool neg = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(datasize, n);
+            BigInteger element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = SInt(Elem(operand, e, esize));
+
+                if (neg)
+                {
+                    element = -element;
+                }
+                else
+                {
+                    element = Abs(element);
+                }
+
+                (Bits _result, bool _sat) = SignedSatQ(element, esize);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
+        // sqneg_advsimd.html#SQNEG_asimdmisc_R
+        public static void Sqneg_V(bool Q, Bits size, Bits Rn, Bits Rd)
+        {
+            const bool U = true;
+
+            /* Decode Vector */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
+            /* if size:Q == '110' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = (Q ? 128 : 64);
+            int elements = datasize / esize;
+
+            bool neg = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(datasize, n);
+            BigInteger element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = SInt(Elem(operand, e, esize));
+
+                if (neg)
+                {
+                    element = -element;
+                }
+                else
+                {
+                    element = Abs(element);
+                }
+
+                (Bits _result, bool _sat) = SignedSatQ(element, esize);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
         // sqxtn_advsimd.html#SQXTN_asisdmisc_N
         public static void Sqxtn_S(Bits size, Bits Rn, Bits Rd)
         {
@@ -3069,11 +3273,176 @@ namespace Ryujinx.Tests.Cpu.Tester
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
 
-            /* if size == '11' then ReservedValue(); */
-
+            /* if size == '11' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = esize;
+            int part = 0;
+            int elements = 1;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(2 * datasize, n);
+            Bits element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = Elem(operand, e, 2 * esize);
+
+                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            Vpart(d, part, result);
+        }
+
+        // sqxtn_advsimd.html#SQXTN_asimdmisc_N
+        public static void Sqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+
+            /* Decode Vector */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
+            /* if size == '11' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = 64;
+            int part = (int)UInt(Q);
+            int elements = datasize / esize;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(2 * datasize, n);
+            Bits element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = Elem(operand, e, 2 * esize);
+
+                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            Vpart(d, part, result);
+        }
+
+        // sqxtun_advsimd.html#SQXTUN_asisdmisc_N
+        public static void Sqxtun_S(Bits size, Bits Rn, Bits Rd)
+        {
+            /* Decode Scalar */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
+            /* if size == '11' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = esize;
+            int part = 0;
+            int elements = 1;
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(2 * datasize, n);
+            Bits element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = Elem(operand, e, 2 * esize);
+
+                (Bits _result, bool _sat) = UnsignedSatQ(SInt(element), esize);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            Vpart(d, part, result);
+        }
+
+        // sqxtun_advsimd.html#SQXTUN_asimdmisc_N
+        public static void Sqxtun_V(bool Q, Bits size, Bits Rn, Bits Rd)
+        {
+            /* Decode Vector */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
+            /* if size == '11' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = 64;
+            int part = (int)UInt(Q);
+            int elements = datasize / esize;
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand = V(2 * datasize, n);
+            Bits element;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element = Elem(operand, e, 2 * esize);
+
+                (Bits _result, bool _sat) = UnsignedSatQ(SInt(element), esize);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            Vpart(d, part, result);
+        }
+
+        // suqadd_advsimd.html#SUQADD_asisdmisc_R
+        public static void Suqadd_S(Bits size, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+
+            /* Decode Scalar */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+
             int esize = 8 << (int)UInt(size);
             int datasize = esize;
-            int part = 0;
             int elements = 1;
 
             bool unsigned = (U == true);
@@ -3082,15 +3451,18 @@ namespace Ryujinx.Tests.Cpu.Tester
             /* CheckFPAdvSIMDEnabled64(); */
 
             Bits result = new Bits(datasize);
-            Bits operand = V(2 * datasize, n);
-            Bits element;
+            Bits operand = V(datasize, n);
+            Bits operand2 = V(datasize, d);
+            BigInteger op1;
+            BigInteger op2;
             bool sat;
 
             for (int e = 0; e <= elements - 1; e++)
             {
-                element = Elem(operand, e, 2 * esize);
+                op1 = Int(Elem(operand, e, esize), !unsigned);
+                op2 = Int(Elem(operand2, e, esize), unsigned);
 
-                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
+                (Bits _result, bool _sat) = SatQ(op1 + op2, esize, unsigned);
                 Elem(result, e, esize, _result);
                 sat = _sat;
 
@@ -3101,11 +3473,11 @@ namespace Ryujinx.Tests.Cpu.Tester
                 }
             }
 
-            Vpart(d, part, result);
+            V(d, result);
         }
 
-        // sqxtn_advsimd.html#SQXTN_asimdmisc_N
-        public static void Sqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd)
+        // suqadd_advsimd.html#SUQADD_asimdmisc_R
+        public static void Suqadd_V(bool Q, Bits size, Bits Rn, Bits Rd)
         {
             const bool U = false;
 
@@ -3113,11 +3485,10 @@ namespace Ryujinx.Tests.Cpu.Tester
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
 
-            /* if size == '11' then ReservedValue(); */
+            /* if size:Q == '110' then ReservedValue(); */
 
             int esize = 8 << (int)UInt(size);
-            int datasize = 64;
-            int part = (int)UInt(Q);
+            int datasize = (Q ? 128 : 64);
             int elements = datasize / esize;
 
             bool unsigned = (U == true);
@@ -3126,15 +3497,18 @@ namespace Ryujinx.Tests.Cpu.Tester
             /* CheckFPAdvSIMDEnabled64(); */
 
             Bits result = new Bits(datasize);
-            Bits operand = V(2 * datasize, n);
-            Bits element;
+            Bits operand = V(datasize, n);
+            Bits operand2 = V(datasize, d);
+            BigInteger op1;
+            BigInteger op2;
             bool sat;
 
             for (int e = 0; e <= elements - 1; e++)
             {
-                element = Elem(operand, e, 2 * esize);
+                op1 = Int(Elem(operand, e, esize), !unsigned);
+                op2 = Int(Elem(operand2, e, esize), unsigned);
 
-                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
+                (Bits _result, bool _sat) = SatQ(op1 + op2, esize, unsigned);
                 Elem(result, e, esize, _result);
                 sat = _sat;
 
@@ -3145,12 +3519,14 @@ namespace Ryujinx.Tests.Cpu.Tester
                 }
             }
 
-            Vpart(d, part, result);
+            V(d, result);
         }
 
-        // sqxtun_advsimd.html#SQXTUN_asisdmisc_N
-        public static void Sqxtun_S(Bits size, Bits Rn, Bits Rd)
+        // uqxtn_advsimd.html#UQXTN_asisdmisc_N
+        public static void Uqxtn_S(Bits size, Bits Rn, Bits Rd)
         {
+            const bool U = true;
+
             /* Decode Scalar */
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
@@ -3162,6 +3538,8 @@ namespace Ryujinx.Tests.Cpu.Tester
             int part = 0;
             int elements = 1;
 
+            bool unsigned = (U == true);
+
             /* Operation */
             /* CheckFPAdvSIMDEnabled64(); */
 
@@ -3174,7 +3552,7 @@ namespace Ryujinx.Tests.Cpu.Tester
             {
                 element = Elem(operand, e, 2 * esize);
 
-                (Bits _result, bool _sat) = UnsignedSatQ(SInt(element), esize);
+                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
                 Elem(result, e, esize, _result);
                 sat = _sat;
 
@@ -3188,9 +3566,11 @@ namespace Ryujinx.Tests.Cpu.Tester
             Vpart(d, part, result);
         }
 
-        // sqxtun_advsimd.html#SQXTUN_asimdmisc_N
-        public static void Sqxtun_V(bool Q, Bits size, Bits Rn, Bits Rd)
+        // uqxtn_advsimd.html#UQXTN_asimdmisc_N
+        public static void Uqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd)
         {
+            const bool U = true;
+
             /* Decode Vector */
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
@@ -3202,6 +3582,8 @@ namespace Ryujinx.Tests.Cpu.Tester
             int part = (int)UInt(Q);
             int elements = datasize / esize;
 
+            bool unsigned = (U == true);
+
             /* Operation */
             /* CheckFPAdvSIMDEnabled64(); */
 
@@ -3214,7 +3596,7 @@ namespace Ryujinx.Tests.Cpu.Tester
             {
                 element = Elem(operand, e, 2 * esize);
 
-                (Bits _result, bool _sat) = UnsignedSatQ(SInt(element), esize);
+                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
                 Elem(result, e, esize, _result);
                 sat = _sat;
 
@@ -3228,8 +3610,8 @@ namespace Ryujinx.Tests.Cpu.Tester
             Vpart(d, part, result);
         }
 
-        // uqxtn_advsimd.html#UQXTN_asisdmisc_N
-        public static void Uqxtn_S(Bits size, Bits Rn, Bits Rd)
+        // usqadd_advsimd.html#USQADD_asisdmisc_R
+        public static void Usqadd_S(Bits size, Bits Rn, Bits Rd)
         {
             const bool U = true;
 
@@ -3237,11 +3619,8 @@ namespace Ryujinx.Tests.Cpu.Tester
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
 
-            /* if size == '11' then ReservedValue(); */
-
             int esize = 8 << (int)UInt(size);
             int datasize = esize;
-            int part = 0;
             int elements = 1;
 
             bool unsigned = (U == true);
@@ -3250,15 +3629,18 @@ namespace Ryujinx.Tests.Cpu.Tester
             /* CheckFPAdvSIMDEnabled64(); */
 
             Bits result = new Bits(datasize);
-            Bits operand = V(2 * datasize, n);
-            Bits element;
+            Bits operand = V(datasize, n);
+            Bits operand2 = V(datasize, d);
+            BigInteger op1;
+            BigInteger op2;
             bool sat;
 
             for (int e = 0; e <= elements - 1; e++)
             {
-                element = Elem(operand, e, 2 * esize);
+                op1 = Int(Elem(operand, e, esize), !unsigned);
+                op2 = Int(Elem(operand2, e, esize), unsigned);
 
-                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
+                (Bits _result, bool _sat) = SatQ(op1 + op2, esize, unsigned);
                 Elem(result, e, esize, _result);
                 sat = _sat;
 
@@ -3269,11 +3651,11 @@ namespace Ryujinx.Tests.Cpu.Tester
                 }
             }
 
-            Vpart(d, part, result);
+            V(d, result);
         }
 
-        // uqxtn_advsimd.html#UQXTN_asimdmisc_N
-        public static void Uqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd)
+        // usqadd_advsimd.html#USQADD_asimdmisc_R
+        public static void Usqadd_V(bool Q, Bits size, Bits Rn, Bits Rd)
         {
             const bool U = true;
 
@@ -3281,11 +3663,10 @@ namespace Ryujinx.Tests.Cpu.Tester
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
 
-            /* if size == '11' then ReservedValue(); */
+            /* if size:Q == '110' then ReservedValue(); */
 
             int esize = 8 << (int)UInt(size);
-            int datasize = 64;
-            int part = (int)UInt(Q);
+            int datasize = (Q ? 128 : 64);
             int elements = datasize / esize;
 
             bool unsigned = (U == true);
@@ -3294,15 +3675,18 @@ namespace Ryujinx.Tests.Cpu.Tester
             /* CheckFPAdvSIMDEnabled64(); */
 
             Bits result = new Bits(datasize);
-            Bits operand = V(2 * datasize, n);
-            Bits element;
+            Bits operand = V(datasize, n);
+            Bits operand2 = V(datasize, d);
+            BigInteger op1;
+            BigInteger op2;
             bool sat;
 
             for (int e = 0; e <= elements - 1; e++)
             {
-                element = Elem(operand, e, 2 * esize);
+                op1 = Int(Elem(operand, e, esize), !unsigned);
+                op2 = Int(Elem(operand2, e, esize), unsigned);
 
-                (Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
+                (Bits _result, bool _sat) = SatQ(op1 + op2, esize, unsigned);
                 Elem(result, e, esize, _result);
                 sat = _sat;
 
@@ -3313,7 +3697,7 @@ namespace Ryujinx.Tests.Cpu.Tester
                 }
             }
 
-            Vpart(d, part, result);
+            V(d, result);
         }
 
         // xtn_advsimd.html
@@ -4489,105 +4873,301 @@ namespace Ryujinx.Tests.Cpu.Tester
                 element1 = Int(Elem(operand1, e, esize), unsigned);
                 element2 = Int(Elem(operand2, e, esize), unsigned);
 
-                absdiff = Abs(element1 - element2).SubBigInteger(esize - 1, 0);
+                absdiff = Abs(element1 - element2).SubBigInteger(esize - 1, 0);
+
+                Elem(result, e, esize, Elem(result, e, esize) + absdiff);
+            }
+
+            V(d, result);
+        }
+
+        // sabdl_advsimd.html
+        public static void Sabdl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+            const bool op = true;
+
+            /* Decode */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            /* if size == '11' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = 64;
+            int part = (int)UInt(Q);
+            int elements = datasize / esize;
+
+            bool accumulate = (op == false);
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits operand1 = Vpart(datasize, n, part);
+            Bits operand2 = Vpart(datasize, m, part);
+            BigInteger element1;
+            BigInteger element2;
+            Bits absdiff;
+
+            Bits result = (accumulate ? V(2 * datasize, d) : Zeros(2 * datasize));
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                absdiff = Abs(element1 - element2).SubBigInteger(2 * esize - 1, 0);
+
+                Elem(result, e, 2 * esize, Elem(result, e, 2 * esize) + absdiff);
+            }
+
+            V(d, result);
+        }
+
+        // saddw_advsimd.html
+        public static void Saddw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+            const bool o1 = false;
+
+            /* Decode */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            /* if size == '11' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = 64;
+            int part = (int)UInt(Q);
+            int elements = datasize / esize;
+
+            bool sub_op = (o1 == true);
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(2 * datasize);
+            Bits operand1 = V(2 * datasize, n);
+            Bits operand2 = Vpart(datasize, m, part);
+            BigInteger element1;
+            BigInteger element2;
+            BigInteger sum;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, 2 * esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                if (sub_op)
+                {
+                    sum = element1 - element2;
+                }
+                else
+                {
+                    sum = element1 + element2;
+                }
+
+                Elem(result, e, 2 * esize, sum.SubBigInteger(2 * esize - 1, 0));
+            }
+
+            V(d, result);
+        }
+
+        // sqadd_advsimd.html#SQADD_asisdsame_only
+        public static void Sqadd_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+
+            /* Decode Scalar */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = esize;
+            int elements = 1;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
+            BigInteger element1;
+            BigInteger element2;
+            BigInteger sum;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                sum = element1 + element2;
+
+                (Bits _result, bool _sat) = SatQ(sum, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
+        // sqadd_advsimd.html#SQADD_asimdsame_only
+        public static void Sqadd_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = false;
+
+            /* Decode Vector */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            /* if size:Q == '110' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = (Q ? 128 : 64);
+            int elements = datasize / esize;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
+            BigInteger element1;
+            BigInteger element2;
+            BigInteger sum;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                sum = element1 + element2;
 
-                Elem(result, e, esize, Elem(result, e, esize) + absdiff);
+                (Bits _result, bool _sat) = SatQ(sum, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
             }
 
             V(d, result);
         }
 
-        // sabdl_advsimd.html
-        public static void Sabdl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
+        // sqsub_advsimd.html#SQSUB_asisdsame_only
+        public static void Sqsub_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
         {
             const bool U = false;
-            const bool op = true;
 
-            /* Decode */
+            /* Decode Scalar */
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
             int m = (int)UInt(Rm);
 
-            /* if size == '11' then ReservedValue(); */
-
             int esize = 8 << (int)UInt(size);
-            int datasize = 64;
-            int part = (int)UInt(Q);
-            int elements = datasize / esize;
+            int datasize = esize;
+            int elements = 1;
 
-            bool accumulate = (op == false);
             bool unsigned = (U == true);
 
             /* Operation */
             /* CheckFPAdvSIMDEnabled64(); */
 
-            Bits operand1 = Vpart(datasize, n, part);
-            Bits operand2 = Vpart(datasize, m, part);
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
             BigInteger element1;
             BigInteger element2;
-            Bits absdiff;
-
-            Bits result = (accumulate ? V(2 * datasize, d) : Zeros(2 * datasize));
+            BigInteger diff;
+            bool sat;
 
             for (int e = 0; e <= elements - 1; e++)
             {
                 element1 = Int(Elem(operand1, e, esize), unsigned);
                 element2 = Int(Elem(operand2, e, esize), unsigned);
 
-                absdiff = Abs(element1 - element2).SubBigInteger(2 * esize - 1, 0);
+                diff = element1 - element2;
 
-                Elem(result, e, 2 * esize, Elem(result, e, 2 * esize) + absdiff);
+                (Bits _result, bool _sat) = SatQ(diff, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
             }
 
             V(d, result);
         }
 
-        // saddw_advsimd.html
-        public static void Saddw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
+        // sqsub_advsimd.html#SQSUB_asimdsame_only
+        public static void Sqsub_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
         {
             const bool U = false;
-            const bool o1 = false;
 
-            /* Decode */
+            /* Decode Vector */
             int d = (int)UInt(Rd);
             int n = (int)UInt(Rn);
             int m = (int)UInt(Rm);
 
-            /* if size == '11' then ReservedValue(); */
+            /* if size:Q == '110' then ReservedValue(); */
 
             int esize = 8 << (int)UInt(size);
-            int datasize = 64;
-            int part = (int)UInt(Q);
+            int datasize = (Q ? 128 : 64);
             int elements = datasize / esize;
 
-            bool sub_op = (o1 == true);
             bool unsigned = (U == true);
 
             /* Operation */
             /* CheckFPAdvSIMDEnabled64(); */
 
-            Bits result = new Bits(2 * datasize);
-            Bits operand1 = V(2 * datasize, n);
-            Bits operand2 = Vpart(datasize, m, part);
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
             BigInteger element1;
             BigInteger element2;
-            BigInteger sum;
+            BigInteger diff;
+            bool sat;
 
             for (int e = 0; e <= elements - 1; e++)
             {
-                element1 = Int(Elem(operand1, e, 2 * esize), unsigned);
+                element1 = Int(Elem(operand1, e, esize), unsigned);
                 element2 = Int(Elem(operand2, e, esize), unsigned);
 
-                if (sub_op)
-                {
-                    sum = element1 - element2;
-                }
-                else
+                diff = element1 - element2;
+
+                (Bits _result, bool _sat) = SatQ(diff, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
                 {
-                    sum = element1 + element2;
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
                 }
-
-                Elem(result, e, 2 * esize, sum.SubBigInteger(2 * esize - 1, 0));
             }
 
             V(d, result);
@@ -5085,6 +5665,202 @@ namespace Ryujinx.Tests.Cpu.Tester
             V(d, result);
         }
 
+        // uqadd_advsimd.html#UQADD_asisdsame_only
+        public static void Uqadd_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = true;
+
+            /* Decode Scalar */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = esize;
+            int elements = 1;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
+            BigInteger element1;
+            BigInteger element2;
+            BigInteger sum;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                sum = element1 + element2;
+
+                (Bits _result, bool _sat) = SatQ(sum, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
+        // uqadd_advsimd.html#UQADD_asimdsame_only
+        public static void Uqadd_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = true;
+
+            /* Decode Vector */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            /* if size:Q == '110' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = (Q ? 128 : 64);
+            int elements = datasize / esize;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
+            BigInteger element1;
+            BigInteger element2;
+            BigInteger sum;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                sum = element1 + element2;
+
+                (Bits _result, bool _sat) = SatQ(sum, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
+        // uqsub_advsimd.html#UQSUB_asisdsame_only
+        public static void Uqsub_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = true;
+
+            /* Decode Scalar */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = esize;
+            int elements = 1;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
+            BigInteger element1;
+            BigInteger element2;
+            BigInteger diff;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                diff = element1 - element2;
+
+                (Bits _result, bool _sat) = SatQ(diff, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
+        // uqsub_advsimd.html#UQSUB_asimdsame_only
+        public static void Uqsub_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
+        {
+            const bool U = true;
+
+            /* Decode Vector */
+            int d = (int)UInt(Rd);
+            int n = (int)UInt(Rn);
+            int m = (int)UInt(Rm);
+
+            /* if size:Q == '110' then ReservedValue(); */
+
+            int esize = 8 << (int)UInt(size);
+            int datasize = (Q ? 128 : 64);
+            int elements = datasize / esize;
+
+            bool unsigned = (U == true);
+
+            /* Operation */
+            /* CheckFPAdvSIMDEnabled64(); */
+
+            Bits result = new Bits(datasize);
+            Bits operand1 = V(datasize, n);
+            Bits operand2 = V(datasize, m);
+            BigInteger element1;
+            BigInteger element2;
+            BigInteger diff;
+            bool sat;
+
+            for (int e = 0; e <= elements - 1; e++)
+            {
+                element1 = Int(Elem(operand1, e, esize), unsigned);
+                element2 = Int(Elem(operand2, e, esize), unsigned);
+
+                diff = element1 - element2;
+
+                (Bits _result, bool _sat) = SatQ(diff, esize, unsigned);
+                Elem(result, e, esize, _result);
+                sat = _sat;
+
+                if (sat)
+                {
+                    /* FPSR.QC = '1'; */
+                    FPSR[27] = true; // TODO: Add named fields.
+                }
+            }
+
+            V(d, result);
+        }
+
         // usubw_advsimd.html
         public static void Usubw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
         {

+ 2 - 2
Ryujinx.Tests/Cpu/Tester/Pseudocode.cs

@@ -1193,9 +1193,9 @@ namespace Ryujinx.Tests.Cpu.Tester
                 result = BigInteger.Pow(2, N) - 1;
                 saturated = true;
             }
-            else if (i < 0)
+            else if (i < (BigInteger)0)
             {
-                result = 0;
+                result = (BigInteger)0;
                 saturated = true;
             }
             else