From 3bdd109f45cc3edc0217f5e952a6cc672ce53580 Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Mon, 18 Jun 2018 19:55:26 +0200 Subject: [PATCH] Add Cmeq_S, Cmge_S, Cmgt_S, Cmhi_S, Cmhs_S, Cmle_S, Cmlt_S (Reg, Zero) & Cmtst_S compare instructions. Add 22 compare tests (Scalar, Vector). Add Eor_V, Not_V tests. (#171) * Add files via upload * Add files via upload * Delete CpuTestScalar.cs * Update CpuTestSimdArithmetic.cs --- ChocolArm64/AOpCodeTable.cs | 11 + ChocolArm64/Instruction/AInstEmitSimdCmp.cs | 137 +- Ryujinx.Tests/Cpu/CpuTest.cs | 4 +- Ryujinx.Tests/Cpu/CpuTestAlu.cs | 5 + Ryujinx.Tests/Cpu/CpuTestAluImm.cs | 5 + Ryujinx.Tests/Cpu/CpuTestAluRs.cs | 5 + Ryujinx.Tests/Cpu/CpuTestAluRx.cs | 5 + Ryujinx.Tests/Cpu/CpuTestBfm.cs | 5 + Ryujinx.Tests/Cpu/CpuTestCcmpImm.cs | 5 + Ryujinx.Tests/Cpu/CpuTestCcmpReg.cs | 5 + Ryujinx.Tests/Cpu/CpuTestCsel.cs | 5 + Ryujinx.Tests/Cpu/CpuTestMov.cs | 5 + Ryujinx.Tests/Cpu/CpuTestMul.cs | 5 + Ryujinx.Tests/Cpu/CpuTestScalar.cs | 63 - Ryujinx.Tests/Cpu/CpuTestSimd.cs | 386 ++++- Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs | 86 +- Ryujinx.Tests/Cpu/CpuTestSimdMove.cs | 8 +- Ryujinx.Tests/Cpu/CpuTestSimdReg.cs | 507 +++++- Ryujinx.Tests/Cpu/Tester/Instructions.cs | 1555 +++++++++++++++++-- Ryujinx.Tests/Cpu/Tester/Pseudocode.cs | 155 +- 20 files changed, 2624 insertions(+), 338 deletions(-) delete mode 100644 Ryujinx.Tests/Cpu/CpuTestScalar.cs diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 903d6e0f..853c06a6 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -187,16 +187,27 @@ namespace ChocolArm64 SetA64("0x101110011xxxxx000111xxxxxxxxxx", AInstEmit.Bsl_V, typeof(AOpCodeSimdReg)); SetA64("0x001110<<100000010010xxxxxxxxxx", AInstEmit.Cls_V, typeof(AOpCodeSimd)); SetA64("0x101110<<100000010010xxxxxxxxxx", AInstEmit.Clz_V, typeof(AOpCodeSimd)); + SetA64("01111110111xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_S, typeof(AOpCodeSimdReg)); + SetA64("0101111011100000100110xxxxxxxxxx", AInstEmit.Cmeq_S, typeof(AOpCodeSimd)); SetA64("0>101110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimdReg)); SetA64("0>001110<<100000100110xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimd)); + SetA64("01011110111xxxxx001111xxxxxxxxxx", AInstEmit.Cmge_S, typeof(AOpCodeSimdReg)); + SetA64("0111111011100000100010xxxxxxxxxx", AInstEmit.Cmge_S, typeof(AOpCodeSimd)); SetA64("0>001110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimdReg)); SetA64("0>101110<<100000100010xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimd)); + SetA64("01011110111xxxxx001101xxxxxxxxxx", AInstEmit.Cmgt_S, typeof(AOpCodeSimdReg)); + SetA64("0101111011100000100010xxxxxxxxxx", AInstEmit.Cmgt_S, typeof(AOpCodeSimd)); SetA64("0>001110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimdReg)); SetA64("0>001110<<100000100010xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimd)); + SetA64("01111110111xxxxx001101xxxxxxxxxx", AInstEmit.Cmhi_S, typeof(AOpCodeSimdReg)); SetA64("0>101110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmhi_V, typeof(AOpCodeSimdReg)); + SetA64("01111110111xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_S, typeof(AOpCodeSimdReg)); SetA64("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg)); + SetA64("0111111011100000100110xxxxxxxxxx", AInstEmit.Cmle_S, typeof(AOpCodeSimd)); SetA64("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd)); + SetA64("0101111011100000101010xxxxxxxxxx", AInstEmit.Cmlt_S, typeof(AOpCodeSimd)); SetA64("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd)); + SetA64("01011110111xxxxx100011xxxxxxxxxx", AInstEmit.Cmtst_S, typeof(AOpCodeSimdReg)); SetA64("0>001110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmtst_V, typeof(AOpCodeSimdReg)); SetA64("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd)); SetA64("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns)); diff --git a/ChocolArm64/Instruction/AInstEmitSimdCmp.cs b/ChocolArm64/Instruction/AInstEmitSimdCmp.cs index 3ffab1e8..ba8ac3e2 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdCmp.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdCmp.cs @@ -12,6 +12,11 @@ namespace ChocolArm64.Instruction { static partial class AInstEmit { + public static void Cmeq_S(AILEmitterCtx Context) + { + EmitCmp(Context, OpCodes.Beq_S, Scalar: true); + } + public static void Cmeq_V(AILEmitterCtx Context) { if (AOptimizations.UseSse2 && Context.CurrOp is AOpCodeSimdReg Op && Op.Size < 3) @@ -20,13 +25,23 @@ namespace ChocolArm64.Instruction } else { - EmitVectorCmp(Context, OpCodes.Beq_S); + EmitCmp(Context, OpCodes.Beq_S, Scalar: false); } } + public static void Cmge_S(AILEmitterCtx Context) + { + EmitCmp(Context, OpCodes.Bge_S, Scalar: true); + } + public static void Cmge_V(AILEmitterCtx Context) { - EmitVectorCmp(Context, OpCodes.Bge_S); + EmitCmp(Context, OpCodes.Bge_S, Scalar: false); + } + + public static void Cmgt_S(AILEmitterCtx Context) + { + EmitCmp(Context, OpCodes.Bgt_S, Scalar: true); } public static void Cmgt_V(AILEmitterCtx Context) @@ -37,67 +52,58 @@ namespace ChocolArm64.Instruction } else { - EmitVectorCmp(Context, OpCodes.Bgt_S); + EmitCmp(Context, OpCodes.Bgt_S, Scalar: false); } } + public static void Cmhi_S(AILEmitterCtx Context) + { + EmitCmp(Context, OpCodes.Bgt_Un_S, Scalar: true); + } + public static void Cmhi_V(AILEmitterCtx Context) { - EmitVectorCmp(Context, OpCodes.Bgt_Un_S); + EmitCmp(Context, OpCodes.Bgt_Un_S, Scalar: false); + } + + public static void Cmhs_S(AILEmitterCtx Context) + { + EmitCmp(Context, OpCodes.Bge_Un_S, Scalar: true); } public static void Cmhs_V(AILEmitterCtx Context) { - EmitVectorCmp(Context, OpCodes.Bge_Un_S); + EmitCmp(Context, OpCodes.Bge_Un_S, Scalar: false); + } + + public static void Cmle_S(AILEmitterCtx Context) + { + EmitCmp(Context, OpCodes.Ble_S, Scalar: true); } public static void Cmle_V(AILEmitterCtx Context) { - EmitVectorCmp(Context, OpCodes.Ble_S); + EmitCmp(Context, OpCodes.Ble_S, Scalar: false); + } + + public static void Cmlt_S(AILEmitterCtx Context) + { + EmitCmp(Context, OpCodes.Blt_S, Scalar: true); } public static void Cmlt_V(AILEmitterCtx Context) { - EmitVectorCmp(Context, OpCodes.Blt_S); + EmitCmp(Context, OpCodes.Blt_S, Scalar: false); + } + + public static void Cmtst_S(AILEmitterCtx Context) + { + EmitCmtst(Context, Scalar: true); } public static void Cmtst_V(AILEmitterCtx Context) { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); - EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size); - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.Emit(OpCodes.And); - - Context.EmitLdc_I8(0); - - Context.Emit(OpCodes.Bne_Un_S, LblTrue); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask); - - Context.MarkLabel(LblEnd); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } + EmitCmtst(Context, Scalar: false); } public static void Fccmp_S(AILEmitterCtx Context) @@ -325,15 +331,16 @@ namespace ChocolArm64.Instruction } } - private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp) + private static void EmitCmp(AILEmitterCtx Context, OpCode ILOp, bool Scalar) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int Bytes = Context.CurrOp.GetBitsCount() >> 3; + int Elems = (!Scalar ? Bytes >> Op.Size : 1); ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + for (int Index = 0; Index < Elems; Index++) { EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size); @@ -362,7 +369,47 @@ namespace ChocolArm64.Instruction Context.MarkLabel(LblEnd); } - if (Op.RegisterSize == ARegisterSize.SIMD64) + if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitCmtst(AILEmitterCtx Context, bool Scalar) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + int Elems = (!Scalar ? Bytes >> Op.Size : 1); + + ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); + EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size); + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.Emit(OpCodes.And); + + Context.EmitLdc_I8(0); + + Context.Emit(OpCodes.Bne_Un_S, LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask); + + Context.MarkLabel(LblEnd); + } + + if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar) { EmitVectorZeroUpper(Context, Op.Rd); } diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index 493be779..e2442ee4 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -1,7 +1,9 @@ using ChocolArm64; using ChocolArm64.Memory; using ChocolArm64.State; + using NUnit.Framework; + using System; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; @@ -38,8 +40,8 @@ namespace Ryujinx.Tests.Cpu public void Teardown() { Memory.Dispose(); - Thread = null; Memory = null; + Thread = null; } protected void Reset() diff --git a/Ryujinx.Tests/Cpu/CpuTestAlu.cs b/Ryujinx.Tests/Cpu/CpuTestAlu.cs index 1efb2a01..564fadec 100644 --- a/Ryujinx.Tests/Cpu/CpuTestAlu.cs +++ b/Ryujinx.Tests/Cpu/CpuTestAlu.cs @@ -1,9 +1,14 @@ //#define Alu +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("Alu"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestAlu : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestAluImm.cs b/Ryujinx.Tests/Cpu/CpuTestAluImm.cs index 73f7bff3..5d1f0b6b 100644 --- a/Ryujinx.Tests/Cpu/CpuTestAluImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestAluImm.cs @@ -1,9 +1,14 @@ //#define AluImm +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("AluImm"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestAluImm : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestAluRs.cs b/Ryujinx.Tests/Cpu/CpuTestAluRs.cs index 2ecaf997..b81f7100 100644 --- a/Ryujinx.Tests/Cpu/CpuTestAluRs.cs +++ b/Ryujinx.Tests/Cpu/CpuTestAluRs.cs @@ -1,9 +1,14 @@ //#define AluRs +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("AluRs"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestAluRs : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestAluRx.cs b/Ryujinx.Tests/Cpu/CpuTestAluRx.cs index c60d86c1..26169bca 100644 --- a/Ryujinx.Tests/Cpu/CpuTestAluRx.cs +++ b/Ryujinx.Tests/Cpu/CpuTestAluRx.cs @@ -1,9 +1,14 @@ //#define AluRx +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("AluRx"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestAluRx : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestBfm.cs b/Ryujinx.Tests/Cpu/CpuTestBfm.cs index f6fd02ce..2952bca4 100644 --- a/Ryujinx.Tests/Cpu/CpuTestBfm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestBfm.cs @@ -1,9 +1,14 @@ //#define Bfm +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("Bfm"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestBfm : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestCcmpImm.cs b/Ryujinx.Tests/Cpu/CpuTestCcmpImm.cs index 915acc3e..38d73878 100644 --- a/Ryujinx.Tests/Cpu/CpuTestCcmpImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestCcmpImm.cs @@ -1,9 +1,14 @@ //#define CcmpImm +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("CcmpImm"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestCcmpImm : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestCcmpReg.cs b/Ryujinx.Tests/Cpu/CpuTestCcmpReg.cs index 6bec214b..eb1c3abf 100644 --- a/Ryujinx.Tests/Cpu/CpuTestCcmpReg.cs +++ b/Ryujinx.Tests/Cpu/CpuTestCcmpReg.cs @@ -1,9 +1,14 @@ //#define CcmpReg +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("CcmpReg"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestCcmpReg : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestCsel.cs b/Ryujinx.Tests/Cpu/CpuTestCsel.cs index 93683adc..9dd61957 100644 --- a/Ryujinx.Tests/Cpu/CpuTestCsel.cs +++ b/Ryujinx.Tests/Cpu/CpuTestCsel.cs @@ -1,9 +1,14 @@ //#define Csel +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("Csel"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestCsel : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestMov.cs b/Ryujinx.Tests/Cpu/CpuTestMov.cs index bd753b21..9c7e3255 100644 --- a/Ryujinx.Tests/Cpu/CpuTestMov.cs +++ b/Ryujinx.Tests/Cpu/CpuTestMov.cs @@ -1,9 +1,14 @@ //#define Mov +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("Mov"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestMov : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestMul.cs b/Ryujinx.Tests/Cpu/CpuTestMul.cs index 23aab037..9bdc1fa6 100644 --- a/Ryujinx.Tests/Cpu/CpuTestMul.cs +++ b/Ryujinx.Tests/Cpu/CpuTestMul.cs @@ -1,9 +1,14 @@ //#define Mul +using ChocolArm64.State; + using NUnit.Framework; namespace Ryujinx.Tests.Cpu { + using Tester; + using Tester.Types; + [Category("Mul"), Ignore("Tested: first half of 2018.")] public sealed class CpuTestMul : CpuTest { diff --git a/Ryujinx.Tests/Cpu/CpuTestScalar.cs b/Ryujinx.Tests/Cpu/CpuTestScalar.cs deleted file mode 100644 index d1a0c313..00000000 --- a/Ryujinx.Tests/Cpu/CpuTestScalar.cs +++ /dev/null @@ -1,63 +0,0 @@ -using ChocolArm64.State; - -using NUnit.Framework; - -using System.Runtime.Intrinsics.X86; - -namespace Ryujinx.Tests.Cpu -{ - public class CpuTestScalar : CpuTest - { - [TestCase(0x1E224820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000000000000ul)] - [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000000000000ul, 0x0000000000000000ul)] - [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] - [TestCase(0x1E224820u, 0x0000000080000000ul, 0x000000003DCCCCCDul, 0x000000003DCCCCCDul)] - [TestCase(0x1E224820u, 0x000000003DCCCCCDul, 0x000000003C9623B1ul, 0x000000003DCCCCCDul)] - [TestCase(0x1E224820u, 0x000000008BA98D27ul, 0x0000000000000076ul, 0x0000000000000076ul)] - [TestCase(0x1E224820u, 0x00000000807FFFFFul, 0x000000007F7FFFFFul, 0x000000007F7FFFFFul)] - [TestCase(0x1E224820u, 0x000000007F7FFFFFul, 0x00000000807FFFFFul, 0x000000007F7FFFFFul)] - [TestCase(0x1E224820u, 0x000000007FC00000ul, 0x000000003F800000ul, 0x000000007FC00000ul)] - [TestCase(0x1E224820u, 0x000000003F800000ul, 0x000000007FC00000ul, 0x000000007FC00000ul)] - [TestCase(0x1E224820u, 0x000000007F800001ul, 0x000000007FC00042ul, 0x000000007FC00001ul, Ignore = "NaN test.")] - [TestCase(0x1E224820u, 0x000000007FC00042ul, 0x000000007F800001ul, 0x000000007FC00001ul, Ignore = "NaN test.")] - [TestCase(0x1E224820u, 0x000000007FC0000Aul, 0x000000007FC0000Bul, 0x000000007FC0000Aul, Ignore = "NaN test.")] - [TestCase(0x1E624820u, 0x0000000000000000ul, 0x8000000000000000ul, 0x0000000000000000ul)] - [TestCase(0x1E624820u, 0x8000000000000000ul, 0x0000000000000000ul, 0x0000000000000000ul)] - [TestCase(0x1E624820u, 0x8000000000000000ul, 0x8000000000000000ul, 0x8000000000000000ul)] - [TestCase(0x1E624820u, 0x8000000000000000ul, 0x3FF3333333333333ul, 0x3FF3333333333333ul)] - public void Fmax_S(uint Opcode, ulong A, ulong B, ulong Result) - { - // FMAX S0, S1, S2 - AThreadState ThreadState = SingleOpcode(Opcode, - V1: Sse.StaticCast(Sse2.SetVector128(0, A)), - V2: Sse.StaticCast(Sse2.SetVector128(0, B))); - Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast(ThreadState.V0), 0)); - } - - [TestCase(0x1E225820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] - [TestCase(0x1E225820u, 0x0000000080000000ul, 0x0000000000000000ul, 0x0000000080000000ul)] - [TestCase(0x1E225820u, 0x0000000080000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] - [TestCase(0x1E225820u, 0x0000000080000000ul, 0x000000003DCCCCCDul, 0x0000000080000000ul)] - [TestCase(0x1E225820u, 0x000000003DCCCCCDul, 0x000000003C9623B1ul, 0x000000003C9623B1ul)] - [TestCase(0x1E225820u, 0x000000008BA98D27ul, 0x0000000000000076ul, 0x000000008BA98D27ul)] - [TestCase(0x1E225820u, 0x00000000807FFFFFul, 0x000000007F7FFFFFul, 0x00000000807FFFFFul)] - [TestCase(0x1E225820u, 0x000000007F7FFFFFul, 0x00000000807FFFFFul, 0x00000000807FFFFFul)] - [TestCase(0x1E225820u, 0x000000007FC00000ul, 0x000000003F800000ul, 0x000000007FC00000ul)] - [TestCase(0x1E225820u, 0x000000003F800000ul, 0x000000007FC00000ul, 0x000000007FC00000ul)] - [TestCase(0x1E225820u, 0x000000007F800001ul, 0x000000007FC00042ul, 0x000000007FC00001ul, Ignore = "NaN test.")] - [TestCase(0x1E225820u, 0x000000007FC00042ul, 0x000000007F800001ul, 0x000000007FC00001ul, Ignore = "NaN test.")] - [TestCase(0x1E225820u, 0x000000007FC0000Aul, 0x000000007FC0000Bul, 0x000000007FC0000Aul, Ignore = "NaN test.")] - [TestCase(0x1E625820u, 0x0000000000000000ul, 0x8000000000000000ul, 0x8000000000000000ul)] - [TestCase(0x1E625820u, 0x8000000000000000ul, 0x0000000000000000ul, 0x8000000000000000ul)] - [TestCase(0x1E625820u, 0x8000000000000000ul, 0x8000000000000000ul, 0x8000000000000000ul)] - [TestCase(0x1E625820u, 0x8000000000000000ul, 0x3FF3333333333333ul, 0x8000000000000000ul)] - public void Fmin_S(uint Opcode, ulong A, ulong B, ulong Result) - { - // FMIN S0, S1, S2 - AThreadState ThreadState = SingleOpcode(Opcode, - V1: Sse.StaticCast(Sse2.SetVector128(0, A)), - V2: Sse.StaticCast(Sse2.SetVector128(0, B))); - Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast(ThreadState.V0), 0)); - } - } -} diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs index e2adc995..6cc82304 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Tests.Cpu using Tester; using Tester.Types; - [Category("Simd")] + [Category("Simd")/*, Ignore("Tested: first half of 2018.")*/] public sealed class CpuTestSimd : CpuTest { #if Simd @@ -45,6 +45,12 @@ namespace Ryujinx.Tests.Cpu 0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul }; } + private static ulong[] _8B_() + { + return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful, + 0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul }; + } + private static ulong[] _8B4H_() { return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful, @@ -297,6 +303,331 @@ namespace Ryujinx.Tests.Cpu }); } + [Test, Description("CMEQ , , #0")] + public void Cmeq_S_D([ValueSource("_1D_")] [Random(1)] ulong A) + { + uint Opcode = 0x5EE09820; // CMEQ D0, D1, #0 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmeq_Zero_S(Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMEQ ., ., #0")] + public void Cmeq_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x0E209820; // CMEQ V0.8B, V1.8B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmeq_Zero_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMEQ ., ., #0")] + public void Cmeq_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x4E209820; // CMEQ V0.16B, V1.16B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + SimdFp.Cmeq_Zero_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())); + }); + } + + [Test, Description("CMGE , , #0")] + public void Cmge_S_D([ValueSource("_1D_")] [Random(1)] ulong A) + { + uint Opcode = 0x7EE08820; // CMGE D0, D1, #0 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmge_Zero_S(Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMGE ., ., #0")] + public void Cmge_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x2E208820; // CMGE V0.8B, V1.8B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmge_Zero_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMGE ., ., #0")] + public void Cmge_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x6E208820; // CMGE V0.16B, V1.16B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + SimdFp.Cmge_Zero_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())); + }); + } + + [Test, Description("CMGT , , #0")] + public void Cmgt_S_D([ValueSource("_1D_")] [Random(1)] ulong A) + { + uint Opcode = 0x5EE08820; // CMGT D0, D1, #0 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmgt_Zero_S(Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMGT ., ., #0")] + public void Cmgt_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x0E208820; // CMGT V0.8B, V1.8B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmgt_Zero_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMGT ., ., #0")] + public void Cmgt_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x4E208820; // CMGT V0.16B, V1.16B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + SimdFp.Cmgt_Zero_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())); + }); + } + + [Test, Description("CMLE , , #0")] + public void Cmle_S_D([ValueSource("_1D_")] [Random(1)] ulong A) + { + uint Opcode = 0x7EE09820; // CMLE D0, D1, #0 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmle_S(Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMLE ., ., #0")] + public void Cmle_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x2E209820; // CMLE V0.8B, V1.8B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmle_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMLE ., ., #0")] + public void Cmle_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x6E209820; // CMLE V0.16B, V1.16B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + SimdFp.Cmle_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())); + }); + } + + [Test, Description("CMLT , , #0")] + public void Cmlt_S_D([ValueSource("_1D_")] [Random(1)] ulong A) + { + uint Opcode = 0x5EE0A820; // CMLT D0, D1, #0 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmlt_S(Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMLT ., ., #0")] + public void Cmlt_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x0E20A820; // CMLT V0.8B, V1.8B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Cmlt_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMLT ., ., #0")] + public void Cmlt_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x4E20A820; // CMLT V0.16B, V1.16B, #0 + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + SimdFp.Cmlt_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())); + }); + } + [Test, Description("NEG , ")] public void Neg_S_D([ValueSource("_1D_")] [Random(1)] ulong A) { @@ -362,6 +693,47 @@ namespace Ryujinx.Tests.Cpu }); } + [Test, Description("NOT ., .")] + public void Not_V_8B([ValueSource("_8B_")] [Random(1)] ulong A) + { + uint Opcode = 0x2E205820; // NOT V0.8B, V1.8B + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1); + + AArch64.V(1, new Bits(A)); + SimdFp.Not_V(Op[30], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("NOT ., .")] + public void Not_V_16B([ValueSource("_8B_")] [Random(1)] ulong A0, + [ValueSource("_8B_")] [Random(1)] ulong A1) + { + uint Opcode = 0x6E205820; // NOT V0.16B, V1.16B + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + SimdFp.Not_V(Op[30], 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())); + }); + } + [Test, Description("SQXTN , ")] public void Sqxtn_S_HB_SH_DS([ValueSource("_1H1S1D_")] [Random(1)] ulong A, [Values(0b00u, 0b01u, 0b10u)] uint size) // @@ -384,7 +756,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); }); - Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution. + Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); } [Test, Pairwise, Description("SQXTN{2} ., .")] @@ -409,7 +781,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); }); - Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution. + Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); } [Test, Pairwise, Description("SQXTN{2} ., .")] @@ -435,7 +807,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(_X0)); 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])); // FIXME: Temporary solution. + Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); } [Test, Description("UQXTN , ")] @@ -460,7 +832,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); }); - Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution. + Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); } [Test, Pairwise, Description("UQXTN{2} ., .")] @@ -485,7 +857,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); }); - Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution. + Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); } [Test, Pairwise, Description("UQXTN{2} ., .")] @@ -511,7 +883,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(_X0)); 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])); // FIXME: Temporary solution. + Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); } #endif } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs index f4982c1b..d04eca7b 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs @@ -49,6 +49,32 @@ namespace Ryujinx.Tests.Cpu }); } + [TestCase(0x1E224820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000000000000ul)] + [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000000000000ul, 0x0000000000000000ul)] + [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] + [TestCase(0x1E224820u, 0x0000000080000000ul, 0x000000003DCCCCCDul, 0x000000003DCCCCCDul)] + [TestCase(0x1E224820u, 0x000000003DCCCCCDul, 0x000000003C9623B1ul, 0x000000003DCCCCCDul)] + [TestCase(0x1E224820u, 0x000000008BA98D27ul, 0x0000000000000076ul, 0x0000000000000076ul)] + [TestCase(0x1E224820u, 0x00000000807FFFFFul, 0x000000007F7FFFFFul, 0x000000007F7FFFFFul)] + [TestCase(0x1E224820u, 0x000000007F7FFFFFul, 0x00000000807FFFFFul, 0x000000007F7FFFFFul)] + [TestCase(0x1E224820u, 0x000000007FC00000ul, 0x000000003F800000ul, 0x000000007FC00000ul)] + [TestCase(0x1E224820u, 0x000000003F800000ul, 0x000000007FC00000ul, 0x000000007FC00000ul)] + [TestCase(0x1E224820u, 0x000000007F800001ul, 0x000000007FC00042ul, 0x000000007FC00001ul, Ignore = "NaN test.")] + [TestCase(0x1E224820u, 0x000000007FC00042ul, 0x000000007F800001ul, 0x000000007FC00001ul, Ignore = "NaN test.")] + [TestCase(0x1E224820u, 0x000000007FC0000Aul, 0x000000007FC0000Bul, 0x000000007FC0000Aul, Ignore = "NaN test.")] + [TestCase(0x1E624820u, 0x0000000000000000ul, 0x8000000000000000ul, 0x0000000000000000ul)] + [TestCase(0x1E624820u, 0x8000000000000000ul, 0x0000000000000000ul, 0x0000000000000000ul)] + [TestCase(0x1E624820u, 0x8000000000000000ul, 0x8000000000000000ul, 0x8000000000000000ul)] + [TestCase(0x1E624820u, 0x8000000000000000ul, 0x3FF3333333333333ul, 0x3FF3333333333333ul)] + public void Fmax_S(uint Opcode, ulong A, ulong B, ulong Result) + { + // FMAX S0, S1, S2 + AThreadState ThreadState = SingleOpcode(Opcode, + V1: Sse.StaticCast(Sse2.SetVector128(0, A)), + V2: Sse.StaticCast(Sse2.SetVector128(0, B))); + Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast(ThreadState.V0), 0)); + } + [TestCase(0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u)] [TestCase(0x00000000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u)] [TestCase(0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u)] @@ -75,6 +101,32 @@ namespace Ryujinx.Tests.Cpu }); } + [TestCase(0x1E225820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] + [TestCase(0x1E225820u, 0x0000000080000000ul, 0x0000000000000000ul, 0x0000000080000000ul)] + [TestCase(0x1E225820u, 0x0000000080000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] + [TestCase(0x1E225820u, 0x0000000080000000ul, 0x000000003DCCCCCDul, 0x0000000080000000ul)] + [TestCase(0x1E225820u, 0x000000003DCCCCCDul, 0x000000003C9623B1ul, 0x000000003C9623B1ul)] + [TestCase(0x1E225820u, 0x000000008BA98D27ul, 0x0000000000000076ul, 0x000000008BA98D27ul)] + [TestCase(0x1E225820u, 0x00000000807FFFFFul, 0x000000007F7FFFFFul, 0x00000000807FFFFFul)] + [TestCase(0x1E225820u, 0x000000007F7FFFFFul, 0x00000000807FFFFFul, 0x00000000807FFFFFul)] + [TestCase(0x1E225820u, 0x000000007FC00000ul, 0x000000003F800000ul, 0x000000007FC00000ul)] + [TestCase(0x1E225820u, 0x000000003F800000ul, 0x000000007FC00000ul, 0x000000007FC00000ul)] + [TestCase(0x1E225820u, 0x000000007F800001ul, 0x000000007FC00042ul, 0x000000007FC00001ul, Ignore = "NaN test.")] + [TestCase(0x1E225820u, 0x000000007FC00042ul, 0x000000007F800001ul, 0x000000007FC00001ul, Ignore = "NaN test.")] + [TestCase(0x1E225820u, 0x000000007FC0000Aul, 0x000000007FC0000Bul, 0x000000007FC0000Aul, Ignore = "NaN test.")] + [TestCase(0x1E625820u, 0x0000000000000000ul, 0x8000000000000000ul, 0x8000000000000000ul)] + [TestCase(0x1E625820u, 0x8000000000000000ul, 0x0000000000000000ul, 0x8000000000000000ul)] + [TestCase(0x1E625820u, 0x8000000000000000ul, 0x8000000000000000ul, 0x8000000000000000ul)] + [TestCase(0x1E625820u, 0x8000000000000000ul, 0x3FF3333333333333ul, 0x8000000000000000ul)] + public void Fmin_S(uint Opcode, ulong A, ulong B, ulong Result) + { + // FMIN S0, S1, S2 + AThreadState ThreadState = SingleOpcode(Opcode, + V1: Sse.StaticCast(Sse2.SetVector128(0, A)), + V2: Sse.StaticCast(Sse2.SetVector128(0, B))); + Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast(ThreadState.V0), 0)); + } + [TestCase(0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x80000000u)] [TestCase(0x00000000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u)] [TestCase(0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u)] @@ -101,7 +153,7 @@ namespace Ryujinx.Tests.Cpu }); } - [Test, Description("fmul s6, s1, v0.s[2]")] + [Test, Description("FMUL S6, S1, V0.S[2]")] public void Fmul_Se([Random(10)] float A, [Random(10)] float B) { AThreadState ThreadState = SingleOpcode(0x5F809826, @@ -111,7 +163,15 @@ namespace Ryujinx.Tests.Cpu Assert.That(Sse41.Extract(ThreadState.V6, (byte)0), Is.EqualTo(A * B)); } - [Test, Description("frecpe v2.4s, v0.4s")] + [Test, Description("FRECPE D0, D1")] + public void Frecpe_S([Random(100)] double A) + { + AThreadState ThreadState = SingleOpcode(0x5EE1D820, V1: MakeVectorE0(A)); + + Assert.That(VectorExtractDouble(ThreadState.V0, 0), Is.EqualTo(1 / A)); + } + + [Test, Description("FRECPE V2.4S, V0.4S")] public void Frecpe_V([Random(100)] float A) { AThreadState ThreadState = SingleOpcode(0x4EA1D802, V0: Sse.SetAllVector128(A)); @@ -122,15 +182,17 @@ namespace Ryujinx.Tests.Cpu Assert.That(Sse41.Extract(ThreadState.V2, (byte)3), Is.EqualTo(1 / A)); } - [Test, Description("frecpe d0, d1")] - public void Frecpe_S([Random(100)] double A) + [Test, Description("FRECPS D0, D1, D2")] + public void Frecps_S([Random(10)] double A, [Random(10)] double B) { - AThreadState ThreadState = SingleOpcode(0x5EE1D820, V1: MakeVectorE0(A)); + AThreadState ThreadState = SingleOpcode(0x5E62FC20, + V1: MakeVectorE0(A), + V2: MakeVectorE0(B)); - Assert.That(VectorExtractDouble(ThreadState.V0, 0), Is.EqualTo(1 / A)); + Assert.That(VectorExtractDouble(ThreadState.V0, 0), Is.EqualTo(2 - (A * B))); } - [Test, Description("frecps v4.4s, v2.4s, v0.4s")] + [Test, Description("FRECPS V4.4S, V2.4S, V0.4S")] public void Frecps_V([Random(10)] float A, [Random(10)] float B) { AThreadState ThreadState = SingleOpcode(0x4E20FC44, @@ -143,16 +205,6 @@ namespace Ryujinx.Tests.Cpu Assert.That(Sse41.Extract(ThreadState.V4, (byte)3), Is.EqualTo(2 - (A * B))); } - [Test, Description("frecps d0, d1, d2")] - public void Frecps_S([Random(10)] double A, [Random(10)] double B) - { - AThreadState ThreadState = SingleOpcode(0x5E62FC20, - V1: MakeVectorE0(A), - V2: MakeVectorE0(B)); - - Assert.That(VectorExtractDouble(ThreadState.V0, 0), Is.EqualTo(2 - (A * B))); - } - [TestCase(0x3FE66666u, false, 0x40000000u)] [TestCase(0x3F99999Au, false, 0x3F800000u)] [TestCase(0x404CCCCDu, false, 0x40400000u)] diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdMove.cs b/Ryujinx.Tests/Cpu/CpuTestSimdMove.cs index e2766a16..49848820 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdMove.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdMove.cs @@ -9,7 +9,7 @@ namespace Ryujinx.Tests.Cpu { public class CpuTestSimdMove : CpuTest { - [Test, Description("trn1 v0.4s, v1.4s, v2.4s")] + [Test, Description("TRN1 V0.4S, V1.4S, V2.4S")] public void Trn1_V_4S([Random(2)] uint A0, [Random(2)] uint A1, [Random(2)] uint A2, [Random(2)] uint A3, [Random(2)] uint B0, [Random(2)] uint B1, [Random(2)] uint B2, [Random(2)] uint B3) { @@ -27,7 +27,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(Sse41.Extract(Sse.StaticCast(ThreadState.V0), (byte)3), Is.EqualTo(B2)); } - [Test, Description("trn1 v0.8b, v1.8b, v2.8b")] + [Test, Description("TRN1 V0.8B, V1.8B, V2.8B")] public void Trn1_V_8B([Random(2)] byte A0, [Random(1)] byte A1, [Random(2)] byte A2, [Random(1)] byte A3, [Random(2)] byte A4, [Random(1)] byte A5, [Random(2)] byte A6, [Random(1)] byte A7, [Random(2)] byte B0, [Random(1)] byte B1, [Random(2)] byte B2, [Random(1)] byte B3, @@ -49,7 +49,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(Sse41.Extract(Sse.StaticCast(ThreadState.V0), (byte)7), Is.EqualTo(B6)); } - [Test, Description("trn2 v0.4s, v1.4s, v2.4s")] + [Test, Description("TRN2 V0.4S, V1.4S, V2.4S")] public void Trn2_V_4S([Random(2)] uint A0, [Random(2)] uint A1, [Random(2)] uint A2, [Random(2)] uint A3, [Random(2)] uint B0, [Random(2)] uint B1, [Random(2)] uint B2, [Random(2)] uint B3) { @@ -65,7 +65,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(Sse41.Extract(Sse.StaticCast(ThreadState.V0), (byte)3), Is.EqualTo(B3)); } - [Test, Description("trn2 v0.8b, v1.8b, v2.8b")] + [Test, Description("TRN2 V0.8B, V1.8B, V2.8B")] public void Trn2_V_8B([Random(1)] byte A0, [Random(2)] byte A1, [Random(1)] byte A2, [Random(2)] byte A3, [Random(1)] byte A4, [Random(2)] byte A5, [Random(1)] byte A6, [Random(2)] byte A7, [Random(1)] byte B0, [Random(2)] byte B1, [Random(1)] byte B2, [Random(2)] byte B3, diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs b/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs index 88aebfbe..c05a862c 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Tests.Cpu using Tester; using Tester.Types; - [Category("SimdReg")] + [Category("SimdReg")/*, Ignore("Tested: first half of 2018.")*/] public sealed class CpuTestSimdReg : CpuTest { #if SimdReg @@ -514,6 +514,511 @@ namespace Ryujinx.Tests.Cpu }); } + [Test, Description("CMEQ , , ")] + public void Cmeq_S_D([ValueSource("_1D_")] [Random(1)] ulong A, + [ValueSource("_1D_")] [Random(1)] ulong B) + { + uint Opcode = 0x7EE28C20; // CMEQ D0, D1, D2 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmeq_Reg_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMEQ ., ., .")] + public void Cmeq_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [ValueSource("_8B4H2S_")] [Random(1)] ulong B, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x2E228C20; // CMEQ V0.8B, V1.8B, V2.8B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmeq_Reg_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.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMEQ ., ., .")] + public void Cmeq_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x6E228C20; // CMEQ V0.16B, V1.16B, V2.16B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + Vector128 V2 = MakeVectorE0E1(B0, B1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + AArch64.Vpart(2, 0, new Bits(B0)); + AArch64.Vpart(2, 1, new Bits(B1)); + SimdFp.Cmeq_Reg_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())); + }); + } + + [Test, Description("CMGE , , ")] + public void Cmge_S_D([ValueSource("_1D_")] [Random(1)] ulong A, + [ValueSource("_1D_")] [Random(1)] ulong B) + { + uint Opcode = 0x5EE23C20; // CMGE D0, D1, D2 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmge_Reg_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMGE ., ., .")] + public void Cmge_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [ValueSource("_8B4H2S_")] [Random(1)] ulong B, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x0E223C20; // CMGE V0.8B, V1.8B, V2.8B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmge_Reg_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.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMGE ., ., .")] + public void Cmge_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x4E223C20; // CMGE V0.16B, V1.16B, V2.16B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + Vector128 V2 = MakeVectorE0E1(B0, B1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + AArch64.Vpart(2, 0, new Bits(B0)); + AArch64.Vpart(2, 1, new Bits(B1)); + SimdFp.Cmge_Reg_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())); + }); + } + + [Test, Description("CMGT , , ")] + public void Cmgt_S_D([ValueSource("_1D_")] [Random(1)] ulong A, + [ValueSource("_1D_")] [Random(1)] ulong B) + { + uint Opcode = 0x5EE23420; // CMGT D0, D1, D2 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmgt_Reg_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMGT ., ., .")] + public void Cmgt_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [ValueSource("_8B4H2S_")] [Random(1)] ulong B, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x0E223420; // CMGT V0.8B, V1.8B, V2.8B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmgt_Reg_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.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMGT ., ., .")] + public void Cmgt_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x4E223420; // CMGT V0.16B, V1.16B, V2.16B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + Vector128 V2 = MakeVectorE0E1(B0, B1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + AArch64.Vpart(2, 0, new Bits(B0)); + AArch64.Vpart(2, 1, new Bits(B1)); + SimdFp.Cmgt_Reg_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())); + }); + } + + [Test, Description("CMHI , , ")] + public void Cmhi_S_D([ValueSource("_1D_")] [Random(1)] ulong A, + [ValueSource("_1D_")] [Random(1)] ulong B) + { + uint Opcode = 0x7EE23420; // CMHI D0, D1, D2 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmhi_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMHI ., ., .")] + public void Cmhi_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [ValueSource("_8B4H2S_")] [Random(1)] ulong B, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x2E223420; // CMHI V0.8B, V1.8B, V2.8B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmhi_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.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMHI ., ., .")] + public void Cmhi_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x6E223420; // CMHI V0.16B, V1.16B, V2.16B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + Vector128 V2 = MakeVectorE0E1(B0, B1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + AArch64.Vpart(2, 0, new Bits(B0)); + AArch64.Vpart(2, 1, new Bits(B1)); + SimdFp.Cmhi_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())); + }); + } + + [Test, Description("CMHS , , ")] + public void Cmhs_S_D([ValueSource("_1D_")] [Random(1)] ulong A, + [ValueSource("_1D_")] [Random(1)] ulong B) + { + uint Opcode = 0x7EE23C20; // CMHS D0, D1, D2 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmhs_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMHS ., ., .")] + public void Cmhs_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [ValueSource("_8B4H2S_")] [Random(1)] ulong B, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x2E223C20; // CMHS V0.8B, V1.8B, V2.8B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmhs_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.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMHS ., ., .")] + public void Cmhs_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x6E223C20; // CMHS V0.16B, V1.16B, V2.16B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + Vector128 V2 = MakeVectorE0E1(B0, B1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + AArch64.Vpart(2, 0, new Bits(B0)); + AArch64.Vpart(2, 1, new Bits(B1)); + SimdFp.Cmhs_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())); + }); + } + + [Test, Description("CMTST , , ")] + public void Cmtst_S_D([ValueSource("_1D_")] [Random(1)] ulong A, + [ValueSource("_1D_")] [Random(1)] ulong B) + { + uint Opcode = 0x5EE28C20; // CMTST D0, D1, D2 + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmtst_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Description("CMTST ., ., .")] + public void Cmtst_V_8B_4H_2S([ValueSource("_8B4H2S_")] [Random(1)] ulong A, + [ValueSource("_8B4H2S_")] [Random(1)] ulong B, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + uint Opcode = 0x0E228C20; // CMTST V0.8B, V1.8B, V2.8B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Cmtst_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.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("CMTST ., ., .")] + public void Cmtst_V_16B_8H_4S_2D([ValueSource("_8B4H2S1D_")] [Random(1)] ulong A0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong A1, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B0, + [ValueSource("_8B4H2S1D_")] [Random(1)] ulong B1, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint size) // <16B, 8H, 4S, 2D> + { + uint Opcode = 0x4E228C20; // CMTST V0.16B, V1.16B, V2.16B + Opcode |= ((size & 3) << 22); + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + Vector128 V2 = MakeVectorE0E1(B0, B1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + AArch64.Vpart(2, 0, new Bits(B0)); + AArch64.Vpart(2, 1, new Bits(B1)); + SimdFp.Cmtst_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())); + }); + } + + [Test, Description("EOR ., ., .")] + public void Eor_V_8B([ValueSource("_8B_")] [Random(1)] ulong A, + [ValueSource("_8B_")] [Random(1)] ulong B) + { + uint Opcode = 0x2E221C20; // EOR V0.8B, V1.8B, V2.8B + Bits Op = new Bits(Opcode); + + Vector128 V0 = MakeVectorE1(TestContext.CurrentContext.Random.NextULong()); + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1, V2: V2); + + AArch64.V(1, new Bits(A)); + AArch64.V(2, new Bits(B)); + SimdFp.Eor_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]); + + Assert.Multiple(() => + { + Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(AArch64.V(64, 0).ToUInt64())); + Assert.That(GetVectorE1(ThreadState.V0), Is.Zero); + }); + } + + [Test, Pairwise, Description("EOR ., ., .")] + public void Eor_V_16B([ValueSource("_8B_")] [Random(1)] ulong A0, + [ValueSource("_8B_")] [Random(1)] ulong A1, + [ValueSource("_8B_")] [Random(1)] ulong B0, + [ValueSource("_8B_")] [Random(1)] ulong B1) + { + uint Opcode = 0x6E221C20; // EOR V0.16B, V1.16B, V2.16B + Bits Op = new Bits(Opcode); + + Vector128 V1 = MakeVectorE0E1(A0, A1); + Vector128 V2 = MakeVectorE0E1(B0, B1); + AThreadState ThreadState = SingleOpcode(Opcode, V1: V1, V2: V2); + + AArch64.Vpart(1, 0, new Bits(A0)); + AArch64.Vpart(1, 1, new Bits(A1)); + AArch64.Vpart(2, 0, new Bits(B0)); + AArch64.Vpart(2, 1, new Bits(B1)); + SimdFp.Eor_V(Op[30], 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())); + }); + } + [Test, Description("ORN ., ., .")] public void Orn_V_8B([ValueSource("_8B_")] [Random(1)] ulong A, [ValueSource("_8B_")] [Random(1)] ulong B) diff --git a/Ryujinx.Tests/Cpu/Tester/Instructions.cs b/Ryujinx.Tests/Cpu/Tester/Instructions.cs index efea80bb..aa62ddcc 100644 --- a/Ryujinx.Tests/Cpu/Tester/Instructions.cs +++ b/Ryujinx.Tests/Cpu/Tester/Instructions.cs @@ -1,7 +1,7 @@ // https://github.com/LDj3SNuD/ARM_v8-A_AArch64_Instructions_Tester/blob/master/Tester/Instructions.cs -// https://meriac.github.io/archex/A64_v83A_ISA/index.xml -// https://meriac.github.io/archex/A64_v83A_ISA/fpsimdindex.xml +// https://developer.arm.com/products/architecture/a-profile/exploration-tools +// ..\A64_v83A_ISA_xml_00bet6.1\ISA_v83A_A64_xml_00bet6.1_OPT\xhtml\ using System.Numerics; @@ -12,10 +12,11 @@ namespace Ryujinx.Tests.Cpu.Tester using static AArch64; using static Shared; + // index.html internal static class Base { #region "Alu" - // https://meriac.github.io/archex/A64_v83A_ISA/cls_int.xml + // cls_int.html public static void Cls(bool sf, Bits Rn, Bits Rd) { /* Decode */ @@ -32,7 +33,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(datasize - 1, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/clz_int.xml + // clz_int.html public static void Clz(bool sf, Bits Rn, Bits Rd) { /* Decode */ @@ -49,7 +50,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(datasize - 1, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/rbit_int.xml + // rbit_int.html public static void Rbit(bool sf, Bits Rn, Bits Rd) { /* Decode */ @@ -70,7 +71,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/rev16_int.xml + // rev16_int.html public static void Rev16(bool sf, Bits Rn, Bits Rd) { /* Bits opc = "01"; */ @@ -108,8 +109,8 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/rev32_int.xml - // (https://meriac.github.io/archex/A64_v83A_ISA/rev.xml) + // rev32_int.html + // (rev.html) public static void Rev32(bool sf, Bits Rn, Bits Rd) { /* Bits opc = "10"; */ @@ -147,8 +148,8 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/rev64_rev.xml - // (https://meriac.github.io/archex/A64_v83A_ISA/rev.xml) + // rev64_rev.html + // (rev.html) public static void Rev64(Bits Rn, Bits Rd) { /* Bits opc = "11"; */ @@ -186,7 +187,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "AluImm" - // https://meriac.github.io/archex/A64_v83A_ISA/add_addsub_imm.xml + // add_addsub_imm.html public static void Add_Imm(bool sf, Bits shift, Bits imm12, Bits Rn, Bits Rd) { /* Decode */ @@ -225,7 +226,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // https://meriac.github.io/archex/A64_v83A_ISA/adds_addsub_imm.xml + // adds_addsub_imm.html public static void Adds_Imm(bool sf, Bits shift, Bits imm12, Bits Rn, Bits Rd) { /* Decode */ @@ -260,7 +261,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/and_log_imm.xml + // and_log_imm.html public static void And_Imm(bool sf, bool N, Bits immr, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -290,7 +291,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // https://meriac.github.io/archex/A64_v83A_ISA/ands_log_imm.xml + // ands_log_imm.html public static void Ands_Imm(bool sf, bool N, Bits immr, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -315,7 +316,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/eor_log_imm.xml + // eor_log_imm.html public static void Eor_Imm(bool sf, bool N, Bits immr, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -345,7 +346,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // https://meriac.github.io/archex/A64_v83A_ISA/orr_log_imm.xml + // orr_log_imm.html public static void Orr_Imm(bool sf, bool N, Bits immr, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -375,7 +376,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // https://meriac.github.io/archex/A64_v83A_ISA/sub_addsub_imm.xml + // sub_addsub_imm.html public static void Sub_Imm(bool sf, Bits shift, Bits imm12, Bits Rn, Bits Rd) { /* Decode */ @@ -415,7 +416,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // https://meriac.github.io/archex/A64_v83A_ISA/subs_addsub_imm.xml + // subs_addsub_imm.html public static void Subs_Imm(bool sf, Bits shift, Bits imm12, Bits Rn, Bits Rd) { /* Decode */ @@ -453,7 +454,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "AluRs" - // https://meriac.github.io/archex/A64_v83A_ISA/adc.xml + // adc.html public static void Adc(bool sf, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -473,7 +474,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/adcs.xml + // adcs.html public static void Adcs(bool sf, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -496,7 +497,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/add_addsub_shift.xml + // add_addsub_shift.html public static void Add_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -522,7 +523,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/adds_addsub_shift.xml + // adds_addsub_shift.html public static void Adds_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -551,7 +552,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/and_log_shift.xml + // and_log_shift.html public static void And_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -575,7 +576,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/ands_log_shift.xml + // ands_log_shift.html public static void Ands_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -601,10 +602,10 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/asrv.xml + // asrv.html public static void Asrv(bool sf, Bits Rm, Bits Rn, Bits Rd) { - Bits op2 = "10"; + /*readonly */Bits op2 = "10"; /* Decode */ int d = (int)UInt(Rd); @@ -623,7 +624,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/bic_log_shift.xml + // bic_log_shift.html public static void Bic(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -649,7 +650,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/bics.xml + // bics.html public static void Bics(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -677,7 +678,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/crc32.xml + // crc32.html public static void Crc32(bool sf, Bits Rm, Bits sz, Bits Rn, Bits Rd) { /* Decode */ @@ -704,7 +705,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, BitReverse(Poly32Mod2(EOR(tempacc, tempval), poly))); } - // https://meriac.github.io/archex/A64_v83A_ISA/crc32c.xml + // crc32c.html public static void Crc32c(bool sf, Bits Rm, Bits sz, Bits Rn, Bits Rd) { /* Decode */ @@ -731,7 +732,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, BitReverse(Poly32Mod2(EOR(tempacc, tempval), poly))); } - // https://meriac.github.io/archex/A64_v83A_ISA/eon.xml + // eon.html public static void Eon(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -757,7 +758,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/eor_log_shift.xml + // eor_log_shift.html public static void Eor_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -781,7 +782,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/extr.xml + // extr.html public static void Extr(bool sf, bool N, Bits Rm, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -806,10 +807,10 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/lslv.xml + // lslv.html public static void Lslv(bool sf, Bits Rm, Bits Rn, Bits Rd) { - Bits op2 = "00"; + /*readonly */Bits op2 = "00"; /* Decode */ int d = (int)UInt(Rd); @@ -828,10 +829,10 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/lsrv.xml + // lsrv.html public static void Lsrv(bool sf, Bits Rm, Bits Rn, Bits Rd) { - Bits op2 = "01"; + /*readonly */Bits op2 = "01"; /* Decode */ int d = (int)UInt(Rd); @@ -850,7 +851,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/orn_log_shift.xml + // orn_log_shift.html public static void Orn(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -876,7 +877,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/orr_log_shift.xml + // orr_log_shift.html public static void Orr_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -900,10 +901,10 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/rorv.xml + // rorv.html public static void Rorv(bool sf, Bits Rm, Bits Rn, Bits Rd) { - Bits op2 = "11"; + /*readonly */Bits op2 = "11"; /* Decode */ int d = (int)UInt(Rd); @@ -922,7 +923,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sbc.xml + // sbc.html public static void Sbc(bool sf, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -944,7 +945,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sbcs.xml + // sbcs.html public static void Sbcs(bool sf, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -969,7 +970,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sdiv.xml + // sdiv.html public static void Sdiv(bool sf, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -996,7 +997,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(datasize - 1, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/sub_addsub_shift.xml + // sub_addsub_shift.html public static void Sub_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -1024,7 +1025,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/subs_addsub_shift.xml + // subs_addsub_shift.html public static void Subs_Rs(bool sf, Bits shift, Bits Rm, Bits imm6, Bits Rn, Bits Rd) { /* Decode */ @@ -1055,7 +1056,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/udiv.xml + // udiv.html public static void Udiv(bool sf, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -1084,7 +1085,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "AluRx" - // https://meriac.github.io/archex/A64_v83A_ISA/add_addsub_ext.xml + // add_addsub_ext.html public static void Add_Rx(bool sf, Bits Rm, Bits option, Bits imm3, Bits Rn, Bits Rd) { /* Decode */ @@ -1116,7 +1117,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // https://meriac.github.io/archex/A64_v83A_ISA/adds_addsub_ext.xml + // adds_addsub_ext.html public static void Adds_Rx(bool sf, Bits Rm, Bits option, Bits imm3, Bits Rn, Bits Rd) { /* Decode */ @@ -1144,7 +1145,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sub_addsub_ext.xml + // sub_addsub_ext.html public static void Sub_Rx(bool sf, Bits Rm, Bits option, Bits imm3, Bits Rn, Bits Rd) { /* Decode */ @@ -1178,7 +1179,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // https://meriac.github.io/archex/A64_v83A_ISA/subs_addsub_ext.xml + // subs_addsub_ext.html public static void Subs_Rx(bool sf, Bits Rm, Bits option, Bits imm3, Bits Rn, Bits Rd) { /* Decode */ @@ -1210,7 +1211,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "Bfm" - // https://meriac.github.io/archex/A64_v83A_ISA/bfm.xml + // bfm.html public static void Bfm(bool sf, bool N, Bits immr, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -1240,7 +1241,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, OR(AND(dst, NOT(tmask)), AND(bot, tmask))); } - // https://meriac.github.io/archex/A64_v83A_ISA/sbfm.xml + // sbfm.html public static void Sbfm(bool sf, bool N, Bits immr, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -1274,7 +1275,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, OR(AND(top, NOT(tmask)), AND(bot, tmask))); } - // https://meriac.github.io/archex/A64_v83A_ISA/ubfm.xml + // ubfm.html public static void Ubfm(bool sf, bool N, Bits immr, Bits imms, Bits Rn, Bits Rd) { /* Decode */ @@ -1305,7 +1306,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "CcmpImm" - // https://meriac.github.io/archex/A64_v83A_ISA/ccmn_imm.xml + // ccmn_imm.html public static void Ccmn_Imm(bool sf, Bits imm5, Bits cond, Bits Rn, Bits nzcv) { /* Decode */ @@ -1327,7 +1328,7 @@ namespace Ryujinx.Tests.Cpu.Tester PSTATE.NZCV(flags); } - // https://meriac.github.io/archex/A64_v83A_ISA/ccmp_imm.xml + // ccmp_imm.html public static void Ccmp_Imm(bool sf, Bits imm5, Bits cond, Bits Rn, Bits nzcv) { /* Decode */ @@ -1353,7 +1354,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "CcmpReg" - // https://meriac.github.io/archex/A64_v83A_ISA/ccmn_reg.xml + // ccmn_reg.html public static void Ccmn_Reg(bool sf, Bits Rm, Bits cond, Bits Rn, Bits nzcv) { /* Decode */ @@ -1376,7 +1377,7 @@ namespace Ryujinx.Tests.Cpu.Tester PSTATE.NZCV(flags); } - // https://meriac.github.io/archex/A64_v83A_ISA/ccmp_reg.xml + // ccmp_reg.html public static void Ccmp_Reg(bool sf, Bits Rm, Bits cond, Bits Rn, Bits nzcv) { /* Decode */ @@ -1402,7 +1403,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "Csel" - // https://meriac.github.io/archex/A64_v83A_ISA/csel.xml + // csel.html public static void Csel(bool sf, Bits Rm, Bits cond, Bits Rn, Bits Rd) { /* Decode */ @@ -1429,7 +1430,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/csinc.xml + // csinc.html public static void Csinc(bool sf, Bits Rm, Bits cond, Bits Rn, Bits Rd) { /* Decode */ @@ -1456,7 +1457,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/csinv.xml + // csinv.html public static void Csinv(bool sf, Bits Rm, Bits cond, Bits Rn, Bits Rd) { /* Decode */ @@ -1483,7 +1484,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/csneg.xml + // csneg.html public static void Csneg(bool sf, Bits Rm, Bits cond, Bits Rn, Bits Rd) { /* Decode */ @@ -1513,7 +1514,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "Mov" - // https://meriac.github.io/archex/A64_v83A_ISA/movk.xml + // movk.html public static void Movk(bool sf, Bits hw, Bits imm16, Bits Rd) { /* Decode */ @@ -1533,7 +1534,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/movn.xml + // movn.html public static void Movn(bool sf, Bits hw, Bits imm16, Bits Rd) { /* Decode */ @@ -1554,7 +1555,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/movz.xml + // movz.html public static void Movz(bool sf, Bits hw, Bits imm16, Bits Rd) { /* Decode */ @@ -1576,7 +1577,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "Mul" - // https://meriac.github.io/archex/A64_v83A_ISA/madd.xml + // madd.html public static void Madd(bool sf, Bits Rm, Bits Ra, Bits Rn, Bits Rd) { /* Decode */ @@ -1597,7 +1598,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(datasize - 1, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/msub.xml + // msub.html public static void Msub(bool sf, Bits Rm, Bits Ra, Bits Rn, Bits Rd) { /* Decode */ @@ -1618,7 +1619,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(datasize - 1, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/smaddl.xml + // smaddl.html public static void Smaddl(Bits Rm, Bits Ra, Bits Rn, Bits Rd) { /* Decode */ @@ -1637,7 +1638,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(63, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/umaddl.xml + // umaddl.html public static void Umaddl(Bits Rm, Bits Ra, Bits Rn, Bits Rd) { /* Decode */ @@ -1656,7 +1657,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(63, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/smsubl.xml + // smsubl.html public static void Smsubl(Bits Rm, Bits Ra, Bits Rn, Bits Rd) { /* Decode */ @@ -1675,7 +1676,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(63, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/umsubl.xml + // umsubl.html public static void Umsubl(Bits Rm, Bits Ra, Bits Rn, Bits Rd) { /* Decode */ @@ -1694,7 +1695,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(63, 0)); } - // https://meriac.github.io/archex/A64_v83A_ISA/smulh.xml + // smulh.html public static void Smulh(Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -1711,7 +1712,7 @@ namespace Ryujinx.Tests.Cpu.Tester X(d, result.SubBigInteger(127, 64)); } - // https://meriac.github.io/archex/A64_v83A_ISA/umulh.xml + // umulh.html public static void Umulh(Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -1730,13 +1731,14 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion } + // fpsimdindex.html internal static class SimdFp { #region "Simd" - // https://meriac.github.io/archex/A64_v83A_ISA/abs_advsimd.xml#ABS_asisdmisc_R + // abs_advsimd.html#ABS_asisdmisc_R public static void Abs_S(Bits size, Bits Rn, Bits Rd) { - bool U = false; + const bool U = false; /* Decode Scalar */ int d = (int)UInt(Rd); @@ -1777,10 +1779,10 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/abs_advsimd.xml#ABS_asimdmisc_R + // abs_advsimd.html#ABS_asimdmisc_R public static void Abs_V(bool Q, Bits size, Bits Rn, Bits Rd) { - bool U = false; + const bool U = false; /* Decode Vector */ int d = (int)UInt(Rd); @@ -1821,7 +1823,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/addp_advsimd_pair.xml + // addp_advsimd_pair.html public static void Addp_S(Bits size, Bits Rn, Bits Rd) { /* Decode Scalar */ @@ -1844,7 +1846,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, Reduce(op, operand, esize)); } - // https://meriac.github.io/archex/A64_v83A_ISA/addv_advsimd.xml + // addv_advsimd.html public static void Addv_V(bool Q, Bits size, Bits Rn, Bits Rd) { /* Decode */ @@ -1868,10 +1870,10 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, Reduce(op, operand, esize)); } - // https://meriac.github.io/archex/A64_v83A_ISA/cls_advsimd.xml + // cls_advsimd.html public static void Cls_V(bool Q, Bits size, Bits Rn, Bits Rd) { - bool U = false; + const bool U = false; /* Decode */ int d = (int)UInt(Rd); @@ -1910,10 +1912,10 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/clz_advsimd.xml + // clz_advsimd.html public static void Clz_V(bool Q, Bits size, Bits Rn, Bits Rd) { - bool U = true; + const bool U = true; /* Decode */ int d = (int)UInt(Rd); @@ -1952,10 +1954,710 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/neg_advsimd.xml#NEG_asisdmisc_R + // cmeq_advsimd_zero.html#CMEQ_asisdmisc_Z + public static void Cmeq_Zero_S(Bits size, Bits Rn, Bits Rd) + { + const bool U = false; + const bool op = true; + + /* 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 elements = 1; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmeq_advsimd_zero.html#CMEQ_asimdmisc_Z + public static void Cmeq_Zero_V(bool Q, Bits size, Bits Rn, Bits Rd) + { + const bool U = false; + const bool op = 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; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmge_advsimd_zero.html#CMGE_asisdmisc_Z + public static void Cmge_Zero_S(Bits size, Bits Rn, Bits Rd) + { + const bool U = true; + const bool op = false; + + /* 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 elements = 1; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmge_advsimd_zero.html#CMGE_asimdmisc_Z + public static void Cmge_Zero_V(bool Q, Bits size, Bits Rn, Bits Rd) + { + const bool U = true; + const bool op = 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; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmgt_advsimd_zero.html#CMGT_asisdmisc_Z + public static void Cmgt_Zero_S(Bits size, Bits Rn, Bits Rd) + { + const bool U = false; + const bool op = false; + + /* 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 elements = 1; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmgt_advsimd_zero.html#CMGT_asimdmisc_Z + public static void Cmgt_Zero_V(bool Q, Bits size, Bits Rn, Bits Rd) + { + const bool U = false; + const bool op = 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; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmle_advsimd.html#CMLE_asisdmisc_Z + public static void Cmle_S(Bits size, Bits Rn, Bits Rd) + { + const bool U = true; + const bool op = true; + + /* 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 elements = 1; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmle_advsimd.html#CMLE_asimdmisc_Z + public static void Cmle_V(bool Q, Bits size, Bits Rn, Bits Rd) + { + const bool U = true; + const bool op = 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; + + CompareOp comparison; + + switch (Bits.Concat(op, U)) + { + default: + case Bits bits when bits == "00": + comparison = CompareOp.CompareOp_GT; + break; + case Bits bits when bits == "01": + comparison = CompareOp.CompareOp_GE; + break; + case Bits bits when bits == "10": + comparison = CompareOp.CompareOp_EQ; + break; + case Bits bits when bits == "11": + comparison = CompareOp.CompareOp_LE; + break; + } + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmlt_advsimd.html#CMLT_asisdmisc_Z + public static void Cmlt_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 elements = 1; + + CompareOp comparison = CompareOp.CompareOp_LT; + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmlt_advsimd.html#CMLT_asimdmisc_Z + public static void Cmlt_V(bool Q, Bits size, Bits Rn, Bits Rd) + { + /* 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; + + CompareOp comparison = CompareOp.CompareOp_LT; + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + BigInteger element; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element = SInt(Elem(operand, e, esize)); + + switch (comparison) + { + default: + case CompareOp.CompareOp_GT: + test_passed = (element > (BigInteger)0); + break; + case CompareOp.CompareOp_GE: + test_passed = (element >= (BigInteger)0); + break; + case CompareOp.CompareOp_EQ: + test_passed = (element == (BigInteger)0); + break; + case CompareOp.CompareOp_LE: + test_passed = (element <= (BigInteger)0); + break; + case CompareOp.CompareOp_LT: + test_passed = (element < (BigInteger)0); + break; + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // neg_advsimd.html#NEG_asisdmisc_R public static void Neg_S(Bits size, Bits Rn, Bits Rd) { - bool U = true; + const bool U = true; /* Decode Scalar */ int d = (int)UInt(Rd); @@ -1996,10 +2698,10 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/neg_advsimd.xml#NEG_asimdmisc_R + // neg_advsimd.html#NEG_asimdmisc_R public static void Neg_V(bool Q, Bits size, Bits Rn, Bits Rd) { - bool U = true; + const bool U = true; /* Decode Vector */ int d = (int)UInt(Rd); @@ -2040,10 +2742,38 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sqxtn_advsimd.xml#SQXTN_asisdmisc_N + // not_advsimd.html + public static void Not_V(bool Q, Bits Rn, Bits Rd) + { + /* Decode */ + int d = (int)UInt(Rd); + int n = (int)UInt(Rn); + + int esize = 8; + int datasize = (Q ? 128 : 64); + int elements = datasize / 8; + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand = V(datasize, n); + Bits element; + + for (int e = 0; e <= elements - 1; e++) + { + element = Elem(operand, e, esize); + + Elem(result, e, esize, NOT(element)); + } + + V(d, result); + } + + // sqxtn_advsimd.html#SQXTN_asisdmisc_N public static void Sqxtn_S(Bits size, Bits Rn, Bits Rd) { - bool U = false; + const bool U = false; /* Decode Scalar */ int d = (int)UInt(Rd); @@ -2077,17 +2807,17 @@ namespace Ryujinx.Tests.Cpu.Tester if (sat) { /* FPSR.QC = '1'; */ - FPSR[27] = true; // FIXME: Temporary solution. + FPSR[27] = true; // TODO: Add named fields. } } Vpart(d, part, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sqxtn_advsimd.xml#SQXTN_asimdmisc_N + // sqxtn_advsimd.html#SQXTN_asimdmisc_N public static void Sqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd) { - bool U = false; + const bool U = false; /* Decode Vector */ int d = (int)UInt(Rd); @@ -2121,17 +2851,17 @@ namespace Ryujinx.Tests.Cpu.Tester if (sat) { /* FPSR.QC = '1'; */ - FPSR[27] = true; // FIXME: Temporary solution. + FPSR[27] = true; // TODO: Add named fields. } } Vpart(d, part, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/uqxtn_advsimd.xml#UQXTN_asisdmisc_N + // uqxtn_advsimd.html#UQXTN_asisdmisc_N public static void Uqxtn_S(Bits size, Bits Rn, Bits Rd) { - bool U = true; + const bool U = true; /* Decode Scalar */ int d = (int)UInt(Rd); @@ -2165,17 +2895,17 @@ namespace Ryujinx.Tests.Cpu.Tester if (sat) { /* FPSR.QC = '1'; */ - FPSR[27] = true; // FIXME: Temporary solution. + FPSR[27] = true; // TODO: Add named fields. } } Vpart(d, part, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/uqxtn_advsimd.xml#UQXTN_asimdmisc_N + // uqxtn_advsimd.html#UQXTN_asimdmisc_N public static void Uqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd) { - bool U = true; + const bool U = true; /* Decode Vector */ int d = (int)UInt(Rd); @@ -2209,7 +2939,7 @@ namespace Ryujinx.Tests.Cpu.Tester if (sat) { /* FPSR.QC = '1'; */ - FPSR[27] = true; // FIXME: Temporary solution. + FPSR[27] = true; // TODO: Add named fields. } } @@ -2218,10 +2948,10 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "SimdReg" - // https://meriac.github.io/archex/A64_v83A_ISA/add_advsimd.xml#ADD_asisdsame_only + // add_advsimd.html#ADD_asisdsame_only public static void Add_S(Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = false; + const bool U = false; /* Decode Scalar */ int d = (int)UInt(Rd); @@ -2263,10 +2993,10 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/add_advsimd.xml#ADD_asimdsame_only + // add_advsimd.html#ADD_asimdsame_only public static void Add_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = false; + const bool U = false; /* Decode Vector */ int d = (int)UInt(Rd); @@ -2308,11 +3038,11 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/addhn_advsimd.xml + // addhn_advsimd.html public static void Addhn_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = false; - bool o1 = false; + const bool U = false; + const bool o1 = false; /* Decode */ int d = (int)UInt(Rd); @@ -2362,7 +3092,7 @@ namespace Ryujinx.Tests.Cpu.Tester Vpart(d, part, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/addp_advsimd_vec.xml + // addp_advsimd_vec.html public static void Addp_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) { /* Decode Vector */ @@ -2397,7 +3127,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/and_advsimd.xml + // and_advsimd.html public static void And_V(bool Q, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -2418,7 +3148,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/bic_advsimd_reg.xml + // bic_advsimd_reg.html public static void Bic_V(bool Q, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -2441,7 +3171,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/bif_advsimd.xml + // bif_advsimd.html public static void Bif_V(bool Q, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -2464,7 +3194,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, EOR(operand1, AND(EOR(operand1, operand4), operand3))); } - // https://meriac.github.io/archex/A64_v83A_ISA/bit_advsimd.xml + // bit_advsimd.html public static void Bit_V(bool Q, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -2487,7 +3217,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, EOR(operand1, AND(EOR(operand1, operand4), operand3))); } - // https://meriac.github.io/archex/A64_v83A_ISA/bsl_advsimd.xml + // bsl_advsimd.html public static void Bsl_V(bool Q, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -2510,7 +3240,578 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, EOR(operand1, AND(EOR(operand1, operand4), operand3))); } - // https://meriac.github.io/archex/A64_v83A_ISA/orn_advsimd.xml + // cmeq_advsimd_reg.html#CMEQ_asisdsame_only + public static void Cmeq_Reg_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); + + /* if size != '11' then ReservedValue(); */ + + int esize = 8 << (int)UInt(size); + int datasize = esize; + int elements = 1; + + bool and_test = (U == false); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + Bits element1; + Bits element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Elem(operand1, e, esize); + element2 = Elem(operand2, e, esize); + + if (and_test) + { + test_passed = !IsZero(AND(element1, element2)); + } + else + { + test_passed = (element1 == element2); + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmeq_advsimd_reg.html#CMEQ_asimdsame_only + public static void Cmeq_Reg_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 and_test = (U == false); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + Bits element1; + Bits element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Elem(operand1, e, esize); + element2 = Elem(operand2, e, esize); + + if (and_test) + { + test_passed = !IsZero(AND(element1, element2)); + } + else + { + test_passed = (element1 == element2); + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmge_advsimd_reg.html#CMGE_asisdsame_only + public static void Cmge_Reg_S(Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = false; + const bool eq = true; + + /* 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 = esize; + int elements = 1; + + bool unsigned = (U == true); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmge_advsimd_reg.html#CMGE_asimdsame_only + public static void Cmge_Reg_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = false; + const bool eq = 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); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmgt_advsimd_reg.html#CMGT_asisdsame_only + public static void Cmgt_Reg_S(Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = false; + const bool eq = false; + + /* 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 = esize; + int elements = 1; + + bool unsigned = (U == true); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmgt_advsimd_reg.html#CMGT_asimdsame_only + public static void Cmgt_Reg_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = false; + const bool eq = 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); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmhi_advsimd.html#CMHI_asisdsame_only + public static void Cmhi_S(Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = true; + const bool eq = false; + + /* 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 = esize; + int elements = 1; + + bool unsigned = (U == true); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmhi_advsimd.html#CMHI_asimdsame_only + public static void Cmhi_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = true; + const bool eq = 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); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmhs_advsimd.html#CMHS_asisdsame_only + public static void Cmhs_S(Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = true; + const bool eq = true; + + /* 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 = esize; + int elements = 1; + + bool unsigned = (U == true); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmhs_advsimd.html#CMHS_asimdsame_only + public static void Cmhs_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) + { + const bool U = true; + const bool eq = 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); + bool cmp_eq = (eq == true); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + BigInteger element1; + BigInteger element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Int(Elem(operand1, e, esize), unsigned); + element2 = Int(Elem(operand2, e, esize), unsigned); + + test_passed = (cmp_eq ? element1 >= element2 : element1 > element2); + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmtst_advsimd.html#CMTST_asisdsame_only + public static void Cmtst_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); + + /* if size != '11' then ReservedValue(); */ + + int esize = 8 << (int)UInt(size); + int datasize = esize; + int elements = 1; + + bool and_test = (U == false); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + Bits element1; + Bits element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Elem(operand1, e, esize); + element2 = Elem(operand2, e, esize); + + if (and_test) + { + test_passed = !IsZero(AND(element1, element2)); + } + else + { + test_passed = (element1 == element2); + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // cmtst_advsimd.html#CMTST_asimdsame_only + public static void Cmtst_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 and_test = (U == false); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits result = new Bits(datasize); + Bits operand1 = V(datasize, n); + Bits operand2 = V(datasize, m); + Bits element1; + Bits element2; + + bool test_passed; + + for (int e = 0; e <= elements - 1; e++) + { + element1 = Elem(operand1, e, esize); + element2 = Elem(operand2, e, esize); + + if (and_test) + { + test_passed = !IsZero(AND(element1, element2)); + } + else + { + test_passed = (element1 == element2); + } + + Elem(result, e, esize, test_passed ? Ones(esize) : Zeros(esize)); + } + + V(d, result); + } + + // eor_advsimd.html + public static void Eor_V(bool Q, Bits Rm, Bits Rn, Bits Rd) + { + /* Decode */ + int d = (int)UInt(Rd); + int n = (int)UInt(Rn); + int m = (int)UInt(Rm); + + int datasize = (Q ? 128 : 64); + + /* Operation */ + /* CheckFPAdvSIMDEnabled64(); */ + + Bits operand1 = V(datasize, m); + Bits operand2 = Zeros(datasize); + Bits operand3 = Ones(datasize); + Bits operand4 = V(datasize, n); + + Bits result = EOR(operand1, AND(EOR(operand2, operand4), operand3)); + + V(d, result); + } + + // orn_advsimd.html public static void Orn_V(bool Q, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -2533,7 +3834,7 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/orr_advsimd_reg.xml + // orr_advsimd_reg.html public static void Orr_V(bool Q, Bits Rm, Bits Rn, Bits Rd) { /* Decode */ @@ -2554,11 +3855,11 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/raddhn_advsimd.xml + // raddhn_advsimd.html public static void Raddhn_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = true; - bool o1 = false; + const bool U = true; + const bool o1 = false; /* Decode */ int d = (int)UInt(Rd); @@ -2608,11 +3909,11 @@ namespace Ryujinx.Tests.Cpu.Tester Vpart(d, part, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/rsubhn_advsimd.xml + // rsubhn_advsimd.html public static void Rsubhn_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = true; - bool o1 = true; + const bool U = true; + const bool o1 = true; /* Decode */ int d = (int)UInt(Rd); @@ -2662,10 +3963,10 @@ namespace Ryujinx.Tests.Cpu.Tester Vpart(d, part, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sub_advsimd.xml#SUB_asisdsame_only + // sub_advsimd.html#SUB_asisdsame_only public static void Sub_S(Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = true; + const bool U = true; /* Decode Scalar */ int d = (int)UInt(Rd); @@ -2707,10 +4008,10 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/sub_advsimd.xml#SUB_asimdsame_only + // sub_advsimd.html#SUB_asimdsame_only public static void Sub_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = true; + const bool U = true; /* Decode Vector */ int d = (int)UInt(Rd); @@ -2752,11 +4053,11 @@ namespace Ryujinx.Tests.Cpu.Tester V(d, result); } - // https://meriac.github.io/archex/A64_v83A_ISA/subhn_advsimd.xml + // subhn_advsimd.html public static void Subhn_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd) { - bool U = false; - bool o1 = true; + const bool U = false; + const bool o1 = true; /* Decode */ int d = (int)UInt(Rd); diff --git a/Ryujinx.Tests/Cpu/Tester/Pseudocode.cs b/Ryujinx.Tests/Cpu/Tester/Pseudocode.cs index 18a1f441..363e2de9 100644 --- a/Ryujinx.Tests/Cpu/Tester/Pseudocode.cs +++ b/Ryujinx.Tests/Cpu/Tester/Pseudocode.cs @@ -1,6 +1,8 @@ // https://github.com/LDj3SNuD/ARM_v8-A_AArch64_Instructions_Tester/blob/master/Tester/Pseudocode.cs -// https://meriac.github.io/archex/A64_v83A_ISA/shared_pseudocode.xml +// https://developer.arm.com/products/architecture/a-profile/exploration-tools +// ..\A64_v83A_ISA_xml_00bet6.1\ISA_v83A_A64_xml_00bet6.1_OPT\xhtml\ + // https://alastairreid.github.io/asl-lexical-syntax/ // | ------------------------|----------------------------------- | @@ -31,7 +33,7 @@ namespace Ryujinx.Tests.Cpu.Tester internal static class AArch64 { #region "exceptions/exceptions/" - /* #AArch64.ResetControlRegisters.1 */ + /* shared_pseudocode.html#AArch64.ResetControlRegisters.1 */ public static void ResetControlRegisters(bool cold_reset) { PSTATE.N = cold_reset; @@ -76,7 +78,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "functions/registers/" - /* #AArch64.ResetGeneralRegisters.0 */ + /* shared_pseudocode.html#AArch64.ResetGeneralRegisters.0 */ public static void ResetGeneralRegisters() { for (int i = 0; i <= 30; i++) @@ -86,7 +88,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #AArch64.ResetSIMDFPRegisters.0 */ + /* shared_pseudocode.html#AArch64.ResetSIMDFPRegisters.0 */ public static void ResetSIMDFPRegisters() { for (int i = 0; i <= 31; i++) @@ -96,7 +98,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #AArch64.ResetSpecialRegisters.0 */ + /* shared_pseudocode.html#AArch64.ResetSpecialRegisters.0 */ public static void ResetSpecialRegisters() { // AArch64 special registers @@ -105,10 +107,10 @@ namespace Ryujinx.Tests.Cpu.Tester /* SP_EL1 = bits(64) UNKNOWN; */ SP_EL1.SetAll(false); - FPSR.SetAll(false); // FIXME: Temporary solution. + FPSR.SetAll(false); // TODO: Add named fields. } - // #impl-aarch64.SP.write.0 + // shared_pseudocode.html#impl-aarch64.SP.write.0 public static void SP(Bits value) { /* int width = value.Count; */ @@ -140,7 +142,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // #impl-aarch64.SP.read.0 + // shared_pseudocode.html#impl-aarch64.SP.read.0 public static Bits SP(int width) { /* assert width IN {8,16,32,64}; */ @@ -166,7 +168,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // #impl-aarch64.V.write.1 + // shared_pseudocode.html#impl-aarch64.V.write.1 public static void V(int n, Bits value) { /* int width = value.Count; */ @@ -177,7 +179,7 @@ namespace Ryujinx.Tests.Cpu.Tester _V[n] = ZeroExtend(128, value); } - /* #impl-aarch64.V.read.1 */ + /* shared_pseudocode.html#impl-aarch64.V.read.1 */ public static Bits V(int width, int n) { /* assert n >= 0 && n <= 31; */ @@ -186,7 +188,7 @@ namespace Ryujinx.Tests.Cpu.Tester return _V[n][width - 1, 0]; } - /* #impl-aarch64.Vpart.read.2 */ + /* shared_pseudocode.html#impl-aarch64.Vpart.read.2 */ public static Bits Vpart(int width, int n, int part) { /* assert n >= 0 && n <= 31; */ @@ -204,7 +206,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // #impl-aarch64.Vpart.write.2 + // shared_pseudocode.html#impl-aarch64.Vpart.write.2 public static void Vpart(int n, int part, Bits value) { int width = value.Count; @@ -224,7 +226,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - // #impl-aarch64.X.write.1 + // shared_pseudocode.html#impl-aarch64.X.write.1 public static void X(int n, Bits value) { /* int width = value.Count; */ @@ -238,7 +240,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #impl-aarch64.X.read.1 */ + /* shared_pseudocode.html#impl-aarch64.X.read.1 */ public static Bits X(int width, int n) { /* assert n >= 0 && n <= 31; */ @@ -256,12 +258,12 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "instrs/countop/" - // #CountOp + // shared_pseudocode.html#CountOp public enum CountOp {CountOp_CLZ, CountOp_CLS, CountOp_CNT}; #endregion #region "instrs/extendreg/" - /* #impl-aarch64.DecodeRegExtend.1 */ + /* shared_pseudocode.html#impl-aarch64.DecodeRegExtend.1 */ public static ExtendType DecodeRegExtend(Bits op) { switch (op) @@ -286,7 +288,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #impl-aarch64.ExtendReg.3 */ + /* shared_pseudocode.html#impl-aarch64.ExtendReg.3 */ public static Bits ExtendReg(int N, int reg, ExtendType type, int shift) { /* assert shift >= 0 && shift <= 4; */ @@ -335,13 +337,13 @@ namespace Ryujinx.Tests.Cpu.Tester return Extend(Bits.Concat(val[len - 1, 0], Zeros(shift)), N, unsigned); } - // #ExtendType + // shared_pseudocode.html#ExtendType public enum ExtendType {ExtendType_SXTB, ExtendType_SXTH, ExtendType_SXTW, ExtendType_SXTX, ExtendType_UXTB, ExtendType_UXTH, ExtendType_UXTW, ExtendType_UXTX}; #endregion #region "instrs/integer/bitmasks/" - /* #impl-aarch64.DecodeBitMasks.4 */ + /* shared_pseudocode.html#impl-aarch64.DecodeBitMasks.4 */ public static (Bits, Bits) DecodeBitMasks(int M, bool immN, Bits imms, Bits immr, bool immediate) { Bits tmask, wmask; @@ -404,7 +406,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "instrs/integer/shiftreg/" - /* #impl-aarch64.DecodeShift.1 */ + /* shared_pseudocode.html#impl-aarch64.DecodeShift.1 */ public static ShiftType DecodeShift(Bits op) { switch (op) @@ -421,7 +423,7 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #impl-aarch64.ShiftReg.3 */ + /* shared_pseudocode.html#impl-aarch64.ShiftReg.3 */ public static Bits ShiftReg(int N, int reg, ShiftType type, int amount) { Bits result = X(N, reg); @@ -446,10 +448,15 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #ShiftType + // shared_pseudocode.html#ShiftType public enum ShiftType {ShiftType_LSL, ShiftType_LSR, ShiftType_ASR, ShiftType_ROR}; #endregion +#region "instrs/vector/arithmetic/unary/cmp/compareop/" + // shared_pseudocode.html#CompareOp + public enum CompareOp {CompareOp_GT, CompareOp_GE, CompareOp_EQ, CompareOp_LE, CompareOp_LT}; +#endregion + #region "instrs/vector/reduce/reduceop/" public static Bits Reduce(ReduceOp op, Bits input, int esize) { @@ -495,6 +502,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } + // shared_pseudocode.html#ReduceOp public enum ReduceOp {ReduceOp_FMINNUM, ReduceOp_FMAXNUM, ReduceOp_FMIN, ReduceOp_FMAX, ReduceOp_FADD, ReduceOp_ADD}; @@ -520,7 +528,7 @@ namespace Ryujinx.Tests.Cpu.Tester SP_EL0 = new Bits(64, false); SP_EL1 = new Bits(64, false); - FPSR = new Bits(32, false); // FIXME: Temporary solution. + FPSR = new Bits(32, false); // TODO: Add named fields. PSTATE.N = false; PSTATE.Z = false; @@ -537,7 +545,7 @@ namespace Ryujinx.Tests.Cpu.Tester return x.And(y); } - // #impl-shared.ASR.2 + // shared_pseudocode.html#impl-shared.ASR.2 public static Bits ASR(Bits x, int shift) { int N = x.Count; @@ -558,7 +566,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #impl-shared.ASR_C.2 + // shared_pseudocode.html#impl-shared.ASR_C.2 public static (Bits, bool) ASR_C(Bits x, int shift) { int N = x.Count; @@ -572,13 +580,13 @@ namespace Ryujinx.Tests.Cpu.Tester return (result, carry_out); } - // #impl-shared.Abs.1 + // shared_pseudocode.html#impl-shared.Abs.1 public static BigInteger Abs(BigInteger x) { return (x >= 0 ? x : -x); } - // #impl-shared.CountLeadingSignBits.1 + // shared_pseudocode.html#impl-shared.CountLeadingSignBits.1 public static int CountLeadingSignBits(Bits x) { int N = x.Count; @@ -586,7 +594,7 @@ namespace Ryujinx.Tests.Cpu.Tester return CountLeadingZeroBits(EOR(x[N - 1, 1], x[N - 2, 0])); } - // #impl-shared.CountLeadingZeroBits.1 + // shared_pseudocode.html#impl-shared.CountLeadingZeroBits.1 public static int CountLeadingZeroBits(Bits x) { int N = x.Count; @@ -594,7 +602,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (N - 1 - HighestSetBit(x)); } - // #impl-shared.Elem.read.3 + // shared_pseudocode.html#impl-shared.Elem.read.3 public static Bits Elem(/*in */Bits vector, int e, int size) { /* int N = vector.Count; */ @@ -604,7 +612,7 @@ namespace Ryujinx.Tests.Cpu.Tester return vector[e * size + size - 1, e * size]; } - // #impl-shared.Elem.write.3 + // shared_pseudocode.html#impl-shared.Elem.write.3 public static void Elem(/*out */Bits vector, int e, int size, Bits value) { /* int N = vector.Count; */ @@ -620,7 +628,7 @@ namespace Ryujinx.Tests.Cpu.Tester return x.Xor(y); } - // #impl-shared.Extend.3 + // shared_pseudocode.html#impl-shared.Extend.3 public static Bits Extend(Bits x, int N, bool unsigned) { if (unsigned) @@ -633,13 +641,13 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #impl-shared.Extend.2 */ + /* shared_pseudocode.html#impl-shared.Extend.2 */ public static Bits Extend(int N, Bits x, bool unsigned) { return Extend(x, N, unsigned); } - // #impl-shared.HighestSetBit.1 + // shared_pseudocode.html#impl-shared.HighestSetBit.1 public static int HighestSetBit(Bits x) { int N = x.Count; @@ -655,13 +663,13 @@ namespace Ryujinx.Tests.Cpu.Tester return -1; } - // #impl-shared.Int.2 + // shared_pseudocode.html#impl-shared.Int.2 public static BigInteger Int(Bits x, bool unsigned) { return (unsigned ? UInt(x) : SInt(x)); } - // #impl-shared.IsOnes.1 + // shared_pseudocode.html#impl-shared.IsOnes.1 public static bool IsOnes(Bits x) { int N = x.Count; @@ -669,7 +677,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (x == Ones(N)); } - // #impl-shared.IsZero.1 + // shared_pseudocode.html#impl-shared.IsZero.1 public static bool IsZero(Bits x) { int N = x.Count; @@ -677,13 +685,13 @@ namespace Ryujinx.Tests.Cpu.Tester return (x == Zeros(N)); } - // #impl-shared.IsZeroBit.1 + // shared_pseudocode.html#impl-shared.IsZeroBit.1 public static bool IsZeroBit(Bits x) { return IsZero(x); } - // #impl-shared.LSL.2 + // shared_pseudocode.html#impl-shared.LSL.2 public static Bits LSL(Bits x, int shift) { int N = x.Count; @@ -704,7 +712,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #impl-shared.LSL_C.2 + // shared_pseudocode.html#impl-shared.LSL_C.2 public static (Bits, bool) LSL_C(Bits x, int shift) { int N = x.Count; @@ -718,7 +726,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (result, carry_out); } - // #impl-shared.LSR.2 + // shared_pseudocode.html#impl-shared.LSR.2 public static Bits LSR(Bits x, int shift) { int N = x.Count; @@ -739,7 +747,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #impl-shared.LSR_C.2 + // shared_pseudocode.html#impl-shared.LSR_C.2 public static (Bits, bool) LSR_C(Bits x, int shift) { int N = x.Count; @@ -753,7 +761,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (result, carry_out); } - // #impl-shared.Min.2 + // shared_pseudocode.html#impl-shared.Min.2 public static int Min(int a, int b) { if (a <= b) @@ -766,13 +774,14 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #impl-shared.NOT.1 */ + /* shared_pseudocode.html#impl-shared.NOT.1 */ public static Bits NOT(Bits x) { return x.Not(); } - // #impl-shared.Ones.1 + // shared_pseudocode.html#impl-shared.Ones.1 + /* shared_pseudocode.html#impl-shared.Ones.0 */ public static Bits Ones(int N) { return Replicate(true, N); @@ -790,7 +799,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (decimal)value; } - // #impl-shared.ROR.2 + // shared_pseudocode.html#impl-shared.ROR.2 public static Bits ROR(Bits x, int shift) { /* assert shift >= 0; */ @@ -809,7 +818,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #impl-shared.ROR_C.2 + // shared_pseudocode.html#impl-shared.ROR_C.2 public static (Bits, bool) ROR_C(Bits x, int shift) { int N = x.Count; @@ -823,7 +832,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (result, carry_out); } - /* #impl-shared.Replicate.1 */ + /* shared_pseudocode.html#impl-shared.Replicate.1 */ public static Bits Replicate(int N, Bits x) { int M = x.Count; @@ -833,7 +842,7 @@ namespace Ryujinx.Tests.Cpu.Tester return Replicate(x, N / M); } - /* #impl-shared.Replicate.2 */ + /* shared_pseudocode.html#impl-shared.Replicate.2 */ public static Bits Replicate(Bits x, int N) { int M = x.Count; @@ -848,13 +857,13 @@ namespace Ryujinx.Tests.Cpu.Tester return new Bits(dst); } - /* #impl-shared.RoundDown.1 */ + /* shared_pseudocode.html#impl-shared.RoundDown.1 */ public static BigInteger RoundDown(decimal x) { return (BigInteger)Decimal.Floor(x); } - // #impl-shared.RoundTowardsZero.1 + // shared_pseudocode.html#impl-shared.RoundTowardsZero.1 public static BigInteger RoundTowardsZero(decimal x) { if (x == 0.0m) @@ -871,13 +880,13 @@ namespace Ryujinx.Tests.Cpu.Tester } } - /* #impl-shared.RoundUp.1 */ + /* shared_pseudocode.html#impl-shared.RoundUp.1 */ public static BigInteger RoundUp(decimal x) { return (BigInteger)Decimal.Ceiling(x); } - // #impl-shared.SInt.1 + // shared_pseudocode.html#impl-shared.SInt.1 public static BigInteger SInt(Bits x) { int N = x.Count; @@ -900,7 +909,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #impl-shared.SignExtend.2 + // shared_pseudocode.html#impl-shared.SignExtend.2 public static Bits SignExtend(Bits x, int N) { int M = x.Count; @@ -910,13 +919,13 @@ namespace Ryujinx.Tests.Cpu.Tester return Bits.Concat(Replicate(x[M - 1], N - M), x); } - /* #impl-shared.SignExtend.1 */ + /* shared_pseudocode.html#impl-shared.SignExtend.1 */ public static Bits SignExtend(int N, Bits x) { return SignExtend(x, N); } - // #impl-shared.UInt.1 + // shared_pseudocode.html#impl-shared.UInt.1 public static BigInteger UInt(Bits x) { int N = x.Count; @@ -934,7 +943,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #impl-shared.ZeroExtend.2 + // shared_pseudocode.html#impl-shared.ZeroExtend.2 public static Bits ZeroExtend(Bits x, int N) { int M = x.Count; @@ -944,14 +953,14 @@ namespace Ryujinx.Tests.Cpu.Tester return Bits.Concat(Zeros(N - M), x); } - /* #impl-shared.ZeroExtend.1 */ + /* shared_pseudocode.html#impl-shared.ZeroExtend.1 */ public static Bits ZeroExtend(int N, Bits x) { return ZeroExtend(x, N); } - // #impl-shared.Zeros.1 - /* #impl-shared.Zeros.0 */ + // shared_pseudocode.html#impl-shared.Zeros.1 + /* shared_pseudocode.html#impl-shared.Zeros.0 */ public static Bits Zeros(int N) { return Replicate(false, N); @@ -959,7 +968,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "functions/crc/" - // #impl-shared.BitReverse.1 + // shared_pseudocode.html#impl-shared.BitReverse.1 public static Bits BitReverse(Bits data) { int N = data.Count; @@ -974,7 +983,7 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #impl-shared.Poly32Mod2.2 + // shared_pseudocode.html#impl-shared.Poly32Mod2.2 public static Bits Poly32Mod2(Bits _data, Bits poly) { int N = _data.Count; @@ -996,7 +1005,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "functions/integer/" - /* #impl-shared.AddWithCarry.3 */ + /* shared_pseudocode.html#impl-shared.AddWithCarry.3 */ public static (Bits, Bits) AddWithCarry(int N, Bits x, Bits y, bool carry_in) { BigInteger unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in); @@ -1021,11 +1030,11 @@ namespace Ryujinx.Tests.Cpu.Tester public static Bits SP_EL0; public static Bits SP_EL1; - public static Bits FPSR; // FIXME: Temporary solution. + public static Bits FPSR; // TODO: Add named fields. #endregion #region "functions/system/" - // #impl-shared.ConditionHolds.1 + // shared_pseudocode.html#impl-shared.ConditionHolds.1 public static bool ConditionHolds(Bits cond) { bool result; @@ -1070,16 +1079,16 @@ namespace Ryujinx.Tests.Cpu.Tester return result; } - // #EL3 + // shared_pseudocode.html#EL3 public static readonly Bits EL3 = "11"; - // #EL2 + // shared_pseudocode.html#EL2 public static readonly Bits EL2 = "10"; - // #EL1 + // shared_pseudocode.html#EL1 public static readonly Bits EL1 = "01"; - // #EL0 + // shared_pseudocode.html#EL0 public static readonly Bits EL0 = "00"; - /* #impl-shared.HaveEL.1 */ + /* shared_pseudocode.html#impl-shared.HaveEL.1 */ public static bool HaveEL(Bits el) { if (el == EL1 || el == EL0) @@ -1093,7 +1102,7 @@ namespace Ryujinx.Tests.Cpu.Tester public static ProcState PSTATE; - /* #ProcState */ + /* shared_pseudocode.html#ProcState */ internal struct ProcState { public void NZCV(Bits nzcv) // ASL: ".<,,,>". @@ -1122,7 +1131,7 @@ namespace Ryujinx.Tests.Cpu.Tester #endregion #region "functions/vector/" - // #impl-shared.SatQ.3 + // shared_pseudocode.html#impl-shared.SatQ.3 public static (Bits, bool) SatQ(BigInteger i, int N, bool unsigned) { (Bits result, bool sat) = (unsigned ? UnsignedSatQ(i, N) : SignedSatQ(i, N)); @@ -1130,7 +1139,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (result, sat); } - // #impl-shared.SignedSatQ.2 + // shared_pseudocode.html#impl-shared.SignedSatQ.2 public static (Bits, bool) SignedSatQ(BigInteger i, int N) { BigInteger result; @@ -1155,7 +1164,7 @@ namespace Ryujinx.Tests.Cpu.Tester return (result.SubBigInteger(N - 1, 0), saturated); } - // #impl-shared.UnsignedSatQ.2 + // shared_pseudocode.html#impl-shared.UnsignedSatQ.2 public static (Bits, bool) UnsignedSatQ(BigInteger i, int N) { BigInteger result;