diff options
| author | 2015-08-07 10:10:35 +0200 | |
|---|---|---|
| committer | 2015-08-09 01:31:03 +0200 | |
| commit | 47657a18179c6dc3bf5fa573fd60381cbffcd9e7 (patch) | |
| tree | 7cb492b330fb85618f11d1c5bd7ee8f4073154d2 /src/core/arm/disassembler | |
| parent | Merge pull request #1026 from lioncash/disasm (diff) | |
| download | yuzu-47657a18179c6dc3bf5fa573fd60381cbffcd9e7.tar.gz yuzu-47657a18179c6dc3bf5fa573fd60381cbffcd9e7.tar.xz yuzu-47657a18179c6dc3bf5fa573fd60381cbffcd9e7.zip | |
arm_disasm: ARMv6 packing and sign-extend media instructions
PKH, SEL
SXTAB, SXTAB16, SXTB, SXTB16, SXTH, SXTAH
UXTAB, UXTAB16, UXTB, UXTB16, UXTH, UXTAH
Diffstat (limited to 'src/core/arm/disassembler')
| -rw-r--r-- | src/core/arm/disassembler/arm_disasm.cpp | 163 | ||||
| -rw-r--r-- | src/core/arm/disassembler/arm_disasm.h | 19 |
2 files changed, 181 insertions, 1 deletions
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 964e30112..3ac867949 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // Copyright 2006 The Android Open Source Project | 1 | // Copyright 2006 The Android Open Source Project |
| 2 | 2 | ||
| 3 | #include <string> | 3 | #include <string> |
| 4 | #include <unordered_set> | ||
| 4 | 5 | ||
| 5 | #include "common/string_util.h" | 6 | #include "common/string_util.h" |
| 6 | #include "core/arm/disassembler/arm_disasm.h" | 7 | #include "core/arm/disassembler/arm_disasm.h" |
| @@ -66,10 +67,12 @@ static const char *opcode_names[] = { | |||
| 66 | "mvn", | 67 | "mvn", |
| 67 | "nop", | 68 | "nop", |
| 68 | "orr", | 69 | "orr", |
| 70 | "pkh", | ||
| 69 | "pld", | 71 | "pld", |
| 70 | "rsb", | 72 | "rsb", |
| 71 | "rsc", | 73 | "rsc", |
| 72 | "sbc", | 74 | "sbc", |
| 75 | "sel", | ||
| 73 | "sev", | 76 | "sev", |
| 74 | "smlal", | 77 | "smlal", |
| 75 | "smull", | 78 | "smull", |
| @@ -88,10 +91,22 @@ static const char *opcode_names[] = { | |||
| 88 | "swi", | 91 | "swi", |
| 89 | "swp", | 92 | "swp", |
| 90 | "swpb", | 93 | "swpb", |
| 94 | "sxtab", | ||
| 95 | "sxtab16", | ||
| 96 | "sxtah", | ||
| 97 | "sxtb", | ||
| 98 | "sxtb16", | ||
| 99 | "sxth", | ||
| 91 | "teq", | 100 | "teq", |
| 92 | "tst", | 101 | "tst", |
| 93 | "umlal", | 102 | "umlal", |
| 94 | "umull", | 103 | "umull", |
| 104 | "uxtab", | ||
| 105 | "uxtab16", | ||
| 106 | "uxtah", | ||
| 107 | "uxtb", | ||
| 108 | "uxtb16", | ||
| 109 | "uxth", | ||
| 95 | "wfe", | 110 | "wfe", |
| 96 | "wfi", | 111 | "wfi", |
| 97 | "yield", | 112 | "yield", |
| @@ -236,8 +251,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) | |||
| 236 | case OP_WFI: | 251 | case OP_WFI: |
| 237 | case OP_YIELD: | 252 | case OP_YIELD: |
| 238 | return DisassembleNoOperands(opcode, insn); | 253 | return DisassembleNoOperands(opcode, insn); |
| 254 | case OP_PKH: | ||
| 255 | return DisassemblePKH(insn); | ||
| 239 | case OP_PLD: | 256 | case OP_PLD: |
| 240 | return DisassemblePLD(insn); | 257 | return DisassemblePLD(insn); |
| 258 | case OP_SEL: | ||
| 259 | return DisassembleSEL(insn); | ||
| 241 | case OP_STC: | 260 | case OP_STC: |
| 242 | return "stc"; | 261 | return "stc"; |
| 243 | case OP_SWI: | 262 | case OP_SWI: |
| @@ -245,6 +264,19 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) | |||
| 245 | case OP_SWP: | 264 | case OP_SWP: |
| 246 | case OP_SWPB: | 265 | case OP_SWPB: |
| 247 | return DisassembleSWP(opcode, insn); | 266 | return DisassembleSWP(opcode, insn); |
| 267 | case OP_SXTAB: | ||
| 268 | case OP_SXTAB16: | ||
| 269 | case OP_SXTAH: | ||
| 270 | case OP_SXTB: | ||
| 271 | case OP_SXTB16: | ||
| 272 | case OP_SXTH: | ||
| 273 | case OP_UXTAB: | ||
| 274 | case OP_UXTAB16: | ||
| 275 | case OP_UXTAH: | ||
| 276 | case OP_UXTB: | ||
| 277 | case OP_UXTB16: | ||
| 278 | case OP_UXTH: | ||
| 279 | return DisassembleXT(opcode, insn); | ||
| 248 | case OP_UMLAL: | 280 | case OP_UMLAL: |
| 249 | case OP_UMULL: | 281 | case OP_UMULL: |
| 250 | case OP_SMLAL: | 282 | case OP_SMLAL: |
| @@ -684,6 +716,30 @@ std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn) | |||
| 684 | return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); | 716 | return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); |
| 685 | } | 717 | } |
| 686 | 718 | ||
| 719 | std::string ARM_Disasm::DisassemblePKH(uint32_t insn) | ||
| 720 | { | ||
| 721 | uint32_t cond = BITS(insn, 28, 31); | ||
| 722 | uint32_t rn = BITS(insn, 16, 19); | ||
| 723 | uint32_t rd = BITS(insn, 12, 15); | ||
| 724 | uint32_t imm5 = BITS(insn, 7, 11); | ||
| 725 | uint32_t tb = BIT(insn, 6); | ||
| 726 | uint32_t rm = BITS(insn, 0, 3); | ||
| 727 | |||
| 728 | std::string suffix = tb ? "tb" : "bt"; | ||
| 729 | std::string shift = ""; | ||
| 730 | |||
| 731 | if (tb && imm5 == 0) | ||
| 732 | imm5 = 32; | ||
| 733 | |||
| 734 | if (imm5 > 0) { | ||
| 735 | shift = tb ? ", ASR" : ", LSL"; | ||
| 736 | shift += " #" + std::to_string(imm5); | ||
| 737 | } | ||
| 738 | |||
| 739 | return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond), | ||
| 740 | rd, rn, rm, shift.c_str()); | ||
| 741 | } | ||
| 742 | |||
| 687 | std::string ARM_Disasm::DisassemblePLD(uint32_t insn) | 743 | std::string ARM_Disasm::DisassemblePLD(uint32_t insn) |
| 688 | { | 744 | { |
| 689 | uint8_t is_reg = (insn >> 25) & 0x1; | 745 | uint8_t is_reg = (insn >> 25) & 0x1; |
| @@ -737,6 +793,17 @@ std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { | |||
| 737 | } | 793 | } |
| 738 | } | 794 | } |
| 739 | 795 | ||
| 796 | std::string ARM_Disasm::DisassembleSEL(uint32_t insn) | ||
| 797 | { | ||
| 798 | uint32_t cond = BITS(insn, 28, 31); | ||
| 799 | uint32_t rn = BITS(insn, 16, 19); | ||
| 800 | uint32_t rd = BITS(insn, 12, 15); | ||
| 801 | uint32_t rm = BITS(insn, 0, 3); | ||
| 802 | |||
| 803 | return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[OP_SEL], cond_to_str(cond), | ||
| 804 | rd, rn, rm); | ||
| 805 | } | ||
| 806 | |||
| 740 | std::string ARM_Disasm::DisassembleSWI(uint32_t insn) | 807 | std::string ARM_Disasm::DisassembleSWI(uint32_t insn) |
| 741 | { | 808 | { |
| 742 | uint8_t cond = (insn >> 28) & 0xf; | 809 | uint8_t cond = (insn >> 28) & 0xf; |
| @@ -756,6 +823,30 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) | |||
| 756 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); | 823 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); |
| 757 | } | 824 | } |
| 758 | 825 | ||
| 826 | std::string ARM_Disasm::DisassembleXT(Opcode opcode, uint32_t insn) | ||
| 827 | { | ||
| 828 | uint32_t cond = BITS(insn, 28, 31); | ||
| 829 | uint32_t rn = BITS(insn, 16, 19); | ||
| 830 | uint32_t rd = BITS(insn, 12, 15); | ||
| 831 | uint32_t rotate = BITS(insn, 10, 11); | ||
| 832 | uint32_t rm = BITS(insn, 0, 3); | ||
| 833 | |||
| 834 | std::string rn_part = ""; | ||
| 835 | static std::unordered_set<Opcode, std::hash<int>> extend_with_add = { | ||
| 836 | OP_SXTAB, OP_SXTAB16, OP_SXTAH, | ||
| 837 | OP_UXTAB, OP_UXTAB16, OP_UXTAH | ||
| 838 | }; | ||
| 839 | if (extend_with_add.find(opcode) != extend_with_add.end()) | ||
| 840 | rn_part = ", r" + std::to_string(rn); | ||
| 841 | |||
| 842 | std::string rotate_part = ""; | ||
| 843 | if (rotate != 0) | ||
| 844 | rotate_part = ", ROR #" + std::to_string(rotate << 3); | ||
| 845 | |||
| 846 | return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond), | ||
| 847 | rd, rn_part.c_str(), rm, rotate_part.c_str()); | ||
| 848 | } | ||
| 849 | |||
| 759 | Opcode ARM_Disasm::Decode(uint32_t insn) { | 850 | Opcode ARM_Disasm::Decode(uint32_t insn) { |
| 760 | uint32_t bits27_26 = (insn >> 26) & 0x3; | 851 | uint32_t bits27_26 = (insn >> 26) & 0x3; |
| 761 | switch (bits27_26) { | 852 | switch (bits27_26) { |
| @@ -818,7 +909,7 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) { | |||
| 818 | uint8_t is_reg = (insn >> 25) & 0x1; | 909 | uint8_t is_reg = (insn >> 25) & 0x1; |
| 819 | uint8_t bit4 = (insn >> 4) & 0x1; | 910 | uint8_t bit4 = (insn >> 4) & 0x1; |
| 820 | if (is_reg == 1 && bit4 == 1) | 911 | if (is_reg == 1 && bit4 == 1) |
| 821 | return OP_UNDEFINED; | 912 | return DecodeMedia(insn); |
| 822 | uint8_t is_load = (insn >> 20) & 0x1; | 913 | uint8_t is_load = (insn >> 20) & 0x1; |
| 823 | uint8_t is_byte = (insn >> 22) & 0x1; | 914 | uint8_t is_byte = (insn >> 22) & 0x1; |
| 824 | if ((insn & 0xfd70f000) == 0xf550f000) { | 915 | if ((insn & 0xfd70f000) == 0xf550f000) { |
| @@ -940,6 +1031,59 @@ Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) { | |||
| 940 | } | 1031 | } |
| 941 | } | 1032 | } |
| 942 | 1033 | ||
| 1034 | Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { | ||
| 1035 | uint32_t op1 = BITS(insn, 20, 22); | ||
| 1036 | uint32_t a = BITS(insn, 16, 19); | ||
| 1037 | uint32_t op2 = BITS(insn, 5, 7); | ||
| 1038 | |||
| 1039 | switch (op1) { | ||
| 1040 | case 0x0: | ||
| 1041 | if (BIT(op2, 0) == 0) | ||
| 1042 | return OP_PKH; | ||
| 1043 | if (op2 == 0x3 && a != 0xf) | ||
| 1044 | return OP_SXTAB16; | ||
| 1045 | if (op2 == 0x3 && a == 0xf) | ||
| 1046 | return OP_SXTB16; | ||
| 1047 | if (op2 == 0x5) | ||
| 1048 | return OP_SEL; | ||
| 1049 | break; | ||
| 1050 | case 0x2: | ||
| 1051 | if (op2 == 0x3 && a != 0xf) | ||
| 1052 | return OP_SXTAB; | ||
| 1053 | if (op2 == 0x3 && a == 0xf) | ||
| 1054 | return OP_SXTB; | ||
| 1055 | break; | ||
| 1056 | case 0x3: | ||
| 1057 | if (op2 == 0x3 && a != 0xf) | ||
| 1058 | return OP_SXTAH; | ||
| 1059 | if (op2 == 0x3 && a == 0xf) | ||
| 1060 | return OP_SXTH; | ||
| 1061 | break; | ||
| 1062 | case 0x4: | ||
| 1063 | if (op2 == 0x3 && a != 0xf) | ||
| 1064 | return OP_UXTAB16; | ||
| 1065 | if (op2 == 0x3 && a == 0xf) | ||
| 1066 | return OP_UXTB16; | ||
| 1067 | break; | ||
| 1068 | case 0x6: | ||
| 1069 | if (op2 == 0x3 && a != 0xf) | ||
| 1070 | return OP_UXTAB; | ||
| 1071 | if (op2 == 0x3 && a == 0xf) | ||
| 1072 | return OP_UXTB; | ||
| 1073 | break; | ||
| 1074 | case 0x7: | ||
| 1075 | if (op2 == 0x3 && a != 0xf) | ||
| 1076 | return OP_UXTAH; | ||
| 1077 | if (op2 == 0x3 && a == 0xf) | ||
| 1078 | return OP_UXTH; | ||
| 1079 | break; | ||
| 1080 | default: | ||
| 1081 | break; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | return OP_UNDEFINED; | ||
| 1085 | } | ||
| 1086 | |||
| 943 | Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { | 1087 | Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { |
| 944 | uint8_t bit24 = (insn >> 24) & 0x1; | 1088 | uint8_t bit24 = (insn >> 24) & 0x1; |
| 945 | if (bit24 != 0) { | 1089 | if (bit24 != 0) { |
| @@ -999,6 +1143,23 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) { | |||
| 999 | return OP_MSR; | 1143 | return OP_MSR; |
| 1000 | } | 1144 | } |
| 1001 | 1145 | ||
| 1146 | Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { | ||
| 1147 | uint32_t op1 = BITS(insn, 20, 24); | ||
| 1148 | uint32_t rd = BITS(insn, 12, 15); | ||
| 1149 | uint32_t op2 = BITS(insn, 5, 7); | ||
| 1150 | uint32_t rn = BITS(insn, 0, 3); | ||
| 1151 | |||
| 1152 | switch (BITS(op1, 3, 4)) { | ||
| 1153 | case 0x1: | ||
| 1154 | // Packing, unpacking, saturation, and reversal | ||
| 1155 | return DecodePackingSaturationReversal(insn); | ||
| 1156 | default: | ||
| 1157 | break; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | return OP_UNDEFINED; | ||
| 1161 | } | ||
| 1162 | |||
| 1002 | Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { | 1163 | Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { |
| 1003 | uint8_t is_load = (insn >> 20) & 0x1; | 1164 | uint8_t is_load = (insn >> 20) & 0x1; |
| 1004 | uint8_t bits_65 = (insn >> 5) & 0x3; | 1165 | 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 d04fd21eb..20e92fd0e 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h | |||
| @@ -48,10 +48,12 @@ enum Opcode { | |||
| 48 | OP_MVN, | 48 | OP_MVN, |
| 49 | OP_NOP, | 49 | OP_NOP, |
| 50 | OP_ORR, | 50 | OP_ORR, |
| 51 | OP_PKH, | ||
| 51 | OP_PLD, | 52 | OP_PLD, |
| 52 | OP_RSB, | 53 | OP_RSB, |
| 53 | OP_RSC, | 54 | OP_RSC, |
| 54 | OP_SBC, | 55 | OP_SBC, |
| 56 | OP_SEL, | ||
| 55 | OP_SEV, | 57 | OP_SEV, |
| 56 | OP_SMLAL, | 58 | OP_SMLAL, |
| 57 | OP_SMULL, | 59 | OP_SMULL, |
| @@ -70,10 +72,22 @@ enum Opcode { | |||
| 70 | OP_SWI, | 72 | OP_SWI, |
| 71 | OP_SWP, | 73 | OP_SWP, |
| 72 | OP_SWPB, | 74 | OP_SWPB, |
| 75 | OP_SXTAB, | ||
| 76 | OP_SXTAB16, | ||
| 77 | OP_SXTAH, | ||
| 78 | OP_SXTB, | ||
| 79 | OP_SXTB16, | ||
| 80 | OP_SXTH, | ||
| 73 | OP_TEQ, | 81 | OP_TEQ, |
| 74 | OP_TST, | 82 | OP_TST, |
| 75 | OP_UMLAL, | 83 | OP_UMLAL, |
| 76 | OP_UMULL, | 84 | OP_UMULL, |
| 85 | OP_UXTAB, | ||
| 86 | OP_UXTAB16, | ||
| 87 | OP_UXTAH, | ||
| 88 | OP_UXTB, | ||
| 89 | OP_UXTB16, | ||
| 90 | OP_UXTH, | ||
| 77 | OP_WFE, | 91 | OP_WFE, |
| 78 | OP_WFI, | 92 | OP_WFI, |
| 79 | OP_YIELD, | 93 | OP_YIELD, |
| @@ -132,8 +146,10 @@ class ARM_Disasm { | |||
| 132 | static Opcode Decode10(uint32_t insn); | 146 | static Opcode Decode10(uint32_t insn); |
| 133 | static Opcode Decode11(uint32_t insn); | 147 | static Opcode Decode11(uint32_t insn); |
| 134 | static Opcode DecodeSyncPrimitive(uint32_t insn); | 148 | static Opcode DecodeSyncPrimitive(uint32_t insn); |
| 149 | static Opcode DecodePackingSaturationReversal(uint32_t insn); | ||
| 135 | static Opcode DecodeMUL(uint32_t insn); | 150 | static Opcode DecodeMUL(uint32_t insn); |
| 136 | static Opcode DecodeMSRImmAndHints(uint32_t insn); | 151 | static Opcode DecodeMSRImmAndHints(uint32_t insn); |
| 152 | static Opcode DecodeMedia(uint32_t insn); | ||
| 137 | static Opcode DecodeLDRH(uint32_t insn); | 153 | static Opcode DecodeLDRH(uint32_t insn); |
| 138 | static Opcode DecodeALU(uint32_t insn); | 154 | static Opcode DecodeALU(uint32_t insn); |
| 139 | 155 | ||
| @@ -152,8 +168,11 @@ class ARM_Disasm { | |||
| 152 | static std::string DisassembleMRS(uint32_t insn); | 168 | static std::string DisassembleMRS(uint32_t insn); |
| 153 | static std::string DisassembleMSR(uint32_t insn); | 169 | static std::string DisassembleMSR(uint32_t insn); |
| 154 | static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); | 170 | static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); |
| 171 | static std::string DisassemblePKH(uint32_t insn); | ||
| 155 | static std::string DisassemblePLD(uint32_t insn); | 172 | static std::string DisassemblePLD(uint32_t insn); |
| 156 | static std::string DisassembleREX(Opcode opcode, uint32_t insn); | 173 | static std::string DisassembleREX(Opcode opcode, uint32_t insn); |
| 174 | static std::string DisassembleSEL(uint32_t insn); | ||
| 157 | static std::string DisassembleSWI(uint32_t insn); | 175 | static std::string DisassembleSWI(uint32_t insn); |
| 158 | static std::string DisassembleSWP(Opcode opcode, uint32_t insn); | 176 | static std::string DisassembleSWP(Opcode opcode, uint32_t insn); |
| 177 | static std::string DisassembleXT(Opcode opcode, uint32_t insn); | ||
| 159 | }; | 178 | }; |