diff options
| author | 2015-08-06 18:09:52 -0400 | |
|---|---|---|
| committer | 2015-08-06 18:09:52 -0400 | |
| commit | 482165224181c6c4c04bf3d42962d9caca2a814b (patch) | |
| tree | da545082e7f2c2e158f56f504ffa35e1fc986a48 /src/core/arm/disassembler | |
| parent | Merge pull request #1018 from bbarenblat/master (diff) | |
| parent | Disassembler: ARMv6K REX instructions (diff) | |
| download | yuzu-482165224181c6c4c04bf3d42962d9caca2a814b.tar.gz yuzu-482165224181c6c4c04bf3d42962d9caca2a814b.tar.xz yuzu-482165224181c6c4c04bf3d42962d9caca2a814b.zip | |
Merge pull request #1022 from aroulin/disas-missing-v6k-instructions
Disassembler: ARMv6K instructions
Diffstat (limited to 'src/core/arm/disassembler')
| -rw-r--r-- | src/core/arm/disassembler/arm_disasm.cpp | 141 | ||||
| -rw-r--r-- | src/core/arm/disassembler/arm_disasm.h | 18 |
2 files changed, 153 insertions, 6 deletions
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index f6d44d85a..8eec64d48 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/string_util.h" | 5 | #include "common/string_util.h" |
| 6 | #include "core/arm/disassembler/arm_disasm.h" | 6 | #include "core/arm/disassembler/arm_disasm.h" |
| 7 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 7 | 8 | ||
| 8 | static const char *cond_names[] = { | 9 | static const char *cond_names[] = { |
| 9 | "eq", | 10 | "eq", |
| @@ -37,6 +38,7 @@ static const char *opcode_names[] = { | |||
| 37 | "blx", | 38 | "blx", |
| 38 | "bx", | 39 | "bx", |
| 39 | "cdp", | 40 | "cdp", |
| 41 | "clrex", | ||
| 40 | "clz", | 42 | "clz", |
| 41 | "cmn", | 43 | "cmn", |
| 42 | "cmp", | 44 | "cmp", |
| @@ -46,6 +48,10 @@ static const char *opcode_names[] = { | |||
| 46 | "ldr", | 48 | "ldr", |
| 47 | "ldrb", | 49 | "ldrb", |
| 48 | "ldrbt", | 50 | "ldrbt", |
| 51 | "ldrex", | ||
| 52 | "ldrexb", | ||
| 53 | "ldrexd", | ||
| 54 | "ldrexh", | ||
| 49 | "ldrh", | 55 | "ldrh", |
| 50 | "ldrsb", | 56 | "ldrsb", |
| 51 | "ldrsh", | 57 | "ldrsh", |
| @@ -58,11 +64,13 @@ static const char *opcode_names[] = { | |||
| 58 | "msr", | 64 | "msr", |
| 59 | "mul", | 65 | "mul", |
| 60 | "mvn", | 66 | "mvn", |
| 67 | "nop", | ||
| 61 | "orr", | 68 | "orr", |
| 62 | "pld", | 69 | "pld", |
| 63 | "rsb", | 70 | "rsb", |
| 64 | "rsc", | 71 | "rsc", |
| 65 | "sbc", | 72 | "sbc", |
| 73 | "sev", | ||
| 66 | "smlal", | 74 | "smlal", |
| 67 | "smull", | 75 | "smull", |
| 68 | "stc", | 76 | "stc", |
| @@ -70,6 +78,10 @@ static const char *opcode_names[] = { | |||
| 70 | "str", | 78 | "str", |
| 71 | "strb", | 79 | "strb", |
| 72 | "strbt", | 80 | "strbt", |
| 81 | "strex", | ||
| 82 | "strexb", | ||
| 83 | "strexd", | ||
| 84 | "strexh", | ||
| 73 | "strh", | 85 | "strh", |
| 74 | "strt", | 86 | "strt", |
| 75 | "sub", | 87 | "sub", |
| @@ -80,6 +92,9 @@ static const char *opcode_names[] = { | |||
| 80 | "tst", | 92 | "tst", |
| 81 | "umlal", | 93 | "umlal", |
| 82 | "umull", | 94 | "umull", |
| 95 | "wfe", | ||
| 96 | "wfi", | ||
| 97 | "yield", | ||
| 83 | 98 | ||
| 84 | "undefined", | 99 | "undefined", |
| 85 | "adc", | 100 | "adc", |
| @@ -172,6 +187,8 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) | |||
| 172 | return DisassembleBX(insn); | 187 | return DisassembleBX(insn); |
| 173 | case OP_CDP: | 188 | case OP_CDP: |
| 174 | return "cdp"; | 189 | return "cdp"; |
| 190 | case OP_CLREX: | ||
| 191 | return "clrex"; | ||
| 175 | case OP_CLZ: | 192 | case OP_CLZ: |
| 176 | return DisassembleCLZ(insn); | 193 | return DisassembleCLZ(insn); |
| 177 | case OP_LDC: | 194 | case OP_LDC: |
| @@ -188,6 +205,15 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) | |||
| 188 | case OP_STRBT: | 205 | case OP_STRBT: |
| 189 | case OP_STRT: | 206 | case OP_STRT: |
| 190 | return DisassembleMem(insn); | 207 | return DisassembleMem(insn); |
| 208 | case OP_LDREX: | ||
| 209 | case OP_LDREXB: | ||
| 210 | case OP_LDREXD: | ||
| 211 | case OP_LDREXH: | ||
| 212 | case OP_STREX: | ||
| 213 | case OP_STREXB: | ||
| 214 | case OP_STREXD: | ||
| 215 | case OP_STREXH: | ||
| 216 | return DisassembleREX(opcode, insn); | ||
| 191 | case OP_LDRH: | 217 | case OP_LDRH: |
| 192 | case OP_LDRSB: | 218 | case OP_LDRSB: |
| 193 | case OP_LDRSH: | 219 | case OP_LDRSH: |
| @@ -204,6 +230,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) | |||
| 204 | return DisassembleMSR(insn); | 230 | return DisassembleMSR(insn); |
| 205 | case OP_MUL: | 231 | case OP_MUL: |
| 206 | return DisassembleMUL(opcode, insn); | 232 | return DisassembleMUL(opcode, insn); |
| 233 | case OP_NOP: | ||
| 234 | case OP_SEV: | ||
| 235 | case OP_WFE: | ||
| 236 | case OP_WFI: | ||
| 237 | case OP_YIELD: | ||
| 238 | return DisassembleNoOperands(opcode, insn); | ||
| 207 | case OP_PLD: | 239 | case OP_PLD: |
| 208 | return DisassemblePLD(insn); | 240 | return DisassemblePLD(insn); |
| 209 | case OP_STC: | 241 | case OP_STC: |
| @@ -646,6 +678,12 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn) | |||
| 646 | cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); | 678 | cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); |
| 647 | } | 679 | } |
| 648 | 680 | ||
| 681 | std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn) | ||
| 682 | { | ||
| 683 | uint32_t cond = BITS(insn, 28, 31); | ||
| 684 | return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); | ||
| 685 | } | ||
| 686 | |||
| 649 | std::string ARM_Disasm::DisassemblePLD(uint32_t insn) | 687 | std::string ARM_Disasm::DisassemblePLD(uint32_t insn) |
| 650 | { | 688 | { |
| 651 | uint8_t is_reg = (insn >> 25) & 0x1; | 689 | uint8_t is_reg = (insn >> 25) & 0x1; |
| @@ -669,6 +707,36 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn) | |||
| 669 | } | 707 | } |
| 670 | } | 708 | } |
| 671 | 709 | ||
| 710 | std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { | ||
| 711 | uint32_t rn = BITS(insn, 16, 19); | ||
| 712 | uint32_t rd = BITS(insn, 12, 15); | ||
| 713 | uint32_t rt = BITS(insn, 0, 3); | ||
| 714 | uint32_t cond = BITS(insn, 28, 31); | ||
| 715 | |||
| 716 | switch (opcode) { | ||
| 717 | case OP_STREX: | ||
| 718 | case OP_STREXB: | ||
| 719 | case OP_STREXH: | ||
| 720 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], | ||
| 721 | cond_to_str(cond), rd, rt, rn); | ||
| 722 | case OP_STREXD: | ||
| 723 | return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode], | ||
| 724 | cond_to_str(cond), rd, rt, rt + 1, rn); | ||
| 725 | |||
| 726 | // for LDREX instructions, rd corresponds to Rt from reference manual | ||
| 727 | case OP_LDREX: | ||
| 728 | case OP_LDREXB: | ||
| 729 | case OP_LDREXH: | ||
| 730 | return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode], | ||
| 731 | cond_to_str(cond), rd, rn); | ||
| 732 | case OP_LDREXD: | ||
| 733 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], | ||
| 734 | cond_to_str(cond), rd, rd + 1, rn); | ||
| 735 | default: | ||
| 736 | return opcode_names[OP_UNDEFINED]; | ||
| 737 | } | ||
| 738 | } | ||
| 739 | |||
| 672 | std::string ARM_Disasm::DisassembleSWI(uint32_t insn) | 740 | std::string ARM_Disasm::DisassembleSWI(uint32_t insn) |
| 673 | { | 741 | { |
| 674 | uint8_t cond = (insn >> 28) & 0xf; | 742 | uint8_t cond = (insn >> 28) & 0xf; |
| @@ -721,12 +789,9 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) { | |||
| 721 | } | 789 | } |
| 722 | uint32_t bits7_4 = (insn >> 4) & 0xf; | 790 | uint32_t bits7_4 = (insn >> 4) & 0xf; |
| 723 | if (bits7_4 == 0x9) { | 791 | if (bits7_4 == 0x9) { |
| 724 | if ((insn & 0x0ff00ff0) == 0x01000090) { | 792 | uint32_t bit24 = BIT(insn, 24); |
| 725 | // Swp instruction | 793 | if (bit24) { |
| 726 | uint8_t bit22 = (insn >> 22) & 0x1; | 794 | return DecodeSyncPrimitive(insn); |
| 727 | if (bit22) | ||
| 728 | return OP_SWPB; | ||
| 729 | return OP_SWP; | ||
| 730 | } | 795 | } |
| 731 | // One of the multiply instructions | 796 | // One of the multiply instructions |
| 732 | return DecodeMUL(insn); | 797 | return DecodeMUL(insn); |
| @@ -739,6 +804,12 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) { | |||
| 739 | } | 804 | } |
| 740 | } | 805 | } |
| 741 | 806 | ||
| 807 | uint32_t op1 = BITS(insn, 20, 24); | ||
| 808 | if (bit25 && (op1 == 0x12 || op1 == 0x16)) { | ||
| 809 | // One of the MSR (immediate) and hints instructions | ||
| 810 | return DecodeMSRImmAndHints(insn); | ||
| 811 | } | ||
| 812 | |||
| 742 | // One of the data processing instructions | 813 | // One of the data processing instructions |
| 743 | return DecodeALU(insn); | 814 | return DecodeALU(insn); |
| 744 | } | 815 | } |
| @@ -754,6 +825,10 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) { | |||
| 754 | // Pre-load | 825 | // Pre-load |
| 755 | return OP_PLD; | 826 | return OP_PLD; |
| 756 | } | 827 | } |
| 828 | if (insn == 0xf57ff01f) { | ||
| 829 | // Clear-Exclusive | ||
| 830 | return OP_CLREX; | ||
| 831 | } | ||
| 757 | if (is_load) { | 832 | if (is_load) { |
| 758 | if (is_byte) { | 833 | if (is_byte) { |
| 759 | // Load byte | 834 | // Load byte |
| @@ -844,6 +919,35 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) { | |||
| 844 | return OP_MCR; | 919 | return OP_MCR; |
| 845 | } | 920 | } |
| 846 | 921 | ||
| 922 | Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) { | ||
| 923 | uint32_t op = BITS(insn, 20, 23); | ||
| 924 | uint32_t bit22 = BIT(insn, 22); | ||
| 925 | switch (op) { | ||
| 926 | case 0x0: | ||
| 927 | if (bit22) | ||
| 928 | return OP_SWPB; | ||
| 929 | return OP_SWP; | ||
| 930 | case 0x8: | ||
| 931 | return OP_STREX; | ||
| 932 | case 0x9: | ||
| 933 | return OP_LDREX; | ||
| 934 | case 0xA: | ||
| 935 | return OP_STREXD; | ||
| 936 | case 0xB: | ||
| 937 | return OP_LDREXD; | ||
| 938 | case 0xC: | ||
| 939 | return OP_STREXB; | ||
| 940 | case 0xD: | ||
| 941 | return OP_LDREXB; | ||
| 942 | case 0xE: | ||
| 943 | return OP_STREXH; | ||
| 944 | case 0xF: | ||
| 945 | return OP_LDREXH; | ||
| 946 | default: | ||
| 947 | return OP_UNDEFINED; | ||
| 948 | } | ||
| 949 | } | ||
| 950 | |||
| 847 | Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { | 951 | Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { |
| 848 | uint8_t bit24 = (insn >> 24) & 0x1; | 952 | uint8_t bit24 = (insn >> 24) & 0x1; |
| 849 | if (bit24 != 0) { | 953 | if (bit24 != 0) { |
| @@ -878,6 +982,31 @@ Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { | |||
| 878 | return OP_SMLAL; | 982 | return OP_SMLAL; |
| 879 | } | 983 | } |
| 880 | 984 | ||
| 985 | Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) { | ||
| 986 | uint32_t op = BIT(insn, 22); | ||
| 987 | uint32_t op1 = BITS(insn, 16, 19); | ||
| 988 | uint32_t op2 = BITS(insn, 0, 7); | ||
| 989 | |||
| 990 | if (op == 0 && op1 == 0) { | ||
| 991 | switch (op2) { | ||
| 992 | case 0x0: | ||
| 993 | return OP_NOP; | ||
| 994 | case 0x1: | ||
| 995 | return OP_YIELD; | ||
| 996 | case 0x2: | ||
| 997 | return OP_WFE; | ||
| 998 | case 0x3: | ||
| 999 | return OP_WFI; | ||
| 1000 | case 0x4: | ||
| 1001 | return OP_SEV; | ||
| 1002 | default: | ||
| 1003 | return OP_UNDEFINED; | ||
| 1004 | } | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | return OP_MSR; | ||
| 1008 | } | ||
| 1009 | |||
| 881 | Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { | 1010 | Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { |
| 882 | uint8_t is_load = (insn >> 20) & 0x1; | 1011 | uint8_t is_load = (insn >> 20) & 0x1; |
| 883 | uint8_t bits_65 = (insn >> 5) & 0x3; | 1012 | 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 f94bd4669..d04fd21eb 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h | |||
| @@ -20,6 +20,7 @@ enum Opcode { | |||
| 20 | OP_BLX, | 20 | OP_BLX, |
| 21 | OP_BX, | 21 | OP_BX, |
| 22 | OP_CDP, | 22 | OP_CDP, |
| 23 | OP_CLREX, | ||
| 23 | OP_CLZ, | 24 | OP_CLZ, |
| 24 | OP_CMN, | 25 | OP_CMN, |
| 25 | OP_CMP, | 26 | OP_CMP, |
| @@ -29,6 +30,10 @@ enum Opcode { | |||
| 29 | OP_LDR, | 30 | OP_LDR, |
| 30 | OP_LDRB, | 31 | OP_LDRB, |
| 31 | OP_LDRBT, | 32 | OP_LDRBT, |
| 33 | OP_LDREX, | ||
| 34 | OP_LDREXB, | ||
| 35 | OP_LDREXD, | ||
| 36 | OP_LDREXH, | ||
| 32 | OP_LDRH, | 37 | OP_LDRH, |
| 33 | OP_LDRSB, | 38 | OP_LDRSB, |
| 34 | OP_LDRSH, | 39 | OP_LDRSH, |
| @@ -41,11 +46,13 @@ enum Opcode { | |||
| 41 | OP_MSR, | 46 | OP_MSR, |
| 42 | OP_MUL, | 47 | OP_MUL, |
| 43 | OP_MVN, | 48 | OP_MVN, |
| 49 | OP_NOP, | ||
| 44 | OP_ORR, | 50 | OP_ORR, |
| 45 | OP_PLD, | 51 | OP_PLD, |
| 46 | OP_RSB, | 52 | OP_RSB, |
| 47 | OP_RSC, | 53 | OP_RSC, |
| 48 | OP_SBC, | 54 | OP_SBC, |
| 55 | OP_SEV, | ||
| 49 | OP_SMLAL, | 56 | OP_SMLAL, |
| 50 | OP_SMULL, | 57 | OP_SMULL, |
| 51 | OP_STC, | 58 | OP_STC, |
| @@ -53,6 +60,10 @@ enum Opcode { | |||
| 53 | OP_STR, | 60 | OP_STR, |
| 54 | OP_STRB, | 61 | OP_STRB, |
| 55 | OP_STRBT, | 62 | OP_STRBT, |
| 63 | OP_STREX, | ||
| 64 | OP_STREXB, | ||
| 65 | OP_STREXD, | ||
| 66 | OP_STREXH, | ||
| 56 | OP_STRH, | 67 | OP_STRH, |
| 57 | OP_STRT, | 68 | OP_STRT, |
| 58 | OP_SUB, | 69 | OP_SUB, |
| @@ -63,6 +74,9 @@ enum Opcode { | |||
| 63 | OP_TST, | 74 | OP_TST, |
| 64 | OP_UMLAL, | 75 | OP_UMLAL, |
| 65 | OP_UMULL, | 76 | OP_UMULL, |
| 77 | OP_WFE, | ||
| 78 | OP_WFI, | ||
| 79 | OP_YIELD, | ||
| 66 | 80 | ||
| 67 | // Define thumb opcodes | 81 | // Define thumb opcodes |
| 68 | OP_THUMB_UNDEFINED, | 82 | OP_THUMB_UNDEFINED, |
| @@ -117,7 +131,9 @@ class ARM_Disasm { | |||
| 117 | static Opcode Decode01(uint32_t insn); | 131 | static Opcode Decode01(uint32_t insn); |
| 118 | static Opcode Decode10(uint32_t insn); | 132 | static Opcode Decode10(uint32_t insn); |
| 119 | static Opcode Decode11(uint32_t insn); | 133 | static Opcode Decode11(uint32_t insn); |
| 134 | static Opcode DecodeSyncPrimitive(uint32_t insn); | ||
| 120 | static Opcode DecodeMUL(uint32_t insn); | 135 | static Opcode DecodeMUL(uint32_t insn); |
| 136 | static Opcode DecodeMSRImmAndHints(uint32_t insn); | ||
| 121 | static Opcode DecodeLDRH(uint32_t insn); | 137 | static Opcode DecodeLDRH(uint32_t insn); |
| 122 | static Opcode DecodeALU(uint32_t insn); | 138 | static Opcode DecodeALU(uint32_t insn); |
| 123 | 139 | ||
| @@ -135,7 +151,9 @@ class ARM_Disasm { | |||
| 135 | static std::string DisassembleMUL(Opcode opcode, uint32_t insn); | 151 | static std::string DisassembleMUL(Opcode opcode, uint32_t insn); |
| 136 | static std::string DisassembleMRS(uint32_t insn); | 152 | static std::string DisassembleMRS(uint32_t insn); |
| 137 | static std::string DisassembleMSR(uint32_t insn); | 153 | static std::string DisassembleMSR(uint32_t insn); |
| 154 | static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); | ||
| 138 | static std::string DisassemblePLD(uint32_t insn); | 155 | static std::string DisassemblePLD(uint32_t insn); |
| 156 | static std::string DisassembleREX(Opcode opcode, uint32_t insn); | ||
| 139 | static std::string DisassembleSWI(uint32_t insn); | 157 | static std::string DisassembleSWI(uint32_t insn); |
| 140 | static std::string DisassembleSWP(Opcode opcode, uint32_t insn); | 158 | static std::string DisassembleSWP(Opcode opcode, uint32_t insn); |
| 141 | }; | 159 | }; |