diff --git a/Disarm.Tests/SimdTest.cs b/Disarm.Tests/SimdTest.cs index a5bef05..6e1d2b0 100644 --- a/Disarm.Tests/SimdTest.cs +++ b/Disarm.Tests/SimdTest.cs @@ -376,4 +376,119 @@ public void TestScalarAdvancedSimdScalarTwoRegisterMiscFp16() DisassembleAndCheckMnemonic(0x7EF9B812, Arm64Mnemonic.FCVTZU); DisassembleAndCheckMnemonic(0x7EF9D812, Arm64Mnemonic.FRSQRTE); } + + [Fact] + public void TestScalarAdvancedSimdScalarTwoRegisterMisc() + { + DisassembleAndCheckMnemonic(0x5EA03820, Arm64Mnemonic.SUQADD); + DisassembleAndCheckMnemonic(0x5EA07820, Arm64Mnemonic.SQABS); + DisassembleAndCheckMnemonic(0x5EE08841, Arm64Mnemonic.CMGT); + DisassembleAndCheckMnemonic(0x5EE09841, Arm64Mnemonic.CMEQ); + DisassembleAndCheckMnemonic(0x5EE0A841, Arm64Mnemonic.CMLT); + DisassembleAndCheckMnemonic(0x5EE0B841, Arm64Mnemonic.ABS); + DisassembleAndCheckMnemonic(0x5E214841, Arm64Mnemonic.SQXTN); + DisassembleAndCheckMnemonic(0x5E21A841, Arm64Mnemonic.FCVTNS); + DisassembleAndCheckMnemonic(0x5E21B841, Arm64Mnemonic.FCVTMS); + DisassembleAndCheckMnemonic(0x5E21C841, Arm64Mnemonic.FCVTAS); + DisassembleAndCheckMnemonic(0x5E21D841, Arm64Mnemonic.SCVTF); + DisassembleAndCheckMnemonic(0x5EA0C841, Arm64Mnemonic.FCMGT); + DisassembleAndCheckMnemonic(0x5EA0D841, Arm64Mnemonic.FCMEQ); + DisassembleAndCheckMnemonic(0x5EA0E841, Arm64Mnemonic.FCMLT); + DisassembleAndCheckMnemonic(0x5EA1B841, Arm64Mnemonic.FCVTZS); + DisassembleAndCheckMnemonic(0x5EA1D841, Arm64Mnemonic.FRECPE); + DisassembleAndCheckMnemonic(0x5EA1F841, Arm64Mnemonic.FRECPX); + DisassembleAndCheckMnemonic(0x7EA03841, Arm64Mnemonic.USQADD); + DisassembleAndCheckMnemonic(0x7EA07841, Arm64Mnemonic.SQNEG); + DisassembleAndCheckMnemonic(0x7EE08841, Arm64Mnemonic.CMGE); + DisassembleAndCheckMnemonic(0x7EE09841, Arm64Mnemonic.CMLE); + DisassembleAndCheckMnemonic(0x7EE0B841, Arm64Mnemonic.NEG); + DisassembleAndCheckMnemonic(0x7EA12841, Arm64Mnemonic.SQXTUN); + DisassembleAndCheckMnemonic(0x7EA14841, Arm64Mnemonic.UQXTN); + DisassembleAndCheckMnemonic(0x7E616841, Arm64Mnemonic.FCVTXN); + DisassembleAndCheckMnemonic(0x7E21A841, Arm64Mnemonic.FCVTNU); + DisassembleAndCheckMnemonic(0x7E21B841, Arm64Mnemonic.FCVTMU); + DisassembleAndCheckMnemonic(0x7E21C841, Arm64Mnemonic.FCVTAU); + DisassembleAndCheckMnemonic(0x7E21D841, Arm64Mnemonic.UCVTF); + DisassembleAndCheckMnemonic(0x7EA0C841, Arm64Mnemonic.FCMGE); + DisassembleAndCheckMnemonic(0x7EA0D841, Arm64Mnemonic.FCMLE); + DisassembleAndCheckMnemonic(0x7EA1A841, Arm64Mnemonic.FCVTPU); + DisassembleAndCheckMnemonic(0x7EA1B841, Arm64Mnemonic.FCVTZU); + DisassembleAndCheckMnemonic(0x7EA1D841, Arm64Mnemonic.FRSQRTE); + } + + [Fact] + public void TestScalarAdvancedSimdScalarPairwise() + { + DisassembleAndCheckMnemonic(0x5EF1B801, Arm64Mnemonic.ADDP); + DisassembleAndCheckMnemonic(0x7E70C801, Arm64Mnemonic.FMAXNMP); + DisassembleAndCheckMnemonic(0x7E70D801, Arm64Mnemonic.FADDP); + DisassembleAndCheckMnemonic(0x7E70F801, Arm64Mnemonic.FMAXP); + DisassembleAndCheckMnemonic(0x7EF0C801, Arm64Mnemonic.FMINNMP); + DisassembleAndCheckMnemonic(0x7EF0F801, Arm64Mnemonic.FMINP); + } + + [Fact] + public void TestScalarAdvancedSimdScalarThreeDifferent() + { + DisassembleAndCheckMnemonic(0x5E639041, Arm64Mnemonic.SQDMLAL); + DisassembleAndCheckMnemonic(0x5E63B041, Arm64Mnemonic.SQDMLSL); + DisassembleAndCheckMnemonic(0x5E63D041, Arm64Mnemonic.SQDMULL); + } + + [Fact] + public void TestScalarAdvancedSimdScalarThreeSame() + { + DisassembleAndCheckMnemonic(0x5EE3_0C41, Arm64Mnemonic.SQADD); + DisassembleAndCheckMnemonic(0x5EE3_2C41, Arm64Mnemonic.SQSUB); + DisassembleAndCheckMnemonic(0x5EE3_3441, Arm64Mnemonic.CMGT); + DisassembleAndCheckMnemonic(0x5EE3_3C41, Arm64Mnemonic.CMGE); + DisassembleAndCheckMnemonic(0x5EE3_4441, Arm64Mnemonic.SSHL); + DisassembleAndCheckMnemonic(0x5EE3_4C41, Arm64Mnemonic.SQSHL); + DisassembleAndCheckMnemonic(0x5EE3_5441, Arm64Mnemonic.SRSHL); + DisassembleAndCheckMnemonic(0x5EE3_5C41, Arm64Mnemonic.SQRSHL); + DisassembleAndCheckMnemonic(0x5EE3_8441, Arm64Mnemonic.ADD); + DisassembleAndCheckMnemonic(0x5EE3_8C41, Arm64Mnemonic.CMTST); + DisassembleAndCheckMnemonic(0x5EA3_B441, Arm64Mnemonic.SQDMULH); + DisassembleAndCheckMnemonic(0x5E23_DC41, Arm64Mnemonic.FMULX); + DisassembleAndCheckMnemonic(0x5E23_E441, Arm64Mnemonic.FCMEQ); + DisassembleAndCheckMnemonic(0x5E23_FC41, Arm64Mnemonic.FRECPS); + DisassembleAndCheckMnemonic(0x5EA3_FC41, Arm64Mnemonic.FRSQRTS); + DisassembleAndCheckMnemonic(0x7EA3_0C41, Arm64Mnemonic.UQADD); + DisassembleAndCheckMnemonic(0x7EA3_2C41, Arm64Mnemonic.UQSUB); + DisassembleAndCheckMnemonic(0x7EE3_3441, Arm64Mnemonic.CMHI); + DisassembleAndCheckMnemonic(0x7EE3_3C41, Arm64Mnemonic.CMHS); + DisassembleAndCheckMnemonic(0x7EE3_4441, Arm64Mnemonic.USHL); + DisassembleAndCheckMnemonic(0x7EE3_4C41, Arm64Mnemonic.UQSHL); + DisassembleAndCheckMnemonic(0x7EE3_5441, Arm64Mnemonic.URSHL); + DisassembleAndCheckMnemonic(0x7EE3_5C41, Arm64Mnemonic.UQRSHL); + DisassembleAndCheckMnemonic(0x7EE3_8441, Arm64Mnemonic.SUB); + DisassembleAndCheckMnemonic(0x7EE3_8C41, Arm64Mnemonic.CMEQ); + DisassembleAndCheckMnemonic(0x7EA3_B441, Arm64Mnemonic.SQRDMULH); + DisassembleAndCheckMnemonic(0x7E63_E441, Arm64Mnemonic.FCMGE); + DisassembleAndCheckMnemonic(0x7E63_EC41, Arm64Mnemonic.FACGE); + DisassembleAndCheckMnemonic(0x7EE3_D441, Arm64Mnemonic.FABD); + DisassembleAndCheckMnemonic(0x7EE3_E441, Arm64Mnemonic.FCMGT); + DisassembleAndCheckMnemonic(0x7EE3_EC41, Arm64Mnemonic.FACGT); + } + + [Fact] + public void TestScalarAdvancedSimdScalarThreeSameFp16() + { + DisassembleAndCheckMnemonic(0x5E401C00, Arm64Mnemonic.FMULX); + DisassembleAndCheckMnemonic(0x5E402400, Arm64Mnemonic.FCMEQ); + DisassembleAndCheckMnemonic(0x5E403C00, Arm64Mnemonic.FRECPS); + DisassembleAndCheckMnemonic(0x5EC03C00, Arm64Mnemonic.FRSQRTS); + DisassembleAndCheckMnemonic(0x7E402400, Arm64Mnemonic.FCMGE); + DisassembleAndCheckMnemonic(0x7E402C00, Arm64Mnemonic.FACGE); + DisassembleAndCheckMnemonic(0x7EC01400, Arm64Mnemonic.FABD); + DisassembleAndCheckMnemonic(0x7EC02400, Arm64Mnemonic.FCMGT); + DisassembleAndCheckMnemonic(0x7EC02C00, Arm64Mnemonic.FACGT); + } + + [Fact] + public void TestScalarAdvancedSimdScalarThreeSameExtra() + { + DisassembleAndCheckMnemonic(0x7E808400, Arm64Mnemonic.SQRDMLAH); + DisassembleAndCheckMnemonic(0x7EC08C00, Arm64Mnemonic.SQRDMLSH); + } } diff --git a/Disarm/Arm64ArrangementSpecifier.cs b/Disarm/Arm64ArrangementSpecifier.cs index bfc839e..812cb8b 100644 --- a/Disarm/Arm64ArrangementSpecifier.cs +++ b/Disarm/Arm64ArrangementSpecifier.cs @@ -4,6 +4,7 @@ public enum Arm64ArrangementSpecifier { None, TwoD, + TwoH, FourH, FourS, TwoS, diff --git a/Disarm/Arm64Mnemonic.cs b/Disarm/Arm64Mnemonic.cs index c1ec83c..4232e0a 100644 --- a/Disarm/Arm64Mnemonic.cs +++ b/Disarm/Arm64Mnemonic.cs @@ -8,6 +8,7 @@ public enum Arm64Mnemonic DUP, CMGT, CMGE, + CMLE, CMTST, MLA, ADDP, @@ -25,6 +26,7 @@ public enum Arm64Mnemonic AESD, AESMC, AESIMC, + ABS, ADC, ADCS, ADD, @@ -719,8 +721,10 @@ public enum Arm64Mnemonic YIELD, CMHL, CMHS, + CMHI, UABD, - CMEO, + CMEQ, + CMLT, MLS, PMUL, BSL, diff --git a/Disarm/InternalDisassembly/Arm64ScalarAdvancedSimd.cs b/Disarm/InternalDisassembly/Arm64ScalarAdvancedSimd.cs index f18549a..dc4cb95 100644 --- a/Disarm/InternalDisassembly/Arm64ScalarAdvancedSimd.cs +++ b/Disarm/InternalDisassembly/Arm64ScalarAdvancedSimd.cs @@ -452,59 +452,323 @@ public static Arm64Instruction TwoRegisterMisc(uint instruction) var rn = (int) (instruction >> 5) & 0b1_1111; //Bits 5-9 var rd = (int) instruction & 0b1_1111; //Bits 0-4 - var sz = size.TestBit(0); + var sz = instruction.TestBit(22); - //This is almost excessively miscellaneous. - //Almost everything here has to be handled case-by-case. - - Arm64Register baseReg; - Arm64Mnemonic mnemonic; - Arm64MnemonicCategory category; + var result = new Arm64Instruction() + { + Mnemonic = uFlag switch + { + false => opcode switch + { + 0b00011 => Arm64Mnemonic.SUQADD, + 0b00111 => Arm64Mnemonic.SQABS, + 0b01000 => Arm64Mnemonic.CMGT, + 0b01001 => Arm64Mnemonic.CMEQ, + 0b01010 => Arm64Mnemonic.CMLT, + 0b01011 => Arm64Mnemonic.ABS, + 0b10100 => Arm64Mnemonic.SQXTN, + 0b11010 when size is 0 or 1 => Arm64Mnemonic.FCVTNS, + 0b11011 when size is 0 or 1 => Arm64Mnemonic.FCVTMS, + 0b11100 when size is 0 or 1 => Arm64Mnemonic.FCVTAS, + 0b11101 when size is 0 or 1 => Arm64Mnemonic.SCVTF, + 0b01100 when size is 2 or 3 => Arm64Mnemonic.FCMGT, + 0b01101 when size is 2 or 3 => Arm64Mnemonic.FCMEQ, + 0b01110 when size is 2 or 3 => Arm64Mnemonic.FCMLT, + 0b11010 when size is 2 or 3 => Arm64Mnemonic.FCVTPS, + 0b11011 when size is 2 or 3 => Arm64Mnemonic.FCVTZS, + 0b11101 when size is 2 or 3 => Arm64Mnemonic.FRECPE, + 0b11111 when size is 2 or 3 => Arm64Mnemonic.FRECPX, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + }, + true => opcode switch + { + 0b00011 => Arm64Mnemonic.USQADD, + 0b00111 => Arm64Mnemonic.SQNEG, + 0b01000 => Arm64Mnemonic.CMGE, + 0b01001 => Arm64Mnemonic.CMLE, + 0b01011 => Arm64Mnemonic.NEG, + 0b10010 => Arm64Mnemonic.SQXTUN, + 0b10100 => Arm64Mnemonic.UQXTN, + 0b10110 when size is 0 or 1 => Arm64Mnemonic.FCVTXN, + 0b11010 when size is 0 or 1 => Arm64Mnemonic.FCVTNU, + 0b11011 when size is 0 or 1 => Arm64Mnemonic.FCVTMU, + 0b11100 when size is 0 or 1 => Arm64Mnemonic.FCVTAU, + 0b11101 when size is 0 or 1 => Arm64Mnemonic.UCVTF, + 0b01100 when size is 2 or 3 => Arm64Mnemonic.FCMGE, + 0b01101 when size is 2 or 3 => Arm64Mnemonic.FCMLE, + 0b11010 when size is 2 or 3 => Arm64Mnemonic.FCVTPU, + 0b11011 when size is 2 or 3 => Arm64Mnemonic.FCVTZU, + 0b11101 when size is 2 or 3 => Arm64Mnemonic.FRSQRTE, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + } + }, + Op0Kind = Arm64OperandKind.Register, + Op1Kind = Arm64OperandKind.Register, + MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath, + }; - switch (opcode) + Arm64Register baseRegister; + Arm64Register baseRegister2; + + switch (result.Mnemonic) { - case 0b11101 when !uFlag && size is 0b00 or 0b01: - baseReg = sz ? Arm64Register.D0 : Arm64Register.S0; //32 << sz - mnemonic = Arm64Mnemonic.SCVTF; - category = Arm64MnemonicCategory.SimdScalarConversion; + case Arm64Mnemonic.SUQADD: + case Arm64Mnemonic.SQABS: + case Arm64Mnemonic.USQADD: + case Arm64Mnemonic.SQNEG: + baseRegister = size switch + { + 0 => Arm64Register.B0, + 1 => Arm64Register.H0, + 2 => Arm64Register.S0, + 3 => Arm64Register.D0, + _ => throw new IndexOutOfRangeException() + }; + result = result with + { + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister + rn + }; break; - default: - return new() + case Arm64Mnemonic.CMGT: + case Arm64Mnemonic.CMGE: + case Arm64Mnemonic.CMEQ: + case Arm64Mnemonic.CMLT: + case Arm64Mnemonic.CMLE: + baseRegister = size switch + { + 0 => Arm64Register.B0, + 1 => Arm64Register.H0, + 2 => Arm64Register.S0, + 3 => Arm64Register.D0, + _ => throw new IndexOutOfRangeException() + }; + result = result with { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, - MnemonicCategory = Arm64MnemonicCategory.Unspecified, + Op3Kind = Arm64OperandKind.Immediate, + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister + rn, + Op2Imm = 0 }; + break; + case Arm64Mnemonic.ABS: + case Arm64Mnemonic.NEG: + baseRegister = size switch + { + 0b11 => Arm64Register.D0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + result = result with + { + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister + rn + }; + break; + case Arm64Mnemonic.SQXTN: + case Arm64Mnemonic.SQXTUN: + case Arm64Mnemonic.UQXTN: + + baseRegister = size switch + { + 0 => Arm64Register.B0, + 1 => Arm64Register.H0, + 2 => Arm64Register.S0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + baseRegister2 = size switch + { + 0 => Arm64Register.H0, + 1 => Arm64Register.S0, + 2 => Arm64Register.D0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + result = result with + { + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister2 + rn + }; + break; + case Arm64Mnemonic.FCVTNS: + case Arm64Mnemonic.FCVTMS: + case Arm64Mnemonic.FCVTAS: + case Arm64Mnemonic.SCVTF: + case Arm64Mnemonic.FCVTPS: + case Arm64Mnemonic.FCVTZS: + case Arm64Mnemonic.FRECPE: + case Arm64Mnemonic.FRECPX: + case Arm64Mnemonic.FCVTNU: + case Arm64Mnemonic.FCVTMU: + case Arm64Mnemonic.FCVTAU: + case Arm64Mnemonic.UCVTF: + case Arm64Mnemonic.FCVTPU: + case Arm64Mnemonic.FCVTZU: + case Arm64Mnemonic.FRSQRTE: + baseRegister = sz switch + { + false => Arm64Register.S0, + true => Arm64Register.D0 + }; + result = result with + { + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister + rn + }; + break; + case Arm64Mnemonic.FCVTXN: + baseRegister = sz switch + { + false => throw new Arm64UndefinedInstructionException("Reserved"), + true => Arm64Register.S0 + }; + baseRegister2 = sz switch + { + false => throw new Arm64UndefinedInstructionException("Reserved"), + true => Arm64Register.D0 + }; + result = result with + { + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister2 + rn + }; + break; + case Arm64Mnemonic.FCMGT: + case Arm64Mnemonic.FCMGE: + case Arm64Mnemonic.FCMEQ: + case Arm64Mnemonic.FCMLT: + case Arm64Mnemonic.FCMLE: + baseRegister = sz switch + { + false => Arm64Register.S0, + true => Arm64Register.D0 + }; + result = result with + { + Op2Kind = Arm64OperandKind.FloatingPointImmediate, + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister + rn, + Op2FpImm = 0f + }; + break; } - - var regD = baseReg + rd; - var regN = baseReg + rn; - - return new() - { - Mnemonic = mnemonic, - Op0Kind = Arm64OperandKind.Register, - Op1Kind = Arm64OperandKind.Register, - Op0Reg = regD, - Op1Reg = regN, - MnemonicCategory = category, - }; + + return result; } public static Arm64Instruction Pairwise(uint instruction) { - return new() + var uFlag = instruction.TestBit(29); + var size = (instruction >> 22) & 0b11; //Bits 22-23 + var opcode = (instruction >> 12) & 0b1_1111; //Bits 12-16 + var rn = (int) (instruction >> 5) & 0b1_1111; //Bits 5-9 + var rd = (int) instruction & 0b1_1111; //Bits 0-4 + + var sz = instruction.TestBit(22); + + var result = new Arm64Instruction() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, + Mnemonic = opcode switch + { + // uFlag for H or S/D + 0b11011 when !uFlag => Arm64Mnemonic.ADDP, + 0b01100 when size is 0 or 1 => Arm64Mnemonic.FMAXNMP, + 0b01101 when size is 0 or 1 => Arm64Mnemonic.FADDP, + 0b01111 when size is 0 or 1 => Arm64Mnemonic.FMAXP, + 0b01100 when size is 2 or 3 => Arm64Mnemonic.FMINNMP, + 0b01111 when size is 2 or 3 => Arm64Mnemonic.FMINP, + _ => throw new Arm64UndefinedInstructionException("Unallocated"), + }, MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath, + Op0Kind = Arm64OperandKind.Register, + Op1Kind = Arm64OperandKind.Register, + Op1Reg = Arm64Register.V0 + rn, }; + + switch (result.Mnemonic) + { + case Arm64Mnemonic.ADDP: // only for addp + result = result with + { + Op0Reg = size switch + { + 0b11 => Arm64Register.D0 + rd, + _ => throw new Arm64UndefinedInstructionException("Reserved"), + }, + Op1Arrangement = size switch + { + 0b11 => Arm64ArrangementSpecifier.TwoD, + _ => throw new Arm64UndefinedInstructionException("Reserved"), + } + }; + break; + default: // any other + result = result with + { + Op0Reg = sz switch + { + false when !uFlag => Arm64Register.H0, + false => Arm64Register.S0, + true when uFlag => Arm64Register.D0, + _ => throw new Arm64UndefinedInstructionException("Reserved"), + } + rd, + Op1Arrangement = sz switch + { + false when !uFlag => Arm64ArrangementSpecifier.TwoH, + false => Arm64ArrangementSpecifier.TwoS, + true when uFlag => Arm64ArrangementSpecifier.TwoD, + _ => throw new Arm64UndefinedInstructionException("Reserved"), + } + }; + break; + } + + return result; } public static Arm64Instruction ThreeDifferent(uint instruction) { + var uFlag = instruction.TestBit(29); + + if (uFlag) + throw new Arm64UndefinedInstructionException("Unallocated"); + + var size = (instruction >> 22) & 0b11; //Bits 22-23 + var rm = (int) (instruction >> 5) & 0b1_1111; //Bits 16-20 + var opcode = (instruction >> 12) & 0b1111; //Bits 12-15 + var rn = (int) (instruction >> 5) & 0b1_1111; //Bits 5-9 + var rd = (int) instruction & 0b1_1111; //Bits 0-4 + return new() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, + Mnemonic = opcode switch + { + 0b1001 => Arm64Mnemonic.SQDMLAL, + 0b1011 => Arm64Mnemonic.SQDMLSL, + 0b1101 => Arm64Mnemonic.SQDMULL, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + }, MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath, + // , , + Op0Kind = Arm64OperandKind.Register, + Op1Kind = Arm64OperandKind.Register, + Op2Kind = Arm64OperandKind.Register, + Op0Reg = size switch + { + 0b01 => Arm64Register.S0, + 0b10 => Arm64Register.D0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + } + rd, + Op1Reg = size switch + { + 0b01 => Arm64Register.H0, + 0b10 => Arm64Register.S0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + } + rn, + Op2Reg = size switch + { + 0b01 => Arm64Register.H0, + 0b10 => Arm64Register.S0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + } + rm, }; } @@ -512,28 +776,222 @@ public static Arm64Instruction ThreeDifferent(uint instruction) //Note this is NOT the "Advanced SIMD Three Same" - that's in Adm64NonScalarAdvancedSimd.AdvancedSimdThreeSame public static Arm64Instruction ThreeSame(uint instruction) { - return new() + var uFlag = instruction.TestBit(29); // Bit 29 + var size = (instruction >> 22) & 0b11; //Bits 22-23 + var rm = (int) (instruction >> 5) & 0b1_1111; //Bits 16-20 + var opcode = (instruction >> 11) & 0b1_1111; //Bits 11-15 + var rn = (int) (instruction >> 5) & 0b1_1111; //Bits 5-9 + var rd = (int) instruction & 0b1_1111; //Bits 0-4 + + var sz = instruction.TestBit(22); // Bit 22 + + var result = new Arm64Instruction() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, + Mnemonic = uFlag switch + { + false => opcode switch + { + 0b00001 => Arm64Mnemonic.SQADD, + 0b00101 => Arm64Mnemonic.SQSUB, + 0b00110 => Arm64Mnemonic.CMGT, + 0b00111 => Arm64Mnemonic.CMGE, + 0b01000 => Arm64Mnemonic.SSHL, + 0b01001 => Arm64Mnemonic.SQSHL, + 0b01010 => Arm64Mnemonic.SRSHL, + 0b01011 => Arm64Mnemonic.SQRSHL, + 0b10000 => Arm64Mnemonic.ADD, + 0b10001 => Arm64Mnemonic.CMTST, + 0b10110 => Arm64Mnemonic.SQDMULH, + 0b11011 when size is 0 or 1 => Arm64Mnemonic.FMULX, + 0b11100 when size is 0 or 1 => Arm64Mnemonic.FCMEQ, + 0b11111 when size is 0 or 1 => Arm64Mnemonic.FRECPS, + 0b11111 when size is 2 or 3 => Arm64Mnemonic.FRSQRTS, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + }, + true => opcode switch + { + 0b00001 => Arm64Mnemonic.UQADD, + 0b00101 => Arm64Mnemonic.UQSUB, + 0b00110 => Arm64Mnemonic.CMHI, + 0b00111 => Arm64Mnemonic.CMHS, + 0b01000 => Arm64Mnemonic.USHL, + 0b01001 => Arm64Mnemonic.UQSHL, + 0b01010 => Arm64Mnemonic.URSHL, + 0b01011 => Arm64Mnemonic.UQRSHL, + 0b10000 => Arm64Mnemonic.SUB, + 0b10001 => Arm64Mnemonic.CMEQ, + 0b10110 => Arm64Mnemonic.SQRDMULH, + 0b11100 when size is 0 or 1 => Arm64Mnemonic.FCMGE, + 0b11101 when size is 0 or 1 => Arm64Mnemonic.FACGE, + 0b11010 when size is 2 or 3 => Arm64Mnemonic.FABD, + 0b11100 when size is 2 or 3 => Arm64Mnemonic.FCMGT, + 0b11101 when size is 2 or 3 => Arm64Mnemonic.FACGT, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + } + }, MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath, + Op0Kind = Arm64OperandKind.Register, + Op1Kind = Arm64OperandKind.Register, + Op2Kind = Arm64OperandKind.Register, + }; + + Arm64Register baseRegister; + + switch (result.Mnemonic) + { + case Arm64Mnemonic.SQADD: + case Arm64Mnemonic.SQSUB: + case Arm64Mnemonic.SQSHL: + case Arm64Mnemonic.SQRSHL: + case Arm64Mnemonic.UQADD: + case Arm64Mnemonic.UQSUB: + case Arm64Mnemonic.UQSHL: + case Arm64Mnemonic.UQRSHL: + baseRegister = size switch + { + 0 => Arm64Register.B0, + 1 => Arm64Register.H0, + 2 => Arm64Register.S0, + 3 => Arm64Register.D0, + _ => throw new IndexOutOfRangeException() + }; + break; + + case Arm64Mnemonic.CMGT: + case Arm64Mnemonic.CMGE: + case Arm64Mnemonic.SSHL: + case Arm64Mnemonic.SRSHL: + case Arm64Mnemonic.ADD: + case Arm64Mnemonic.CMTST: + case Arm64Mnemonic.CMHI: + case Arm64Mnemonic.CMHS: + case Arm64Mnemonic.USHL: + case Arm64Mnemonic.URSHL: + case Arm64Mnemonic.SUB: + case Arm64Mnemonic.CMEQ: + baseRegister = size switch + { + 0b11 => Arm64Register.D0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + break; + + case Arm64Mnemonic.SQDMULH: + case Arm64Mnemonic.SQRDMULH: + baseRegister = size switch + { + 0b01 => Arm64Register.H0, + 0b10 => Arm64Register.S0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + break; + + case Arm64Mnemonic.FMULX: + case Arm64Mnemonic.FCMEQ: + case Arm64Mnemonic.FRECPS: + case Arm64Mnemonic.FRSQRTS: + case Arm64Mnemonic.FCMGE: + case Arm64Mnemonic.FACGE: + case Arm64Mnemonic.FABD: + case Arm64Mnemonic.FCMGT: + case Arm64Mnemonic.FACGT: + baseRegister = sz switch + { + false => Arm64Register.S0, + true => Arm64Register.D0, + }; + break; + + default: + baseRegister = Arm64Register.INVALID; + break; + } + + return result with + { + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister + rn, + Op2Reg = baseRegister + rm, }; } public static Arm64Instruction ThreeSameFp16(uint instruction) { + var uFlag = instruction.TestBit(29); // Bit 29 + var rm = (int) (instruction >> 5) & 0b1_1111; //Bits 16-20 + var opcode = (instruction >> 11) & 0b111; //Bits 11-13 + var rn = (int) (instruction >> 5) & 0b1_1111; //Bits 5-9 + var rd = (int) instruction & 0b1_1111; //Bits 0-4 + + var aFlag = instruction.TestBit(23); // Bit 23 + return new() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, - MnemonicCategory = Arm64MnemonicCategory.Unspecified, //Scalar or math + Mnemonic = uFlag switch + { + false => opcode switch + { + 0b011 when !aFlag => Arm64Mnemonic.FMULX, + 0b100 when !aFlag => Arm64Mnemonic.FCMEQ, + 0b111 when !aFlag => Arm64Mnemonic.FRECPS, + 0b111 when aFlag => Arm64Mnemonic.FRSQRTS, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + }, + true => opcode switch + { + 0b100 when !aFlag => Arm64Mnemonic.FCMGE, + 0b101 when !aFlag => Arm64Mnemonic.FACGE, + 0b010 when aFlag => Arm64Mnemonic.FABD, + 0b100 when aFlag => Arm64Mnemonic.FCMGT, + 0b101 when aFlag => Arm64Mnemonic.FACGT, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + } + }, + MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath, + Op0Kind = Arm64OperandKind.Register, + Op1Kind = Arm64OperandKind.Register, + Op2Kind = Arm64OperandKind.Register, + Op0Reg = Arm64Register.H0 + rd, + Op1Reg = Arm64Register.H0 + rn, + Op2Reg = Arm64Register.H0 + rm, }; } public static Arm64Instruction ThreeSameExtra(uint instruction) { + var uFlag = instruction.TestBit(29); // Bit 29 + + if (!uFlag) + throw new Arm64UndefinedInstructionException("Unallocated"); + + var size = (instruction >> 22) & 0b11; //Bits 22-23 + var rm = (int) (instruction >> 5) & 0b1_1111; //Bits 16-20 + var opcode = (instruction >> 11) & 0b1111; //Bits 11-14 + var rn = (int) (instruction >> 5) & 0b1_1111; //Bits 5-9 + var rd = (int) instruction & 0b1_1111; //Bits 0-4 + + Arm64Register baseRegister = size switch + { + 0b10 => Arm64Register.H0, + 0b11 => Arm64Register.S0, + _ => throw new Arm64UndefinedInstructionException("Reserved") + }; + return new() { - Mnemonic = Arm64Mnemonic.UNIMPLEMENTED, + Mnemonic = opcode switch + { + 0b0000 => Arm64Mnemonic.SQRDMLAH, + 0b0001 => Arm64Mnemonic.SQRDMLSH, + _ => throw new Arm64UndefinedInstructionException("Unallocated") + }, MnemonicCategory = Arm64MnemonicCategory.SimdScalarMath, + Op0Kind = Arm64OperandKind.Register, + Op1Kind = Arm64OperandKind.Register, + Op2Kind = Arm64OperandKind.Register, + Op0Reg = baseRegister + rd, + Op1Reg = baseRegister + rn, + Op2Reg = baseRegister + rm, }; } }