From 47657a18179c6dc3bf5fa573fd60381cbffcd9e7 Mon Sep 17 00:00:00 2001 From: aroulin Date: Fri, 7 Aug 2015 10:10:35 +0200 Subject: arm_disasm: ARMv6 packing and sign-extend media instructions PKH, SEL SXTAB, SXTAB16, SXTB, SXTB16, SXTH, SXTAH UXTAB, UXTAB16, UXTB, UXTB16, UXTH, UXTAH --- src/core/arm/disassembler/arm_disasm.cpp | 163 ++++++++++++++++++++++++++++++- src/core/arm/disassembler/arm_disasm.h | 19 ++++ 2 files changed, 181 insertions(+), 1 deletion(-) diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 964e3011..3ac86794 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -1,6 +1,7 @@ // Copyright 2006 The Android Open Source Project #include +#include #include "common/string_util.h" #include "core/arm/disassembler/arm_disasm.h" @@ -66,10 +67,12 @@ static const char *opcode_names[] = { "mvn", "nop", "orr", + "pkh", "pld", "rsb", "rsc", "sbc", + "sel", "sev", "smlal", "smull", @@ -88,10 +91,22 @@ static const char *opcode_names[] = { "swi", "swp", "swpb", + "sxtab", + "sxtab16", + "sxtah", + "sxtb", + "sxtb16", + "sxth", "teq", "tst", "umlal", "umull", + "uxtab", + "uxtab16", + "uxtah", + "uxtb", + "uxtb16", + "uxth", "wfe", "wfi", "yield", @@ -236,8 +251,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) case OP_WFI: case OP_YIELD: return DisassembleNoOperands(opcode, insn); + case OP_PKH: + return DisassemblePKH(insn); case OP_PLD: return DisassemblePLD(insn); + case OP_SEL: + return DisassembleSEL(insn); case OP_STC: return "stc"; case OP_SWI: @@ -245,6 +264,19 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) case OP_SWP: case OP_SWPB: return DisassembleSWP(opcode, insn); + case OP_SXTAB: + case OP_SXTAB16: + case OP_SXTAH: + case OP_SXTB: + case OP_SXTB16: + case OP_SXTH: + case OP_UXTAB: + case OP_UXTAB16: + case OP_UXTAH: + case OP_UXTB: + case OP_UXTB16: + case OP_UXTH: + return DisassembleXT(opcode, insn); case OP_UMLAL: case OP_UMULL: case OP_SMLAL: @@ -684,6 +716,30 @@ std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn) return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); } +std::string ARM_Disasm::DisassemblePKH(uint32_t insn) +{ + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t imm5 = BITS(insn, 7, 11); + uint32_t tb = BIT(insn, 6); + uint32_t rm = BITS(insn, 0, 3); + + std::string suffix = tb ? "tb" : "bt"; + std::string shift = ""; + + if (tb && imm5 == 0) + imm5 = 32; + + if (imm5 > 0) { + shift = tb ? ", ASR" : ", LSL"; + shift += " #" + std::to_string(imm5); + } + + return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond), + rd, rn, rm, shift.c_str()); +} + std::string ARM_Disasm::DisassemblePLD(uint32_t insn) { uint8_t is_reg = (insn >> 25) & 0x1; @@ -737,6 +793,17 @@ std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { } } +std::string ARM_Disasm::DisassembleSEL(uint32_t insn) +{ + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 0, 3); + + return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[OP_SEL], cond_to_str(cond), + rd, rn, rm); +} + std::string ARM_Disasm::DisassembleSWI(uint32_t insn) { uint8_t cond = (insn >> 28) & 0xf; @@ -756,6 +823,30 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); } +std::string ARM_Disasm::DisassembleXT(Opcode opcode, uint32_t insn) +{ + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rotate = BITS(insn, 10, 11); + uint32_t rm = BITS(insn, 0, 3); + + std::string rn_part = ""; + static std::unordered_set> extend_with_add = { + OP_SXTAB, OP_SXTAB16, OP_SXTAH, + OP_UXTAB, OP_UXTAB16, OP_UXTAH + }; + if (extend_with_add.find(opcode) != extend_with_add.end()) + rn_part = ", r" + std::to_string(rn); + + std::string rotate_part = ""; + if (rotate != 0) + rotate_part = ", ROR #" + std::to_string(rotate << 3); + + return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond), + rd, rn_part.c_str(), rm, rotate_part.c_str()); +} + Opcode ARM_Disasm::Decode(uint32_t insn) { uint32_t bits27_26 = (insn >> 26) & 0x3; switch (bits27_26) { @@ -818,7 +909,7 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) { uint8_t is_reg = (insn >> 25) & 0x1; uint8_t bit4 = (insn >> 4) & 0x1; if (is_reg == 1 && bit4 == 1) - return OP_UNDEFINED; + return DecodeMedia(insn); uint8_t is_load = (insn >> 20) & 0x1; uint8_t is_byte = (insn >> 22) & 0x1; if ((insn & 0xfd70f000) == 0xf550f000) { @@ -940,6 +1031,59 @@ Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) { } } +Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 22); + uint32_t a = BITS(insn, 16, 19); + uint32_t op2 = BITS(insn, 5, 7); + + switch (op1) { + case 0x0: + if (BIT(op2, 0) == 0) + return OP_PKH; + if (op2 == 0x3 && a != 0xf) + return OP_SXTAB16; + if (op2 == 0x3 && a == 0xf) + return OP_SXTB16; + if (op2 == 0x5) + return OP_SEL; + break; + case 0x2: + if (op2 == 0x3 && a != 0xf) + return OP_SXTAB; + if (op2 == 0x3 && a == 0xf) + return OP_SXTB; + break; + case 0x3: + if (op2 == 0x3 && a != 0xf) + return OP_SXTAH; + if (op2 == 0x3 && a == 0xf) + return OP_SXTH; + break; + case 0x4: + if (op2 == 0x3 && a != 0xf) + return OP_UXTAB16; + if (op2 == 0x3 && a == 0xf) + return OP_UXTB16; + break; + case 0x6: + if (op2 == 0x3 && a != 0xf) + return OP_UXTAB; + if (op2 == 0x3 && a == 0xf) + return OP_UXTB; + break; + case 0x7: + if (op2 == 0x3 && a != 0xf) + return OP_UXTAH; + if (op2 == 0x3 && a == 0xf) + return OP_UXTH; + break; + default: + break; + } + + return OP_UNDEFINED; +} + Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { uint8_t bit24 = (insn >> 24) & 0x1; if (bit24 != 0) { @@ -999,6 +1143,23 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) { return OP_MSR; } +Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 24); + uint32_t rd = BITS(insn, 12, 15); + uint32_t op2 = BITS(insn, 5, 7); + uint32_t rn = BITS(insn, 0, 3); + + switch (BITS(op1, 3, 4)) { + case 0x1: + // Packing, unpacking, saturation, and reversal + return DecodePackingSaturationReversal(insn); + default: + break; + } + + return OP_UNDEFINED; +} + Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { uint8_t is_load = (insn >> 20) & 0x1; uint8_t bits_65 = (insn >> 5) & 0x3; diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h index d04fd21e..20e92fd0 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h @@ -48,10 +48,12 @@ enum Opcode { OP_MVN, OP_NOP, OP_ORR, + OP_PKH, OP_PLD, OP_RSB, OP_RSC, OP_SBC, + OP_SEL, OP_SEV, OP_SMLAL, OP_SMULL, @@ -70,10 +72,22 @@ enum Opcode { OP_SWI, OP_SWP, OP_SWPB, + OP_SXTAB, + OP_SXTAB16, + OP_SXTAH, + OP_SXTB, + OP_SXTB16, + OP_SXTH, OP_TEQ, OP_TST, OP_UMLAL, OP_UMULL, + OP_UXTAB, + OP_UXTAB16, + OP_UXTAH, + OP_UXTB, + OP_UXTB16, + OP_UXTH, OP_WFE, OP_WFI, OP_YIELD, @@ -132,8 +146,10 @@ class ARM_Disasm { static Opcode Decode10(uint32_t insn); static Opcode Decode11(uint32_t insn); static Opcode DecodeSyncPrimitive(uint32_t insn); + static Opcode DecodePackingSaturationReversal(uint32_t insn); static Opcode DecodeMUL(uint32_t insn); static Opcode DecodeMSRImmAndHints(uint32_t insn); + static Opcode DecodeMedia(uint32_t insn); static Opcode DecodeLDRH(uint32_t insn); static Opcode DecodeALU(uint32_t insn); @@ -152,8 +168,11 @@ class ARM_Disasm { static std::string DisassembleMRS(uint32_t insn); static std::string DisassembleMSR(uint32_t insn); static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); + static std::string DisassemblePKH(uint32_t insn); static std::string DisassemblePLD(uint32_t insn); static std::string DisassembleREX(Opcode opcode, uint32_t insn); + static std::string DisassembleSEL(uint32_t insn); static std::string DisassembleSWI(uint32_t insn); static std::string DisassembleSWP(Opcode opcode, uint32_t insn); + static std::string DisassembleXT(Opcode opcode, uint32_t insn); }; -- cgit v1.2.3 From e4ff2442885e42ed5cfecb1ceadebf99da2cd2cf Mon Sep 17 00:00:00 2001 From: aroulin Date: Fri, 7 Aug 2015 13:44:02 +0200 Subject: arm_disasm: ARMv6 saturation media instructions SSAT, SSAT16, USAT, USAT16 --- src/core/arm/disassembler/arm_disasm.cpp | 52 ++++++++++++++++++++++++++++++-- src/core/arm/disassembler/arm_disasm.h | 5 +++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 3ac86794..d73495fe 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -76,6 +76,8 @@ static const char *opcode_names[] = { "sev", "smlal", "smull", + "ssat", + "ssat16", "stc", "stm", "str", @@ -101,6 +103,8 @@ static const char *opcode_names[] = { "tst", "umlal", "umull", + "usat", + "usat16", "uxtab", "uxtab16", "uxtah", @@ -257,6 +261,11 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) return DisassemblePLD(insn); case OP_SEL: return DisassembleSEL(insn); + case OP_SSAT: + case OP_SSAT16: + case OP_USAT: + case OP_USAT16: + return DisassembleSAT(opcode, insn); case OP_STC: return "stc"; case OP_SWI: @@ -793,8 +802,35 @@ std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { } } -std::string ARM_Disasm::DisassembleSEL(uint32_t insn) -{ +std::string ARM_Disasm::DisassembleSAT(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t sat_imm = BITS(insn, 16, 20); + uint32_t rd = BITS(insn, 12, 15); + uint32_t imm5 = BITS(insn, 7, 11); + uint32_t sh = BIT(insn, 6); + uint32_t rn = BITS(insn, 0, 3); + + std::string shift_part = ""; + bool opcode_has_shift = (opcode == OP_SSAT) || (opcode == OP_USAT); + if (opcode_has_shift && !(sh == 0 && imm5 == 0)) { + if (sh == 0) + shift_part += ", LSL #"; + else + shift_part += ", ASR #"; + + if (imm5 == 0) + imm5 = 32; + shift_part += std::to_string(imm5); + } + + if (opcode == OP_SSAT || opcode == OP_SSAT16) + sat_imm++; + + return Common::StringFromFormat("%s%s\tr%u, #%u, r%u%s", opcode_names[opcode], cond_to_str(cond), rd, + sat_imm, rn, shift_part.c_str()); +} + +std::string ARM_Disasm::DisassembleSEL(uint32_t insn) { uint32_t cond = BITS(insn, 28, 31); uint32_t rn = BITS(insn, 16, 19); uint32_t rd = BITS(insn, 12, 15); @@ -1048,12 +1084,18 @@ Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { return OP_SEL; break; case 0x2: + if (BIT(op2, 0) == 0) + return OP_SSAT; + if (op2 == 0x1) + return OP_SSAT16; if (op2 == 0x3 && a != 0xf) return OP_SXTAB; if (op2 == 0x3 && a == 0xf) return OP_SXTB; break; case 0x3: + if (BIT(op2, 0) == 0) + return OP_SSAT; if (op2 == 0x3 && a != 0xf) return OP_SXTAH; if (op2 == 0x3 && a == 0xf) @@ -1066,12 +1108,18 @@ Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { return OP_UXTB16; break; case 0x6: + if (BIT(op2, 0) == 0) + return OP_USAT; + if (op2 == 0x1) + return OP_USAT16; if (op2 == 0x3 && a != 0xf) return OP_UXTAB; if (op2 == 0x3 && a == 0xf) return OP_UXTB; break; case 0x7: + if (BIT(op2, 0) == 0) + return OP_USAT; if (op2 == 0x3 && a != 0xf) return OP_UXTAH; if (op2 == 0x3 && a == 0xf) diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h index 20e92fd0..d8d4faf9 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h @@ -57,6 +57,8 @@ enum Opcode { OP_SEV, OP_SMLAL, OP_SMULL, + OP_SSAT, + OP_SSAT16, OP_STC, OP_STM, OP_STR, @@ -82,6 +84,8 @@ enum Opcode { OP_TST, OP_UMLAL, OP_UMULL, + OP_USAT, + OP_USAT16, OP_UXTAB, OP_UXTAB16, OP_UXTAH, @@ -171,6 +175,7 @@ class ARM_Disasm { static std::string DisassemblePKH(uint32_t insn); static std::string DisassemblePLD(uint32_t insn); static std::string DisassembleREX(Opcode opcode, uint32_t insn); + static std::string DisassembleSAT(Opcode opcode, uint32_t insn); static std::string DisassembleSEL(uint32_t insn); static std::string DisassembleSWI(uint32_t insn); static std::string DisassembleSWP(Opcode opcode, uint32_t insn); -- cgit v1.2.3 From 0be8e1bfb6a7fb37ddc1bdbbc410362b5e5c009e Mon Sep 17 00:00:00 2001 From: aroulin Date: Sun, 9 Aug 2015 13:52:51 +0200 Subject: arm_disasm: ARMv6 reversal media instructions REV, REV16, REVSH Only their ARM encoding, Thumb encoding is still missing. --- src/core/arm/disassembler/arm_disasm.cpp | 22 ++++++++++++++++++++++ src/core/arm/disassembler/arm_disasm.h | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index d73495fe..a03f113b 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -69,6 +69,9 @@ static const char *opcode_names[] = { "orr", "pkh", "pld", + "rev", + "rev16", + "revsh", "rsb", "rsc", "sbc", @@ -259,6 +262,10 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) return DisassemblePKH(insn); case OP_PLD: return DisassemblePLD(insn); + case OP_REV: + case OP_REV16: + case OP_REVSH: + return DisassembleREV(opcode, insn); case OP_SEL: return DisassembleSEL(insn); case OP_SSAT: @@ -772,6 +779,15 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn) } } +std::string ARM_Disasm::DisassembleREV(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 0, 3); + + return Common::StringFromFormat("%s%s\tr%u, r%u", opcode_names[opcode], cond_to_str(cond), + rd, rm); +} + std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { uint32_t rn = BITS(insn, 16, 19); uint32_t rd = BITS(insn, 12, 15); @@ -1094,12 +1110,16 @@ Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { return OP_SXTB; break; case 0x3: + if (op2 == 0x1) + return OP_REV; if (BIT(op2, 0) == 0) return OP_SSAT; if (op2 == 0x3 && a != 0xf) return OP_SXTAH; if (op2 == 0x3 && a == 0xf) return OP_SXTH; + if (op2 == 0x5) + return OP_REV16; break; case 0x4: if (op2 == 0x3 && a != 0xf) @@ -1124,6 +1144,8 @@ Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { return OP_UXTAH; if (op2 == 0x3 && a == 0xf) return OP_UXTH; + if (op2 == 0x5) + return OP_REVSH; break; default: break; diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h index d8d4faf9..a6b34dae 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h @@ -50,6 +50,9 @@ enum Opcode { OP_ORR, OP_PKH, OP_PLD, + OP_REV, + OP_REV16, + OP_REVSH, OP_RSB, OP_RSC, OP_SBC, @@ -174,6 +177,7 @@ class ARM_Disasm { static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); static std::string DisassemblePKH(uint32_t insn); static std::string DisassemblePLD(uint32_t insn); + static std::string DisassembleREV(Opcode opcode, uint32_t insn); static std::string DisassembleREX(Opcode opcode, uint32_t insn); static std::string DisassembleSAT(Opcode opcode, uint32_t insn); static std::string DisassembleSEL(uint32_t insn); -- cgit v1.2.3 From 4a1db13072764f464db5217c6481b87074963d87 Mon Sep 17 00:00:00 2001 From: aroulin Date: Mon, 10 Aug 2015 14:45:22 +0200 Subject: arm_disasm: ARMv6 parallel add/sub media instructions {S, U, Q, UQ, SH, UH}{ADD16, ASX, SAX, SUB16, ADD8, SUB8} --- src/core/arm/disassembler/arm_disasm.cpp | 129 +++++++++++++++++++++++++++++++ src/core/arm/disassembler/arm_disasm.h | 38 +++++++++ 2 files changed, 167 insertions(+) diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index a03f113b..59a714c4 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -69,18 +69,36 @@ static const char *opcode_names[] = { "orr", "pkh", "pld", + "qadd16", + "qadd8", + "qasx", + "qsax", + "qsub16", + "qsub8", "rev", "rev16", "revsh", "rsb", "rsc", + "sadd16", + "sadd8", + "sasx", "sbc", "sel", "sev", + "shadd16", + "shadd8", + "shasx", + "shsax", + "shsub16", + "shsub8", "smlal", "smull", "ssat", "ssat16", + "ssax", + "ssub16", + "ssub8", "stc", "stm", "str", @@ -104,10 +122,28 @@ static const char *opcode_names[] = { "sxth", "teq", "tst", + "uadd16", + "uadd8", + "uasx", + "uhadd16", + "uhadd8", + "uhasx", + "uhsax", + "uhsub16", + "uhsub8", "umlal", "umull", + "uqadd16", + "uqadd8", + "uqasx", + "uqsax", + "uqsub16", + "uqsub8", "usat", "usat16", + "usax", + "usub16", + "usub8", "uxtab", "uxtab16", "uxtah", @@ -262,6 +298,43 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) return DisassemblePKH(insn); case OP_PLD: return DisassemblePLD(insn); + case OP_QADD16: + case OP_QADD8: + case OP_QASX: + case OP_QSAX: + case OP_QSUB16: + case OP_QSUB8: + case OP_SADD16: + case OP_SADD8: + case OP_SASX: + case OP_SHADD16: + case OP_SHADD8: + case OP_SHASX: + case OP_SHSAX: + case OP_SHSUB16: + case OP_SHSUB8: + case OP_SSAX: + case OP_SSUB16: + case OP_SSUB8: + case OP_UADD16: + case OP_UADD8: + case OP_UASX: + case OP_UHADD16: + case OP_UHADD8: + case OP_UHASX: + case OP_UHSAX: + case OP_UHSUB16: + case OP_UHSUB8: + case OP_UQADD16: + case OP_UQADD8: + case OP_UQASX: + case OP_UQSAX: + case OP_UQSUB16: + case OP_UQSUB8: + case OP_USAX: + case OP_USUB16: + case OP_USUB8: + return DisassembleParallelAddSub(opcode, insn); case OP_REV: case OP_REV16: case OP_REVSH: @@ -732,6 +805,16 @@ std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn) return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); } +std::string ARM_Disasm::DisassembleParallelAddSub(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 0, 3); + + return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[opcode], cond_to_str(cond), + rd, rn, rm); +} + std::string ARM_Disasm::DisassemblePKH(uint32_t insn) { uint32_t cond = BITS(insn, 28, 31); @@ -1083,6 +1166,49 @@ Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) { } } +Opcode ARM_Disasm::DecodeParallelAddSub(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 21); + uint32_t op2 = BITS(insn, 5, 7); + uint32_t is_unsigned = BIT(insn, 22); + + if (op1 == 0x0 || op2 == 0x5 || op2 == 0x6) + return OP_UNDEFINED; + + // change op1 range from [1, 3] to range [0, 2] + op1--; + + // change op2 range from [0, 4] U {7} to range [0, 5] + if (op2 == 0x7) + op2 = 0x5; + + static std::vector opcodes = { + // op1 = 0 + OP_SADD16, OP_UADD16, + OP_SASX, OP_UASX, + OP_SSAX, OP_USAX, + OP_SSUB16, OP_USUB16, + OP_SADD8, OP_UADD8, + OP_SSUB8, OP_USUB8, + // op1 = 1 + OP_QADD16, OP_UQADD16, + OP_QASX, OP_UQASX, + OP_QSAX, OP_UQSAX, + OP_QSUB16, OP_UQSUB16, + OP_QADD8, OP_UQADD8, + OP_QSUB8, OP_UQSUB8, + // op1 = 2 + OP_SHADD16, OP_UHADD16, + OP_SHASX, OP_UHASX, + OP_SHSAX, OP_UHSAX, + OP_SHSUB16, OP_UHSUB16, + OP_SHADD8, OP_UHADD8, + OP_SHSUB8, OP_UHSUB8 + }; + + uint32_t opcode_index = op1 * 12 + op2 * 2 + is_unsigned; + return opcodes[opcode_index]; +} + Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { uint32_t op1 = BITS(insn, 20, 22); uint32_t a = BITS(insn, 16, 19); @@ -1220,6 +1346,9 @@ Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { uint32_t rn = BITS(insn, 0, 3); switch (BITS(op1, 3, 4)) { + case 0x0: + // unsigned and signed parallel addition and subtraction + return DecodeParallelAddSub(insn); case 0x1: // Packing, unpacking, saturation, and reversal return DecodePackingSaturationReversal(insn); diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h index a6b34dae..c1bd1b94 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h @@ -50,18 +50,36 @@ enum Opcode { OP_ORR, OP_PKH, OP_PLD, + OP_QADD16, + OP_QADD8, + OP_QASX, + OP_QSAX, + OP_QSUB16, + OP_QSUB8, OP_REV, OP_REV16, OP_REVSH, OP_RSB, OP_RSC, + OP_SADD16, + OP_SADD8, + OP_SASX, OP_SBC, OP_SEL, OP_SEV, + OP_SHADD16, + OP_SHADD8, + OP_SHASX, + OP_SHSAX, + OP_SHSUB16, + OP_SHSUB8, OP_SMLAL, OP_SMULL, OP_SSAT, OP_SSAT16, + OP_SSAX, + OP_SSUB16, + OP_SSUB8, OP_STC, OP_STM, OP_STR, @@ -85,10 +103,28 @@ enum Opcode { OP_SXTH, OP_TEQ, OP_TST, + OP_UADD16, + OP_UADD8, + OP_UASX, + OP_UHADD16, + OP_UHADD8, + OP_UHASX, + OP_UHSAX, + OP_UHSUB16, + OP_UHSUB8, OP_UMLAL, OP_UMULL, + OP_UQADD16, + OP_UQADD8, + OP_UQASX, + OP_UQSAX, + OP_UQSUB16, + OP_UQSUB8, OP_USAT, OP_USAT16, + OP_USAX, + OP_USUB16, + OP_USUB8, OP_UXTAB, OP_UXTAB16, OP_UXTAH, @@ -153,6 +189,7 @@ class ARM_Disasm { static Opcode Decode10(uint32_t insn); static Opcode Decode11(uint32_t insn); static Opcode DecodeSyncPrimitive(uint32_t insn); + static Opcode DecodeParallelAddSub(uint32_t insn); static Opcode DecodePackingSaturationReversal(uint32_t insn); static Opcode DecodeMUL(uint32_t insn); static Opcode DecodeMSRImmAndHints(uint32_t insn); @@ -175,6 +212,7 @@ class ARM_Disasm { static std::string DisassembleMRS(uint32_t insn); static std::string DisassembleMSR(uint32_t insn); static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); + static std::string DisassembleParallelAddSub(Opcode opcode, uint32_t insn); static std::string DisassemblePKH(uint32_t insn); static std::string DisassemblePLD(uint32_t insn); static std::string DisassembleREV(Opcode opcode, uint32_t insn); -- cgit v1.2.3 From 38c87733d9992927135e619d8710ed04785fdb5d Mon Sep 17 00:00:00 2001 From: aroulin Date: Mon, 10 Aug 2015 18:21:34 +0200 Subject: arm_disasm: ARMv6 mul/div and abs media instructions SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD, SMMLA, SMMUL, SMMLS USAD8, USADA8 --- src/core/arm/disassembler/arm_disasm.cpp | 107 ++++++++++++++++++++++++++++++- src/core/arm/disassembler/arm_disasm.h | 13 ++++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 59a714c4..1d40ae03 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -92,8 +92,17 @@ static const char *opcode_names[] = { "shsax", "shsub16", "shsub8", + "smlad", "smlal", + "smlald", + "smlsd", + "smlsld", + "smmla", + "smmls", + "smmul", + "smuad", "smull", + "smusd", "ssat", "ssat16", "ssax", @@ -139,6 +148,8 @@ static const char *opcode_names[] = { "uqsax", "uqsub16", "uqsub8", + "usad8", + "usada8", "usat", "usat16", "usax", @@ -341,6 +352,18 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) return DisassembleREV(opcode, insn); case OP_SEL: return DisassembleSEL(insn); + case OP_SMLAD: + case OP_SMLALD: + case OP_SMLSD: + case OP_SMLSLD: + case OP_SMMLA: + case OP_SMMLS: + case OP_SMMUL: + case OP_SMUAD: + case OP_SMUSD: + case OP_USAD8: + case OP_USADA8: + return DisassembleMediaMulDiv(opcode, insn); case OP_SSAT: case OP_SSAT16: case OP_USAT: @@ -503,6 +526,38 @@ std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); } +std::string ARM_Disasm::DisassembleMediaMulDiv(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t rd = BITS(insn, 16, 19); + uint32_t ra = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 8, 11); + uint32_t m = BIT(insn, 5); + uint32_t rn = BITS(insn, 0, 3); + + std::string cross = ""; + if (m) { + if (opcode == OP_SMMLA || opcode == OP_SMMUL || opcode == OP_SMMLS) + cross = "r"; + else + cross = "x"; + } + + std::string ext_reg = ""; + std::unordered_set> with_ext_reg = { + OP_SMLAD, OP_SMLSD, OP_SMMLA, OP_SMMLS, OP_USADA8 + }; + if (with_ext_reg.find(opcode) != with_ext_reg.end()) + ext_reg = Common::StringFromFormat(", r%u", ra); + + std::string rd_low = ""; + if (opcode == OP_SMLALD || opcode == OP_SMLSLD) + rd_low = Common::StringFromFormat("r%u, ", ra); + + return Common::StringFromFormat("%s%s%s\t%sr%u, r%u, r%u%s", opcode_names[opcode], + cross.c_str(), cond_to_str(cond), rd_low.c_str(), rd, rn, rm, + ext_reg.c_str()); +} + std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) { std::string tmp_list; @@ -1339,11 +1394,52 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) { return OP_MSR; } +Opcode ARM_Disasm::DecodeMediaMulDiv(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 22); + uint32_t op2_h = BITS(insn, 6, 7); + uint32_t a = BITS(insn, 12, 15); + + switch (op1) { + case 0x0: + if (op2_h == 0x0) { + if (a != 0xf) + return OP_SMLAD; + else + return OP_SMUAD; + } else if (op2_h == 0x1) { + if (a != 0xf) + return OP_SMLSD; + else + return OP_SMUSD; + } + break; + case 0x4: + if (op2_h == 0x0) + return OP_SMLALD; + else if (op2_h == 0x1) + return OP_SMLSLD; + break; + case 0x5: + if (op2_h == 0x0) { + if (a != 0xf) + return OP_SMMLA; + else + return OP_SMMUL; + } else if (op2_h == 0x3) { + return OP_SMMLS; + } + break; + default: + break; + } + + return OP_UNDEFINED; +} + Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { uint32_t op1 = BITS(insn, 20, 24); uint32_t rd = BITS(insn, 12, 15); uint32_t op2 = BITS(insn, 5, 7); - uint32_t rn = BITS(insn, 0, 3); switch (BITS(op1, 3, 4)) { case 0x0: @@ -1352,6 +1448,15 @@ Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { case 0x1: // Packing, unpacking, saturation, and reversal return DecodePackingSaturationReversal(insn); + case 0x2: + // Signed multiply, signed and unsigned divide + return DecodeMediaMulDiv(insn); + case 0x3: + if (op2 == 0 && rd == 0xf) + return OP_USAD8; + if (op2 == 0 && rd != 0xf) + return OP_USADA8; + break; default: break; } diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h index c1bd1b94..259a7786 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h @@ -73,8 +73,17 @@ enum Opcode { OP_SHSAX, OP_SHSUB16, OP_SHSUB8, + OP_SMLAD, OP_SMLAL, + OP_SMLALD, + OP_SMLSD, + OP_SMLSLD, + OP_SMMLA, + OP_SMMLS, + OP_SMMUL, + OP_SMUAD, OP_SMULL, + OP_SMUSD, OP_SSAT, OP_SSAT16, OP_SSAX, @@ -120,6 +129,8 @@ enum Opcode { OP_UQSAX, OP_UQSUB16, OP_UQSUB8, + OP_USAD8, + OP_USADA8, OP_USAT, OP_USAT16, OP_USAX, @@ -193,6 +204,7 @@ class ARM_Disasm { static Opcode DecodePackingSaturationReversal(uint32_t insn); static Opcode DecodeMUL(uint32_t insn); static Opcode DecodeMSRImmAndHints(uint32_t insn); + static Opcode DecodeMediaMulDiv(uint32_t insn); static Opcode DecodeMedia(uint32_t insn); static Opcode DecodeLDRH(uint32_t insn); static Opcode DecodeALU(uint32_t insn); @@ -202,6 +214,7 @@ class ARM_Disasm { static std::string DisassembleBX(uint32_t insn); static std::string DisassembleBKPT(uint32_t insn); static std::string DisassembleCLZ(uint32_t insn); + static std::string DisassembleMediaMulDiv(Opcode opcode, uint32_t insn); static std::string DisassembleMemblock(Opcode opcode, uint32_t insn); static std::string DisassembleMem(uint32_t insn); static std::string DisassembleMemHalf(uint32_t insn); -- cgit v1.2.3