diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/arm/disassembler/arm_disasm.cpp | 1344 | ||||
| -rw-r--r-- | src/core/arm/disassembler/arm_disasm.h | 238 | ||||
| -rw-r--r-- | src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 7 |
4 files changed, 2 insertions, 1589 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 190dc985a..e404063f0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | arm/disassembler/arm_disasm.cpp | ||
| 3 | arm/dynarmic/arm_dynarmic.cpp | 2 | arm/dynarmic/arm_dynarmic.cpp |
| 4 | arm/dynarmic/arm_dynarmic_cp15.cpp | 3 | arm/dynarmic/arm_dynarmic_cp15.cpp |
| 5 | arm/dyncom/arm_dyncom.cpp | 4 | arm/dyncom/arm_dyncom.cpp |
| @@ -178,7 +177,6 @@ set(SRCS | |||
| 178 | 177 | ||
| 179 | set(HEADERS | 178 | set(HEADERS |
| 180 | arm/arm_interface.h | 179 | arm/arm_interface.h |
| 181 | arm/disassembler/arm_disasm.h | ||
| 182 | arm/dynarmic/arm_dynarmic.h | 180 | arm/dynarmic/arm_dynarmic.h |
| 183 | arm/dynarmic/arm_dynarmic_cp15.h | 181 | arm/dynarmic/arm_dynarmic_cp15.h |
| 184 | arm/dyncom/arm_dyncom.h | 182 | arm/dyncom/arm_dyncom.h |
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp deleted file mode 100644 index 05d6ed1fb..000000000 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ /dev/null | |||
| @@ -1,1344 +0,0 @@ | |||
| 1 | // Copyright 2006 The Android Open Source Project | ||
| 2 | |||
| 3 | #include <string> | ||
| 4 | #include <unordered_set> | ||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "common/string_util.h" | ||
| 7 | #include "core/arm/disassembler/arm_disasm.h" | ||
| 8 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 9 | |||
| 10 | static const char* cond_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", | ||
| 11 | "hi", "ls", "ge", "lt", "gt", "le", "", "RESERVED"}; | ||
| 12 | |||
| 13 | static const char* opcode_names[] = { | ||
| 14 | "invalid", "undefined", "adc", "add", "and", "b", "bl", "bic", | ||
| 15 | "bkpt", "blx", "bx", "cdp", "clrex", "clz", "cmn", "cmp", | ||
| 16 | "eor", "ldc", "ldm", "ldr", "ldrb", "ldrbt", "ldrex", "ldrexb", | ||
| 17 | "ldrexd", "ldrexh", "ldrh", "ldrsb", "ldrsh", "ldrt", "mcr", "mla", | ||
| 18 | "mov", "mrc", "mrs", "msr", "mul", "mvn", "nop", "orr", | ||
| 19 | "pkh", "pld", "qadd16", "qadd8", "qasx", "qsax", "qsub16", "qsub8", | ||
| 20 | "rev", "rev16", "revsh", "rsb", "rsc", "sadd16", "sadd8", "sasx", | ||
| 21 | "sbc", "sel", "sev", "shadd16", "shadd8", "shasx", "shsax", "shsub16", | ||
| 22 | "shsub8", "smlad", "smlal", "smlald", "smlsd", "smlsld", "smmla", "smmls", | ||
| 23 | "smmul", "smuad", "smull", "smusd", "ssat", "ssat16", "ssax", "ssub16", | ||
| 24 | "ssub8", "stc", "stm", "str", "strb", "strbt", "strex", "strexb", | ||
| 25 | "strexd", "strexh", "strh", "strt", "sub", "swi", "swp", "swpb", | ||
| 26 | "sxtab", "sxtab16", "sxtah", "sxtb", "sxtb16", "sxth", "teq", "tst", | ||
| 27 | "uadd16", "uadd8", "uasx", "uhadd16", "uhadd8", "uhasx", "uhsax", "uhsub16", | ||
| 28 | "uhsub8", "umlal", "umull", "uqadd16", "uqadd8", "uqasx", "uqsax", "uqsub16", | ||
| 29 | "uqsub8", "usad8", "usada8", "usat", "usat16", "usax", "usub16", "usub8", | ||
| 30 | "uxtab", "uxtab16", "uxtah", "uxtb", "uxtb16", "uxth", "wfe", "wfi", | ||
| 31 | "yield", | ||
| 32 | |||
| 33 | "undefined", "adc", "add", "and", "asr", "b", "bic", "bkpt", | ||
| 34 | "bl", "blx", "bx", "cmn", "cmp", "eor", "ldmia", "ldr", | ||
| 35 | "ldrb", "ldrh", "ldrsb", "ldrsh", "lsl", "lsr", "mov", "mul", | ||
| 36 | "mvn", "neg", "orr", "pop", "push", "ror", "sbc", "stmia", | ||
| 37 | "str", "strb", "strh", "sub", "swi", "tst", | ||
| 38 | |||
| 39 | nullptr}; | ||
| 40 | |||
| 41 | // Indexed by the shift type (bits 6-5) | ||
| 42 | static const char* shift_names[] = {"LSL", "LSR", "ASR", "ROR"}; | ||
| 43 | |||
| 44 | static const char* cond_to_str(u32 cond) { | ||
| 45 | return cond_names[cond]; | ||
| 46 | } | ||
| 47 | |||
| 48 | std::string ARM_Disasm::Disassemble(u32 addr, u32 insn) { | ||
| 49 | Opcode opcode = Decode(insn); | ||
| 50 | switch (opcode) { | ||
| 51 | case OP_INVALID: | ||
| 52 | return "Invalid"; | ||
| 53 | case OP_UNDEFINED: | ||
| 54 | return "Undefined"; | ||
| 55 | case OP_ADC: | ||
| 56 | case OP_ADD: | ||
| 57 | case OP_AND: | ||
| 58 | case OP_BIC: | ||
| 59 | case OP_CMN: | ||
| 60 | case OP_CMP: | ||
| 61 | case OP_EOR: | ||
| 62 | case OP_MOV: | ||
| 63 | case OP_MVN: | ||
| 64 | case OP_ORR: | ||
| 65 | case OP_RSB: | ||
| 66 | case OP_RSC: | ||
| 67 | case OP_SBC: | ||
| 68 | case OP_SUB: | ||
| 69 | case OP_TEQ: | ||
| 70 | case OP_TST: | ||
| 71 | return DisassembleALU(opcode, insn); | ||
| 72 | case OP_B: | ||
| 73 | case OP_BL: | ||
| 74 | return DisassembleBranch(addr, opcode, insn); | ||
| 75 | case OP_BKPT: | ||
| 76 | return DisassembleBKPT(insn); | ||
| 77 | case OP_BLX: | ||
| 78 | // not supported yet | ||
| 79 | break; | ||
| 80 | case OP_BX: | ||
| 81 | return DisassembleBX(insn); | ||
| 82 | case OP_CDP: | ||
| 83 | return "cdp"; | ||
| 84 | case OP_CLREX: | ||
| 85 | return "clrex"; | ||
| 86 | case OP_CLZ: | ||
| 87 | return DisassembleCLZ(insn); | ||
| 88 | case OP_LDC: | ||
| 89 | return "ldc"; | ||
| 90 | case OP_LDM: | ||
| 91 | case OP_STM: | ||
| 92 | return DisassembleMemblock(opcode, insn); | ||
| 93 | case OP_LDR: | ||
| 94 | case OP_LDRB: | ||
| 95 | case OP_LDRBT: | ||
| 96 | case OP_LDRT: | ||
| 97 | case OP_STR: | ||
| 98 | case OP_STRB: | ||
| 99 | case OP_STRBT: | ||
| 100 | case OP_STRT: | ||
| 101 | return DisassembleMem(insn); | ||
| 102 | case OP_LDREX: | ||
| 103 | case OP_LDREXB: | ||
| 104 | case OP_LDREXD: | ||
| 105 | case OP_LDREXH: | ||
| 106 | case OP_STREX: | ||
| 107 | case OP_STREXB: | ||
| 108 | case OP_STREXD: | ||
| 109 | case OP_STREXH: | ||
| 110 | return DisassembleREX(opcode, insn); | ||
| 111 | case OP_LDRH: | ||
| 112 | case OP_LDRSB: | ||
| 113 | case OP_LDRSH: | ||
| 114 | case OP_STRH: | ||
| 115 | return DisassembleMemHalf(insn); | ||
| 116 | case OP_MCR: | ||
| 117 | case OP_MRC: | ||
| 118 | return DisassembleMCR(opcode, insn); | ||
| 119 | case OP_MLA: | ||
| 120 | return DisassembleMLA(opcode, insn); | ||
| 121 | case OP_MRS: | ||
| 122 | return DisassembleMRS(insn); | ||
| 123 | case OP_MSR: | ||
| 124 | return DisassembleMSR(insn); | ||
| 125 | case OP_MUL: | ||
| 126 | return DisassembleMUL(opcode, insn); | ||
| 127 | case OP_NOP: | ||
| 128 | case OP_SEV: | ||
| 129 | case OP_WFE: | ||
| 130 | case OP_WFI: | ||
| 131 | case OP_YIELD: | ||
| 132 | return DisassembleNoOperands(opcode, insn); | ||
| 133 | case OP_PKH: | ||
| 134 | return DisassemblePKH(insn); | ||
| 135 | case OP_PLD: | ||
| 136 | return DisassemblePLD(insn); | ||
| 137 | case OP_QADD16: | ||
| 138 | case OP_QADD8: | ||
| 139 | case OP_QASX: | ||
| 140 | case OP_QSAX: | ||
| 141 | case OP_QSUB16: | ||
| 142 | case OP_QSUB8: | ||
| 143 | case OP_SADD16: | ||
| 144 | case OP_SADD8: | ||
| 145 | case OP_SASX: | ||
| 146 | case OP_SHADD16: | ||
| 147 | case OP_SHADD8: | ||
| 148 | case OP_SHASX: | ||
| 149 | case OP_SHSAX: | ||
| 150 | case OP_SHSUB16: | ||
| 151 | case OP_SHSUB8: | ||
| 152 | case OP_SSAX: | ||
| 153 | case OP_SSUB16: | ||
| 154 | case OP_SSUB8: | ||
| 155 | case OP_UADD16: | ||
| 156 | case OP_UADD8: | ||
| 157 | case OP_UASX: | ||
| 158 | case OP_UHADD16: | ||
| 159 | case OP_UHADD8: | ||
| 160 | case OP_UHASX: | ||
| 161 | case OP_UHSAX: | ||
| 162 | case OP_UHSUB16: | ||
| 163 | case OP_UHSUB8: | ||
| 164 | case OP_UQADD16: | ||
| 165 | case OP_UQADD8: | ||
| 166 | case OP_UQASX: | ||
| 167 | case OP_UQSAX: | ||
| 168 | case OP_UQSUB16: | ||
| 169 | case OP_UQSUB8: | ||
| 170 | case OP_USAX: | ||
| 171 | case OP_USUB16: | ||
| 172 | case OP_USUB8: | ||
| 173 | return DisassembleParallelAddSub(opcode, insn); | ||
| 174 | case OP_REV: | ||
| 175 | case OP_REV16: | ||
| 176 | case OP_REVSH: | ||
| 177 | return DisassembleREV(opcode, insn); | ||
| 178 | case OP_SEL: | ||
| 179 | return DisassembleSEL(insn); | ||
| 180 | case OP_SMLAD: | ||
| 181 | case OP_SMLALD: | ||
| 182 | case OP_SMLSD: | ||
| 183 | case OP_SMLSLD: | ||
| 184 | case OP_SMMLA: | ||
| 185 | case OP_SMMLS: | ||
| 186 | case OP_SMMUL: | ||
| 187 | case OP_SMUAD: | ||
| 188 | case OP_SMUSD: | ||
| 189 | case OP_USAD8: | ||
| 190 | case OP_USADA8: | ||
| 191 | return DisassembleMediaMulDiv(opcode, insn); | ||
| 192 | case OP_SSAT: | ||
| 193 | case OP_SSAT16: | ||
| 194 | case OP_USAT: | ||
| 195 | case OP_USAT16: | ||
| 196 | return DisassembleSAT(opcode, insn); | ||
| 197 | case OP_STC: | ||
| 198 | return "stc"; | ||
| 199 | case OP_SWI: | ||
| 200 | return DisassembleSWI(insn); | ||
| 201 | case OP_SWP: | ||
| 202 | case OP_SWPB: | ||
| 203 | return DisassembleSWP(opcode, insn); | ||
| 204 | case OP_SXTAB: | ||
| 205 | case OP_SXTAB16: | ||
| 206 | case OP_SXTAH: | ||
| 207 | case OP_SXTB: | ||
| 208 | case OP_SXTB16: | ||
| 209 | case OP_SXTH: | ||
| 210 | case OP_UXTAB: | ||
| 211 | case OP_UXTAB16: | ||
| 212 | case OP_UXTAH: | ||
| 213 | case OP_UXTB: | ||
| 214 | case OP_UXTB16: | ||
| 215 | case OP_UXTH: | ||
| 216 | return DisassembleXT(opcode, insn); | ||
| 217 | case OP_UMLAL: | ||
| 218 | case OP_UMULL: | ||
| 219 | case OP_SMLAL: | ||
| 220 | case OP_SMULL: | ||
| 221 | return DisassembleUMLAL(opcode, insn); | ||
| 222 | default: | ||
| 223 | return "Error"; | ||
| 224 | } | ||
| 225 | return nullptr; | ||
| 226 | } | ||
| 227 | |||
| 228 | std::string ARM_Disasm::DisassembleALU(Opcode opcode, u32 insn) { | ||
| 229 | static const u8 kNoOperand1 = 1; | ||
| 230 | static const u8 kNoDest = 2; | ||
| 231 | static const u8 kNoSbit = 4; | ||
| 232 | |||
| 233 | std::string rn_str; | ||
| 234 | std::string rd_str; | ||
| 235 | |||
| 236 | u8 flags = 0; | ||
| 237 | u8 cond = (insn >> 28) & 0xf; | ||
| 238 | u8 is_immed = (insn >> 25) & 0x1; | ||
| 239 | u8 bit_s = (insn >> 20) & 1; | ||
| 240 | u8 rn = (insn >> 16) & 0xf; | ||
| 241 | u8 rd = (insn >> 12) & 0xf; | ||
| 242 | u8 immed = insn & 0xff; | ||
| 243 | |||
| 244 | const char* opname = opcode_names[opcode]; | ||
| 245 | switch (opcode) { | ||
| 246 | case OP_CMN: | ||
| 247 | case OP_CMP: | ||
| 248 | case OP_TEQ: | ||
| 249 | case OP_TST: | ||
| 250 | flags = kNoDest | kNoSbit; | ||
| 251 | break; | ||
| 252 | case OP_MOV: | ||
| 253 | case OP_MVN: | ||
| 254 | flags = kNoOperand1; | ||
| 255 | break; | ||
| 256 | default: | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | |||
| 260 | // The "mov" instruction ignores the first operand (rn). | ||
| 261 | rn_str[0] = 0; | ||
| 262 | if ((flags & kNoOperand1) == 0) { | ||
| 263 | rn_str = Common::StringFromFormat("r%d, ", rn); | ||
| 264 | } | ||
| 265 | |||
| 266 | // The following instructions do not write the result register (rd): | ||
| 267 | // tst, teq, cmp, cmn. | ||
| 268 | rd_str[0] = 0; | ||
| 269 | if ((flags & kNoDest) == 0) { | ||
| 270 | rd_str = Common::StringFromFormat("r%d, ", rd); | ||
| 271 | } | ||
| 272 | |||
| 273 | const char* sbit_str = ""; | ||
| 274 | if (bit_s && !(flags & kNoSbit)) | ||
| 275 | sbit_str = "s"; | ||
| 276 | |||
| 277 | if (is_immed) { | ||
| 278 | return Common::StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", opname, cond_to_str(cond), | ||
| 279 | sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed); | ||
| 280 | } | ||
| 281 | |||
| 282 | u8 shift_is_reg = (insn >> 4) & 1; | ||
| 283 | u8 rotate = (insn >> 8) & 0xf; | ||
| 284 | u8 rm = insn & 0xf; | ||
| 285 | u8 shift_type = (insn >> 5) & 0x3; | ||
| 286 | u8 rs = (insn >> 8) & 0xf; | ||
| 287 | u8 shift_amount = (insn >> 7) & 0x1f; | ||
| 288 | u32 rotated_val = immed; | ||
| 289 | u8 rotate2 = rotate << 1; | ||
| 290 | rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); | ||
| 291 | |||
| 292 | if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { | ||
| 293 | return Common::StringFromFormat("%s%s%s\t%s%sr%d", opname, cond_to_str(cond), sbit_str, | ||
| 294 | rd_str.c_str(), rn_str.c_str(), rm); | ||
| 295 | } | ||
| 296 | |||
| 297 | const char* shift_name = shift_names[shift_type]; | ||
| 298 | if (shift_is_reg) { | ||
| 299 | return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", opname, cond_to_str(cond), | ||
| 300 | sbit_str, rd_str.c_str(), rn_str.c_str(), rm, shift_name, | ||
| 301 | rs); | ||
| 302 | } | ||
| 303 | if (shift_amount == 0) { | ||
| 304 | if (shift_type == 3) { | ||
| 305 | return Common::StringFromFormat("%s%s%s\t%s%sr%d, RRX", opname, cond_to_str(cond), | ||
| 306 | sbit_str, rd_str.c_str(), rn_str.c_str(), rm); | ||
| 307 | } | ||
| 308 | shift_amount = 32; | ||
| 309 | } | ||
| 310 | return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", opname, cond_to_str(cond), sbit_str, | ||
| 311 | rd_str.c_str(), rn_str.c_str(), rm, shift_name, shift_amount); | ||
| 312 | } | ||
| 313 | |||
| 314 | std::string ARM_Disasm::DisassembleBranch(u32 addr, Opcode opcode, u32 insn) { | ||
| 315 | u8 cond = (insn >> 28) & 0xf; | ||
| 316 | u32 offset = insn & 0xffffff; | ||
| 317 | // Sign-extend the 24-bit offset | ||
| 318 | if ((offset >> 23) & 1) | ||
| 319 | offset |= 0xff000000; | ||
| 320 | |||
| 321 | // Pre-compute the left-shift and the prefetch offset | ||
| 322 | offset <<= 2; | ||
| 323 | offset += 8; | ||
| 324 | addr += offset; | ||
| 325 | const char* opname = opcode_names[opcode]; | ||
| 326 | return Common::StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); | ||
| 327 | } | ||
| 328 | |||
| 329 | std::string ARM_Disasm::DisassembleBX(u32 insn) { | ||
| 330 | u8 cond = (insn >> 28) & 0xf; | ||
| 331 | u8 rn = insn & 0xf; | ||
| 332 | return Common::StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); | ||
| 333 | } | ||
| 334 | |||
| 335 | std::string ARM_Disasm::DisassembleBKPT(u32 insn) { | ||
| 336 | u8 cond = (insn >> 28) & 0xf; | ||
| 337 | u32 immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); | ||
| 338 | return Common::StringFromFormat("bkpt%s\t#%d", cond_to_str(cond), immed); | ||
| 339 | } | ||
| 340 | |||
| 341 | std::string ARM_Disasm::DisassembleCLZ(u32 insn) { | ||
| 342 | u8 cond = (insn >> 28) & 0xf; | ||
| 343 | u8 rd = (insn >> 12) & 0xf; | ||
| 344 | u8 rm = insn & 0xf; | ||
| 345 | return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); | ||
| 346 | } | ||
| 347 | |||
| 348 | std::string ARM_Disasm::DisassembleMediaMulDiv(Opcode opcode, u32 insn) { | ||
| 349 | u32 cond = BITS(insn, 28, 31); | ||
| 350 | u32 rd = BITS(insn, 16, 19); | ||
| 351 | u32 ra = BITS(insn, 12, 15); | ||
| 352 | u32 rm = BITS(insn, 8, 11); | ||
| 353 | u32 m = BIT(insn, 5); | ||
| 354 | u32 rn = BITS(insn, 0, 3); | ||
| 355 | |||
| 356 | std::string cross = ""; | ||
| 357 | if (m) { | ||
| 358 | if (opcode == OP_SMMLA || opcode == OP_SMMUL || opcode == OP_SMMLS) | ||
| 359 | cross = "r"; | ||
| 360 | else | ||
| 361 | cross = "x"; | ||
| 362 | } | ||
| 363 | |||
| 364 | std::string ext_reg = ""; | ||
| 365 | std::unordered_set<Opcode, std::hash<int>> with_ext_reg = {OP_SMLAD, OP_SMLSD, OP_SMMLA, | ||
| 366 | OP_SMMLS, OP_USADA8}; | ||
| 367 | if (with_ext_reg.find(opcode) != with_ext_reg.end()) | ||
| 368 | ext_reg = Common::StringFromFormat(", r%u", ra); | ||
| 369 | |||
| 370 | std::string rd_low = ""; | ||
| 371 | if (opcode == OP_SMLALD || opcode == OP_SMLSLD) | ||
| 372 | rd_low = Common::StringFromFormat("r%u, ", ra); | ||
| 373 | |||
| 374 | return Common::StringFromFormat("%s%s%s\t%sr%u, r%u, r%u%s", opcode_names[opcode], | ||
| 375 | cross.c_str(), cond_to_str(cond), rd_low.c_str(), rd, rn, rm, | ||
| 376 | ext_reg.c_str()); | ||
| 377 | } | ||
| 378 | |||
| 379 | std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, u32 insn) { | ||
| 380 | std::string tmp_list; | ||
| 381 | |||
| 382 | u8 cond = (insn >> 28) & 0xf; | ||
| 383 | u8 write_back = (insn >> 21) & 0x1; | ||
| 384 | u8 bit_s = (insn >> 22) & 0x1; | ||
| 385 | u8 is_up = (insn >> 23) & 0x1; | ||
| 386 | u8 is_pre = (insn >> 24) & 0x1; | ||
| 387 | u8 rn = (insn >> 16) & 0xf; | ||
| 388 | u16 reg_list = insn & 0xffff; | ||
| 389 | |||
| 390 | const char* opname = opcode_names[opcode]; | ||
| 391 | |||
| 392 | const char* bang = ""; | ||
| 393 | if (write_back) | ||
| 394 | bang = "!"; | ||
| 395 | |||
| 396 | const char* carret = ""; | ||
| 397 | if (bit_s) | ||
| 398 | carret = "^"; | ||
| 399 | |||
| 400 | const char* comma = ""; | ||
| 401 | tmp_list[0] = 0; | ||
| 402 | for (int ii = 0; ii < 16; ++ii) { | ||
| 403 | if (reg_list & (1 << ii)) { | ||
| 404 | tmp_list += Common::StringFromFormat("%sr%d", comma, ii); | ||
| 405 | comma = ","; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | const char* addr_mode = ""; | ||
| 410 | if (is_pre) { | ||
| 411 | if (is_up) { | ||
| 412 | addr_mode = "ib"; | ||
| 413 | } else { | ||
| 414 | addr_mode = "db"; | ||
| 415 | } | ||
| 416 | } else { | ||
| 417 | if (is_up) { | ||
| 418 | addr_mode = "ia"; | ||
| 419 | } else { | ||
| 420 | addr_mode = "da"; | ||
| 421 | } | ||
| 422 | } | ||
| 423 | |||
| 424 | return Common::StringFromFormat("%s%s%s\tr%d%s, {%s}%s", opname, cond_to_str(cond), addr_mode, | ||
| 425 | rn, bang, tmp_list.c_str(), carret); | ||
| 426 | } | ||
| 427 | |||
| 428 | std::string ARM_Disasm::DisassembleMem(u32 insn) { | ||
| 429 | u8 cond = (insn >> 28) & 0xf; | ||
| 430 | u8 is_reg = (insn >> 25) & 0x1; | ||
| 431 | u8 is_load = (insn >> 20) & 0x1; | ||
| 432 | u8 write_back = (insn >> 21) & 0x1; | ||
| 433 | u8 is_byte = (insn >> 22) & 0x1; | ||
| 434 | u8 is_up = (insn >> 23) & 0x1; | ||
| 435 | u8 is_pre = (insn >> 24) & 0x1; | ||
| 436 | u8 rn = (insn >> 16) & 0xf; | ||
| 437 | u8 rd = (insn >> 12) & 0xf; | ||
| 438 | u16 offset = insn & 0xfff; | ||
| 439 | |||
| 440 | const char* opname = "ldr"; | ||
| 441 | if (!is_load) | ||
| 442 | opname = "str"; | ||
| 443 | |||
| 444 | const char* bang = ""; | ||
| 445 | if (write_back) | ||
| 446 | bang = "!"; | ||
| 447 | |||
| 448 | const char* minus = ""; | ||
| 449 | if (is_up == 0) | ||
| 450 | minus = "-"; | ||
| 451 | |||
| 452 | const char* byte = ""; | ||
| 453 | if (is_byte) | ||
| 454 | byte = "b"; | ||
| 455 | |||
| 456 | if (is_reg == 0) { | ||
| 457 | if (is_pre) { | ||
| 458 | if (offset == 0) { | ||
| 459 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), | ||
| 460 | byte, rd, rn); | ||
| 461 | } else { | ||
| 462 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", opname, | ||
| 463 | cond_to_str(cond), byte, rd, rn, minus, offset, | ||
| 464 | bang); | ||
| 465 | } | ||
| 466 | } else { | ||
| 467 | const char* transfer = ""; | ||
| 468 | if (write_back) | ||
| 469 | transfer = "t"; | ||
| 470 | |||
| 471 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", opname, | ||
| 472 | cond_to_str(cond), byte, transfer, rd, rn, minus, | ||
| 473 | offset); | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | u8 rm = insn & 0xf; | ||
| 478 | u8 shift_type = (insn >> 5) & 0x3; | ||
| 479 | u8 shift_amount = (insn >> 7) & 0x1f; | ||
| 480 | |||
| 481 | const char* shift_name = shift_names[shift_type]; | ||
| 482 | |||
| 483 | if (is_pre) { | ||
| 484 | if (shift_amount == 0) { | ||
| 485 | if (shift_type == 0) { | ||
| 486 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", opname, | ||
| 487 | cond_to_str(cond), byte, rd, rn, minus, rm, bang); | ||
| 488 | } | ||
| 489 | if (shift_type == 3) { | ||
| 490 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", opname, | ||
| 491 | cond_to_str(cond), byte, rd, rn, minus, rm, bang); | ||
| 492 | } | ||
| 493 | shift_amount = 32; | ||
| 494 | } | ||
| 495 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", opname, | ||
| 496 | cond_to_str(cond), byte, rd, rn, minus, rm, shift_name, | ||
| 497 | shift_amount, bang); | ||
| 498 | } | ||
| 499 | |||
| 500 | const char* transfer = ""; | ||
| 501 | if (write_back) | ||
| 502 | transfer = "t"; | ||
| 503 | |||
| 504 | if (shift_amount == 0) { | ||
| 505 | if (shift_type == 0) { | ||
| 506 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", opname, | ||
| 507 | cond_to_str(cond), byte, transfer, rd, rn, minus, rm); | ||
| 508 | } | ||
| 509 | if (shift_type == 3) { | ||
| 510 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", opname, | ||
| 511 | cond_to_str(cond), byte, transfer, rd, rn, minus, rm); | ||
| 512 | } | ||
| 513 | shift_amount = 32; | ||
| 514 | } | ||
| 515 | |||
| 516 | return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", opname, | ||
| 517 | cond_to_str(cond), byte, transfer, rd, rn, minus, rm, | ||
| 518 | shift_name, shift_amount); | ||
| 519 | } | ||
| 520 | |||
| 521 | std::string ARM_Disasm::DisassembleMemHalf(u32 insn) { | ||
| 522 | u8 cond = (insn >> 28) & 0xf; | ||
| 523 | u8 is_load = (insn >> 20) & 0x1; | ||
| 524 | u8 write_back = (insn >> 21) & 0x1; | ||
| 525 | u8 is_immed = (insn >> 22) & 0x1; | ||
| 526 | u8 is_up = (insn >> 23) & 0x1; | ||
| 527 | u8 is_pre = (insn >> 24) & 0x1; | ||
| 528 | u8 rn = (insn >> 16) & 0xf; | ||
| 529 | u8 rd = (insn >> 12) & 0xf; | ||
| 530 | u8 bits_65 = (insn >> 5) & 0x3; | ||
| 531 | u8 rm = insn & 0xf; | ||
| 532 | u8 offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf); | ||
| 533 | |||
| 534 | const char* opname = "ldr"; | ||
| 535 | if (is_load == 0) | ||
| 536 | opname = "str"; | ||
| 537 | |||
| 538 | const char* width = ""; | ||
| 539 | if (bits_65 == 1) | ||
| 540 | width = "h"; | ||
| 541 | else if (bits_65 == 2) | ||
| 542 | width = "sb"; | ||
| 543 | else | ||
| 544 | width = "sh"; | ||
| 545 | |||
| 546 | const char* bang = ""; | ||
| 547 | if (write_back) | ||
| 548 | bang = "!"; | ||
| 549 | const char* minus = ""; | ||
| 550 | if (is_up == 0) | ||
| 551 | minus = "-"; | ||
| 552 | |||
| 553 | if (is_immed) { | ||
| 554 | if (is_pre) { | ||
| 555 | if (offset == 0) { | ||
| 556 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), | ||
| 557 | width, rd, rn); | ||
| 558 | } else { | ||
| 559 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", opname, | ||
| 560 | cond_to_str(cond), width, rd, rn, minus, offset, | ||
| 561 | bang); | ||
| 562 | } | ||
| 563 | } else { | ||
| 564 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d], #%s%u", opname, cond_to_str(cond), | ||
| 565 | width, rd, rn, minus, offset); | ||
| 566 | } | ||
| 567 | } | ||
| 568 | |||
| 569 | if (is_pre) { | ||
| 570 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", opname, cond_to_str(cond), | ||
| 571 | width, rd, rn, minus, rm, bang); | ||
| 572 | } else { | ||
| 573 | return Common::StringFromFormat("%s%s%s\tr%d, [r%d], %sr%d", opname, cond_to_str(cond), | ||
| 574 | width, rd, rn, minus, rm); | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | std::string ARM_Disasm::DisassembleMCR(Opcode opcode, u32 insn) { | ||
| 579 | u8 cond = (insn >> 28) & 0xf; | ||
| 580 | u8 crn = (insn >> 16) & 0xf; | ||
| 581 | u8 crd = (insn >> 12) & 0xf; | ||
| 582 | u8 cpnum = (insn >> 8) & 0xf; | ||
| 583 | u8 opcode2 = (insn >> 5) & 0x7; | ||
| 584 | u8 crm = insn & 0xf; | ||
| 585 | |||
| 586 | const char* opname = opcode_names[opcode]; | ||
| 587 | return Common::StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", opname, cond_to_str(cond), | ||
| 588 | cpnum, crd, crn, crm, opcode2); | ||
| 589 | } | ||
| 590 | |||
| 591 | std::string ARM_Disasm::DisassembleMLA(Opcode opcode, u32 insn) { | ||
| 592 | u8 cond = (insn >> 28) & 0xf; | ||
| 593 | u8 rd = (insn >> 16) & 0xf; | ||
| 594 | u8 rn = (insn >> 12) & 0xf; | ||
| 595 | u8 rs = (insn >> 8) & 0xf; | ||
| 596 | u8 rm = insn & 0xf; | ||
| 597 | u8 bit_s = (insn >> 20) & 1; | ||
| 598 | |||
| 599 | const char* opname = opcode_names[opcode]; | ||
| 600 | return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), | ||
| 601 | bit_s ? "s" : "", rd, rm, rs, rn); | ||
| 602 | } | ||
| 603 | |||
| 604 | std::string ARM_Disasm::DisassembleUMLAL(Opcode opcode, u32 insn) { | ||
| 605 | u8 cond = (insn >> 28) & 0xf; | ||
| 606 | u8 rdhi = (insn >> 16) & 0xf; | ||
| 607 | u8 rdlo = (insn >> 12) & 0xf; | ||
| 608 | u8 rs = (insn >> 8) & 0xf; | ||
| 609 | u8 rm = insn & 0xf; | ||
| 610 | u8 bit_s = (insn >> 20) & 1; | ||
| 611 | |||
| 612 | const char* opname = opcode_names[opcode]; | ||
| 613 | return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), | ||
| 614 | bit_s ? "s" : "", rdlo, rdhi, rm, rs); | ||
| 615 | } | ||
| 616 | |||
| 617 | std::string ARM_Disasm::DisassembleMUL(Opcode opcode, u32 insn) { | ||
| 618 | u8 cond = (insn >> 28) & 0xf; | ||
| 619 | u8 rd = (insn >> 16) & 0xf; | ||
| 620 | u8 rs = (insn >> 8) & 0xf; | ||
| 621 | u8 rm = insn & 0xf; | ||
| 622 | u8 bit_s = (insn >> 20) & 1; | ||
| 623 | |||
| 624 | const char* opname = opcode_names[opcode]; | ||
| 625 | return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d", opname, cond_to_str(cond), | ||
| 626 | bit_s ? "s" : "", rd, rm, rs); | ||
| 627 | } | ||
| 628 | |||
| 629 | std::string ARM_Disasm::DisassembleMRS(u32 insn) { | ||
| 630 | u8 cond = (insn >> 28) & 0xf; | ||
| 631 | u8 rd = (insn >> 12) & 0xf; | ||
| 632 | u8 ps = (insn >> 22) & 1; | ||
| 633 | |||
| 634 | return Common::StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); | ||
| 635 | } | ||
| 636 | |||
| 637 | std::string ARM_Disasm::DisassembleMSR(u32 insn) { | ||
| 638 | char flags[8]; | ||
| 639 | int flag_index = 0; | ||
| 640 | u8 cond = (insn >> 28) & 0xf; | ||
| 641 | u8 is_immed = (insn >> 25) & 0x1; | ||
| 642 | u8 pd = (insn >> 22) & 1; | ||
| 643 | u8 mask = (insn >> 16) & 0xf; | ||
| 644 | |||
| 645 | if (mask & 1) | ||
| 646 | flags[flag_index++] = 'c'; | ||
| 647 | if (mask & 2) | ||
| 648 | flags[flag_index++] = 'x'; | ||
| 649 | if (mask & 4) | ||
| 650 | flags[flag_index++] = 's'; | ||
| 651 | if (mask & 8) | ||
| 652 | flags[flag_index++] = 'f'; | ||
| 653 | flags[flag_index] = 0; | ||
| 654 | |||
| 655 | if (is_immed) { | ||
| 656 | u32 immed = insn & 0xff; | ||
| 657 | u8 rotate = (insn >> 8) & 0xf; | ||
| 658 | u8 rotate2 = rotate << 1; | ||
| 659 | u32 rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); | ||
| 660 | return Common::StringFromFormat("msr%s\t%s_%s, #0x%x", cond_to_str(cond), | ||
| 661 | pd ? "spsr" : "cpsr", flags, rotated_val); | ||
| 662 | } | ||
| 663 | |||
| 664 | u8 rm = insn & 0xf; | ||
| 665 | |||
| 666 | return Common::StringFromFormat("msr%s\t%s_%s, r%d", cond_to_str(cond), pd ? "spsr" : "cpsr", | ||
| 667 | flags, rm); | ||
| 668 | } | ||
| 669 | |||
| 670 | std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, u32 insn) { | ||
| 671 | u32 cond = BITS(insn, 28, 31); | ||
| 672 | return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); | ||
| 673 | } | ||
| 674 | |||
| 675 | std::string ARM_Disasm::DisassembleParallelAddSub(Opcode opcode, u32 insn) { | ||
| 676 | u32 cond = BITS(insn, 28, 31); | ||
| 677 | u32 rn = BITS(insn, 16, 19); | ||
| 678 | u32 rd = BITS(insn, 12, 15); | ||
| 679 | u32 rm = BITS(insn, 0, 3); | ||
| 680 | |||
| 681 | return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[opcode], cond_to_str(cond), | ||
| 682 | rd, rn, rm); | ||
| 683 | } | ||
| 684 | |||
| 685 | std::string ARM_Disasm::DisassemblePKH(u32 insn) { | ||
| 686 | u32 cond = BITS(insn, 28, 31); | ||
| 687 | u32 rn = BITS(insn, 16, 19); | ||
| 688 | u32 rd = BITS(insn, 12, 15); | ||
| 689 | u32 imm5 = BITS(insn, 7, 11); | ||
| 690 | u32 tb = BIT(insn, 6); | ||
| 691 | u32 rm = BITS(insn, 0, 3); | ||
| 692 | |||
| 693 | std::string suffix = tb ? "tb" : "bt"; | ||
| 694 | std::string shift = ""; | ||
| 695 | |||
| 696 | if (tb && imm5 == 0) | ||
| 697 | imm5 = 32; | ||
| 698 | |||
| 699 | if (imm5 > 0) { | ||
| 700 | shift = tb ? ", ASR" : ", LSL"; | ||
| 701 | shift += " #" + std::to_string(imm5); | ||
| 702 | } | ||
| 703 | |||
| 704 | return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond), | ||
| 705 | rd, rn, rm, shift.c_str()); | ||
| 706 | } | ||
| 707 | |||
| 708 | std::string ARM_Disasm::DisassemblePLD(u32 insn) { | ||
| 709 | u8 is_reg = (insn >> 25) & 0x1; | ||
| 710 | u8 is_up = (insn >> 23) & 0x1; | ||
| 711 | u8 rn = (insn >> 16) & 0xf; | ||
| 712 | |||
| 713 | const char* minus = ""; | ||
| 714 | if (is_up == 0) | ||
| 715 | minus = "-"; | ||
| 716 | |||
| 717 | if (is_reg) { | ||
| 718 | u8 rm = insn & 0xf; | ||
| 719 | return Common::StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); | ||
| 720 | } | ||
| 721 | |||
| 722 | u16 offset = insn & 0xfff; | ||
| 723 | if (offset == 0) { | ||
| 724 | return Common::StringFromFormat("pld\t[r%d]", rn); | ||
| 725 | } else { | ||
| 726 | return Common::StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); | ||
| 727 | } | ||
| 728 | } | ||
| 729 | |||
| 730 | std::string ARM_Disasm::DisassembleREV(Opcode opcode, u32 insn) { | ||
| 731 | u32 cond = BITS(insn, 28, 31); | ||
| 732 | u32 rd = BITS(insn, 12, 15); | ||
| 733 | u32 rm = BITS(insn, 0, 3); | ||
| 734 | |||
| 735 | return Common::StringFromFormat("%s%s\tr%u, r%u", opcode_names[opcode], cond_to_str(cond), rd, | ||
| 736 | rm); | ||
| 737 | } | ||
| 738 | |||
| 739 | std::string ARM_Disasm::DisassembleREX(Opcode opcode, u32 insn) { | ||
| 740 | u32 rn = BITS(insn, 16, 19); | ||
| 741 | u32 rd = BITS(insn, 12, 15); | ||
| 742 | u32 rt = BITS(insn, 0, 3); | ||
| 743 | u32 cond = BITS(insn, 28, 31); | ||
| 744 | |||
| 745 | switch (opcode) { | ||
| 746 | case OP_STREX: | ||
| 747 | case OP_STREXB: | ||
| 748 | case OP_STREXH: | ||
| 749 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], | ||
| 750 | cond_to_str(cond), rd, rt, rn); | ||
| 751 | case OP_STREXD: | ||
| 752 | return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode], | ||
| 753 | cond_to_str(cond), rd, rt, rt + 1, rn); | ||
| 754 | |||
| 755 | // for LDREX instructions, rd corresponds to Rt from reference manual | ||
| 756 | case OP_LDREX: | ||
| 757 | case OP_LDREXB: | ||
| 758 | case OP_LDREXH: | ||
| 759 | return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode], cond_to_str(cond), | ||
| 760 | rd, rn); | ||
| 761 | case OP_LDREXD: | ||
| 762 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], | ||
| 763 | cond_to_str(cond), rd, rd + 1, rn); | ||
| 764 | default: | ||
| 765 | return opcode_names[OP_UNDEFINED]; | ||
| 766 | } | ||
| 767 | } | ||
| 768 | |||
| 769 | std::string ARM_Disasm::DisassembleSAT(Opcode opcode, u32 insn) { | ||
| 770 | u32 cond = BITS(insn, 28, 31); | ||
| 771 | u32 sat_imm = BITS(insn, 16, 20); | ||
| 772 | u32 rd = BITS(insn, 12, 15); | ||
| 773 | u32 imm5 = BITS(insn, 7, 11); | ||
| 774 | u32 sh = BIT(insn, 6); | ||
| 775 | u32 rn = BITS(insn, 0, 3); | ||
| 776 | |||
| 777 | std::string shift_part = ""; | ||
| 778 | bool opcode_has_shift = (opcode == OP_SSAT) || (opcode == OP_USAT); | ||
| 779 | if (opcode_has_shift && !(sh == 0 && imm5 == 0)) { | ||
| 780 | if (sh == 0) | ||
| 781 | shift_part += ", LSL #"; | ||
| 782 | else | ||
| 783 | shift_part += ", ASR #"; | ||
| 784 | |||
| 785 | if (imm5 == 0) | ||
| 786 | imm5 = 32; | ||
| 787 | shift_part += std::to_string(imm5); | ||
| 788 | } | ||
| 789 | |||
| 790 | if (opcode == OP_SSAT || opcode == OP_SSAT16) | ||
| 791 | sat_imm++; | ||
| 792 | |||
| 793 | return Common::StringFromFormat("%s%s\tr%u, #%u, r%u%s", opcode_names[opcode], | ||
| 794 | cond_to_str(cond), rd, sat_imm, rn, shift_part.c_str()); | ||
| 795 | } | ||
| 796 | |||
| 797 | std::string ARM_Disasm::DisassembleSEL(u32 insn) { | ||
| 798 | u32 cond = BITS(insn, 28, 31); | ||
| 799 | u32 rn = BITS(insn, 16, 19); | ||
| 800 | u32 rd = BITS(insn, 12, 15); | ||
| 801 | u32 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 | |||
| 807 | std::string ARM_Disasm::DisassembleSWI(u32 insn) { | ||
| 808 | u8 cond = (insn >> 28) & 0xf; | ||
| 809 | u32 sysnum = insn & 0x00ffffff; | ||
| 810 | |||
| 811 | return Common::StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); | ||
| 812 | } | ||
| 813 | |||
| 814 | std::string ARM_Disasm::DisassembleSWP(Opcode opcode, u32 insn) { | ||
| 815 | u8 cond = (insn >> 28) & 0xf; | ||
| 816 | u8 rn = (insn >> 16) & 0xf; | ||
| 817 | u8 rd = (insn >> 12) & 0xf; | ||
| 818 | u8 rm = insn & 0xf; | ||
| 819 | |||
| 820 | const char* opname = opcode_names[opcode]; | ||
| 821 | return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); | ||
| 822 | } | ||
| 823 | |||
| 824 | std::string ARM_Disasm::DisassembleXT(Opcode opcode, u32 insn) { | ||
| 825 | u32 cond = BITS(insn, 28, 31); | ||
| 826 | u32 rn = BITS(insn, 16, 19); | ||
| 827 | u32 rd = BITS(insn, 12, 15); | ||
| 828 | u32 rotate = BITS(insn, 10, 11); | ||
| 829 | u32 rm = BITS(insn, 0, 3); | ||
| 830 | |||
| 831 | std::string rn_part = ""; | ||
| 832 | static std::unordered_set<Opcode, std::hash<int>> extend_with_add = { | ||
| 833 | OP_SXTAB, OP_SXTAB16, OP_SXTAH, OP_UXTAB, OP_UXTAB16, OP_UXTAH}; | ||
| 834 | if (extend_with_add.find(opcode) != extend_with_add.end()) | ||
| 835 | rn_part = ", r" + std::to_string(rn); | ||
| 836 | |||
| 837 | std::string rotate_part = ""; | ||
| 838 | if (rotate != 0) | ||
| 839 | rotate_part = ", ROR #" + std::to_string(rotate << 3); | ||
| 840 | |||
| 841 | return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond), | ||
| 842 | rd, rn_part.c_str(), rm, rotate_part.c_str()); | ||
| 843 | } | ||
| 844 | |||
| 845 | Opcode ARM_Disasm::Decode(u32 insn) { | ||
| 846 | u32 bits27_26 = (insn >> 26) & 0x3; | ||
| 847 | switch (bits27_26) { | ||
| 848 | case 0x0: | ||
| 849 | return Decode00(insn); | ||
| 850 | case 0x1: | ||
| 851 | return Decode01(insn); | ||
| 852 | case 0x2: | ||
| 853 | return Decode10(insn); | ||
| 854 | case 0x3: | ||
| 855 | return Decode11(insn); | ||
| 856 | } | ||
| 857 | return OP_INVALID; | ||
| 858 | } | ||
| 859 | |||
| 860 | Opcode ARM_Disasm::Decode00(u32 insn) { | ||
| 861 | u8 bit25 = (insn >> 25) & 0x1; | ||
| 862 | u8 bit4 = (insn >> 4) & 0x1; | ||
| 863 | if (bit25 == 0 && bit4 == 1) { | ||
| 864 | if ((insn & 0x0ffffff0) == 0x012fff10) { | ||
| 865 | // Bx instruction | ||
| 866 | return OP_BX; | ||
| 867 | } | ||
| 868 | if ((insn & 0x0ff000f0) == 0x01600010) { | ||
| 869 | // Clz instruction | ||
| 870 | return OP_CLZ; | ||
| 871 | } | ||
| 872 | if ((insn & 0xfff000f0) == 0xe1200070) { | ||
| 873 | // Bkpt instruction | ||
| 874 | return OP_BKPT; | ||
| 875 | } | ||
| 876 | u32 bits7_4 = (insn >> 4) & 0xf; | ||
| 877 | if (bits7_4 == 0x9) { | ||
| 878 | u32 bit24 = BIT(insn, 24); | ||
| 879 | if (bit24) { | ||
| 880 | return DecodeSyncPrimitive(insn); | ||
| 881 | } | ||
| 882 | // One of the multiply instructions | ||
| 883 | return DecodeMUL(insn); | ||
| 884 | } | ||
| 885 | |||
| 886 | u8 bit7 = (insn >> 7) & 0x1; | ||
| 887 | if (bit7 == 1) { | ||
| 888 | // One of the load/store halfword/byte instructions | ||
| 889 | return DecodeLDRH(insn); | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 893 | u32 op1 = BITS(insn, 20, 24); | ||
| 894 | if (bit25 && (op1 == 0x12 || op1 == 0x16)) { | ||
| 895 | // One of the MSR (immediate) and hints instructions | ||
| 896 | return DecodeMSRImmAndHints(insn); | ||
| 897 | } | ||
| 898 | |||
| 899 | // One of the data processing instructions | ||
| 900 | return DecodeALU(insn); | ||
| 901 | } | ||
| 902 | |||
| 903 | Opcode ARM_Disasm::Decode01(u32 insn) { | ||
| 904 | u8 is_reg = (insn >> 25) & 0x1; | ||
| 905 | u8 bit4 = (insn >> 4) & 0x1; | ||
| 906 | if (is_reg == 1 && bit4 == 1) | ||
| 907 | return DecodeMedia(insn); | ||
| 908 | u8 is_load = (insn >> 20) & 0x1; | ||
| 909 | u8 is_byte = (insn >> 22) & 0x1; | ||
| 910 | if ((insn & 0xfd70f000) == 0xf550f000) { | ||
| 911 | // Pre-load | ||
| 912 | return OP_PLD; | ||
| 913 | } | ||
| 914 | if (insn == 0xf57ff01f) { | ||
| 915 | // Clear-Exclusive | ||
| 916 | return OP_CLREX; | ||
| 917 | } | ||
| 918 | if (is_load) { | ||
| 919 | if (is_byte) { | ||
| 920 | // Load byte | ||
| 921 | return OP_LDRB; | ||
| 922 | } | ||
| 923 | // Load word | ||
| 924 | return OP_LDR; | ||
| 925 | } | ||
| 926 | if (is_byte) { | ||
| 927 | // Store byte | ||
| 928 | return OP_STRB; | ||
| 929 | } | ||
| 930 | // Store word | ||
| 931 | return OP_STR; | ||
| 932 | } | ||
| 933 | |||
| 934 | Opcode ARM_Disasm::Decode10(u32 insn) { | ||
| 935 | u8 bit25 = (insn >> 25) & 0x1; | ||
| 936 | if (bit25 == 0) { | ||
| 937 | // LDM/STM | ||
| 938 | u8 is_load = (insn >> 20) & 0x1; | ||
| 939 | if (is_load) | ||
| 940 | return OP_LDM; | ||
| 941 | return OP_STM; | ||
| 942 | } | ||
| 943 | |||
| 944 | // Branch with link | ||
| 945 | if ((insn >> 24) & 1) | ||
| 946 | return OP_BL; | ||
| 947 | |||
| 948 | return OP_B; | ||
| 949 | } | ||
| 950 | |||
| 951 | Opcode ARM_Disasm::Decode11(u32 insn) { | ||
| 952 | u8 bit25 = (insn >> 25) & 0x1; | ||
| 953 | if (bit25 == 0) { | ||
| 954 | // LDC, SDC | ||
| 955 | u8 is_load = (insn >> 20) & 0x1; | ||
| 956 | if (is_load) { | ||
| 957 | // LDC | ||
| 958 | return OP_LDC; | ||
| 959 | } | ||
| 960 | // STC | ||
| 961 | return OP_STC; | ||
| 962 | } | ||
| 963 | |||
| 964 | u8 bit24 = (insn >> 24) & 0x1; | ||
| 965 | if (bit24 == 0x1) { | ||
| 966 | // SWI | ||
| 967 | return OP_SWI; | ||
| 968 | } | ||
| 969 | |||
| 970 | u8 bit4 = (insn >> 4) & 0x1; | ||
| 971 | u8 cpnum = (insn >> 8) & 0xf; | ||
| 972 | |||
| 973 | if (cpnum == 15) { | ||
| 974 | // Special case for coprocessor 15 | ||
| 975 | u8 opcode = (insn >> 21) & 0x7; | ||
| 976 | if (bit4 == 0 || opcode != 0) { | ||
| 977 | // This is an unexpected bit pattern. Create an undefined | ||
| 978 | // instruction in case this is ever executed. | ||
| 979 | return OP_UNDEFINED; | ||
| 980 | } | ||
| 981 | |||
| 982 | // MRC, MCR | ||
| 983 | u8 is_mrc = (insn >> 20) & 0x1; | ||
| 984 | if (is_mrc) | ||
| 985 | return OP_MRC; | ||
| 986 | return OP_MCR; | ||
| 987 | } | ||
| 988 | |||
| 989 | if (bit4 == 0) { | ||
| 990 | // CDP | ||
| 991 | return OP_CDP; | ||
| 992 | } | ||
| 993 | // MRC, MCR | ||
| 994 | u8 is_mrc = (insn >> 20) & 0x1; | ||
| 995 | if (is_mrc) | ||
| 996 | return OP_MRC; | ||
| 997 | return OP_MCR; | ||
| 998 | } | ||
| 999 | |||
| 1000 | Opcode ARM_Disasm::DecodeSyncPrimitive(u32 insn) { | ||
| 1001 | u32 op = BITS(insn, 20, 23); | ||
| 1002 | u32 bit22 = BIT(insn, 22); | ||
| 1003 | switch (op) { | ||
| 1004 | case 0x0: | ||
| 1005 | if (bit22) | ||
| 1006 | return OP_SWPB; | ||
| 1007 | return OP_SWP; | ||
| 1008 | case 0x8: | ||
| 1009 | return OP_STREX; | ||
| 1010 | case 0x9: | ||
| 1011 | return OP_LDREX; | ||
| 1012 | case 0xA: | ||
| 1013 | return OP_STREXD; | ||
| 1014 | case 0xB: | ||
| 1015 | return OP_LDREXD; | ||
| 1016 | case 0xC: | ||
| 1017 | return OP_STREXB; | ||
| 1018 | case 0xD: | ||
| 1019 | return OP_LDREXB; | ||
| 1020 | case 0xE: | ||
| 1021 | return OP_STREXH; | ||
| 1022 | case 0xF: | ||
| 1023 | return OP_LDREXH; | ||
| 1024 | default: | ||
| 1025 | return OP_UNDEFINED; | ||
| 1026 | } | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | Opcode ARM_Disasm::DecodeParallelAddSub(u32 insn) { | ||
| 1030 | u32 op1 = BITS(insn, 20, 21); | ||
| 1031 | u32 op2 = BITS(insn, 5, 7); | ||
| 1032 | u32 is_unsigned = BIT(insn, 22); | ||
| 1033 | |||
| 1034 | if (op1 == 0x0 || op2 == 0x5 || op2 == 0x6) | ||
| 1035 | return OP_UNDEFINED; | ||
| 1036 | |||
| 1037 | // change op1 range from [1, 3] to range [0, 2] | ||
| 1038 | op1--; | ||
| 1039 | |||
| 1040 | // change op2 range from [0, 4] U {7} to range [0, 5] | ||
| 1041 | if (op2 == 0x7) | ||
| 1042 | op2 = 0x5; | ||
| 1043 | |||
| 1044 | static std::vector<Opcode> opcodes = { | ||
| 1045 | // op1 = 0 | ||
| 1046 | OP_SADD16, OP_UADD16, OP_SASX, OP_UASX, OP_SSAX, OP_USAX, OP_SSUB16, OP_USUB16, OP_SADD8, | ||
| 1047 | OP_UADD8, OP_SSUB8, OP_USUB8, | ||
| 1048 | // op1 = 1 | ||
| 1049 | OP_QADD16, OP_UQADD16, OP_QASX, OP_UQASX, OP_QSAX, OP_UQSAX, OP_QSUB16, OP_UQSUB16, | ||
| 1050 | OP_QADD8, OP_UQADD8, OP_QSUB8, OP_UQSUB8, | ||
| 1051 | // op1 = 2 | ||
| 1052 | OP_SHADD16, OP_UHADD16, OP_SHASX, OP_UHASX, OP_SHSAX, OP_UHSAX, OP_SHSUB16, OP_UHSUB16, | ||
| 1053 | OP_SHADD8, OP_UHADD8, OP_SHSUB8, OP_UHSUB8}; | ||
| 1054 | |||
| 1055 | u32 opcode_index = op1 * 12 + op2 * 2 + is_unsigned; | ||
| 1056 | return opcodes[opcode_index]; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | Opcode ARM_Disasm::DecodePackingSaturationReversal(u32 insn) { | ||
| 1060 | u32 op1 = BITS(insn, 20, 22); | ||
| 1061 | u32 a = BITS(insn, 16, 19); | ||
| 1062 | u32 op2 = BITS(insn, 5, 7); | ||
| 1063 | |||
| 1064 | switch (op1) { | ||
| 1065 | case 0x0: | ||
| 1066 | if (BIT(op2, 0) == 0) | ||
| 1067 | return OP_PKH; | ||
| 1068 | if (op2 == 0x3 && a != 0xf) | ||
| 1069 | return OP_SXTAB16; | ||
| 1070 | if (op2 == 0x3 && a == 0xf) | ||
| 1071 | return OP_SXTB16; | ||
| 1072 | if (op2 == 0x5) | ||
| 1073 | return OP_SEL; | ||
| 1074 | break; | ||
| 1075 | case 0x2: | ||
| 1076 | if (BIT(op2, 0) == 0) | ||
| 1077 | return OP_SSAT; | ||
| 1078 | if (op2 == 0x1) | ||
| 1079 | return OP_SSAT16; | ||
| 1080 | if (op2 == 0x3 && a != 0xf) | ||
| 1081 | return OP_SXTAB; | ||
| 1082 | if (op2 == 0x3 && a == 0xf) | ||
| 1083 | return OP_SXTB; | ||
| 1084 | break; | ||
| 1085 | case 0x3: | ||
| 1086 | if (op2 == 0x1) | ||
| 1087 | return OP_REV; | ||
| 1088 | if (BIT(op2, 0) == 0) | ||
| 1089 | return OP_SSAT; | ||
| 1090 | if (op2 == 0x3 && a != 0xf) | ||
| 1091 | return OP_SXTAH; | ||
| 1092 | if (op2 == 0x3 && a == 0xf) | ||
| 1093 | return OP_SXTH; | ||
| 1094 | if (op2 == 0x5) | ||
| 1095 | return OP_REV16; | ||
| 1096 | break; | ||
| 1097 | case 0x4: | ||
| 1098 | if (op2 == 0x3 && a != 0xf) | ||
| 1099 | return OP_UXTAB16; | ||
| 1100 | if (op2 == 0x3 && a == 0xf) | ||
| 1101 | return OP_UXTB16; | ||
| 1102 | break; | ||
| 1103 | case 0x6: | ||
| 1104 | if (BIT(op2, 0) == 0) | ||
| 1105 | return OP_USAT; | ||
| 1106 | if (op2 == 0x1) | ||
| 1107 | return OP_USAT16; | ||
| 1108 | if (op2 == 0x3 && a != 0xf) | ||
| 1109 | return OP_UXTAB; | ||
| 1110 | if (op2 == 0x3 && a == 0xf) | ||
| 1111 | return OP_UXTB; | ||
| 1112 | break; | ||
| 1113 | case 0x7: | ||
| 1114 | if (BIT(op2, 0) == 0) | ||
| 1115 | return OP_USAT; | ||
| 1116 | if (op2 == 0x3 && a != 0xf) | ||
| 1117 | return OP_UXTAH; | ||
| 1118 | if (op2 == 0x3 && a == 0xf) | ||
| 1119 | return OP_UXTH; | ||
| 1120 | if (op2 == 0x5) | ||
| 1121 | return OP_REVSH; | ||
| 1122 | break; | ||
| 1123 | default: | ||
| 1124 | break; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | return OP_UNDEFINED; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | Opcode ARM_Disasm::DecodeMUL(u32 insn) { | ||
| 1131 | u8 bit24 = (insn >> 24) & 0x1; | ||
| 1132 | if (bit24 != 0) { | ||
| 1133 | // This is an unexpected bit pattern. Create an undefined | ||
| 1134 | // instruction in case this is ever executed. | ||
| 1135 | return OP_UNDEFINED; | ||
| 1136 | } | ||
| 1137 | u8 bit23 = (insn >> 23) & 0x1; | ||
| 1138 | u8 bit22_U = (insn >> 22) & 0x1; | ||
| 1139 | u8 bit21_A = (insn >> 21) & 0x1; | ||
| 1140 | if (bit23 == 0) { | ||
| 1141 | // 32-bit multiply | ||
| 1142 | if (bit22_U != 0) { | ||
| 1143 | // This is an unexpected bit pattern. Create an undefined | ||
| 1144 | // instruction in case this is ever executed. | ||
| 1145 | return OP_UNDEFINED; | ||
| 1146 | } | ||
| 1147 | if (bit21_A == 0) | ||
| 1148 | return OP_MUL; | ||
| 1149 | return OP_MLA; | ||
| 1150 | } | ||
| 1151 | // 64-bit multiply | ||
| 1152 | if (bit22_U == 0) { | ||
| 1153 | // Unsigned multiply long | ||
| 1154 | if (bit21_A == 0) | ||
| 1155 | return OP_UMULL; | ||
| 1156 | return OP_UMLAL; | ||
| 1157 | } | ||
| 1158 | // Signed multiply long | ||
| 1159 | if (bit21_A == 0) | ||
| 1160 | return OP_SMULL; | ||
| 1161 | return OP_SMLAL; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | Opcode ARM_Disasm::DecodeMSRImmAndHints(u32 insn) { | ||
| 1165 | u32 op = BIT(insn, 22); | ||
| 1166 | u32 op1 = BITS(insn, 16, 19); | ||
| 1167 | u32 op2 = BITS(insn, 0, 7); | ||
| 1168 | |||
| 1169 | if (op == 0 && op1 == 0) { | ||
| 1170 | switch (op2) { | ||
| 1171 | case 0x0: | ||
| 1172 | return OP_NOP; | ||
| 1173 | case 0x1: | ||
| 1174 | return OP_YIELD; | ||
| 1175 | case 0x2: | ||
| 1176 | return OP_WFE; | ||
| 1177 | case 0x3: | ||
| 1178 | return OP_WFI; | ||
| 1179 | case 0x4: | ||
| 1180 | return OP_SEV; | ||
| 1181 | default: | ||
| 1182 | return OP_UNDEFINED; | ||
| 1183 | } | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | return OP_MSR; | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | Opcode ARM_Disasm::DecodeMediaMulDiv(u32 insn) { | ||
| 1190 | u32 op1 = BITS(insn, 20, 22); | ||
| 1191 | u32 op2_h = BITS(insn, 6, 7); | ||
| 1192 | u32 a = BITS(insn, 12, 15); | ||
| 1193 | |||
| 1194 | switch (op1) { | ||
| 1195 | case 0x0: | ||
| 1196 | if (op2_h == 0x0) { | ||
| 1197 | if (a != 0xf) | ||
| 1198 | return OP_SMLAD; | ||
| 1199 | else | ||
| 1200 | return OP_SMUAD; | ||
| 1201 | } else if (op2_h == 0x1) { | ||
| 1202 | if (a != 0xf) | ||
| 1203 | return OP_SMLSD; | ||
| 1204 | else | ||
| 1205 | return OP_SMUSD; | ||
| 1206 | } | ||
| 1207 | break; | ||
| 1208 | case 0x4: | ||
| 1209 | if (op2_h == 0x0) | ||
| 1210 | return OP_SMLALD; | ||
| 1211 | else if (op2_h == 0x1) | ||
| 1212 | return OP_SMLSLD; | ||
| 1213 | break; | ||
| 1214 | case 0x5: | ||
| 1215 | if (op2_h == 0x0) { | ||
| 1216 | if (a != 0xf) | ||
| 1217 | return OP_SMMLA; | ||
| 1218 | else | ||
| 1219 | return OP_SMMUL; | ||
| 1220 | } else if (op2_h == 0x3) { | ||
| 1221 | return OP_SMMLS; | ||
| 1222 | } | ||
| 1223 | break; | ||
| 1224 | default: | ||
| 1225 | break; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | return OP_UNDEFINED; | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | Opcode ARM_Disasm::DecodeMedia(u32 insn) { | ||
| 1232 | u32 op1 = BITS(insn, 20, 24); | ||
| 1233 | u32 rd = BITS(insn, 12, 15); | ||
| 1234 | u32 op2 = BITS(insn, 5, 7); | ||
| 1235 | |||
| 1236 | switch (BITS(op1, 3, 4)) { | ||
| 1237 | case 0x0: | ||
| 1238 | // unsigned and signed parallel addition and subtraction | ||
| 1239 | return DecodeParallelAddSub(insn); | ||
| 1240 | case 0x1: | ||
| 1241 | // Packing, unpacking, saturation, and reversal | ||
| 1242 | return DecodePackingSaturationReversal(insn); | ||
| 1243 | case 0x2: | ||
| 1244 | // Signed multiply, signed and unsigned divide | ||
| 1245 | return DecodeMediaMulDiv(insn); | ||
| 1246 | case 0x3: | ||
| 1247 | if (op2 == 0 && rd == 0xf) | ||
| 1248 | return OP_USAD8; | ||
| 1249 | if (op2 == 0 && rd != 0xf) | ||
| 1250 | return OP_USADA8; | ||
| 1251 | break; | ||
| 1252 | default: | ||
| 1253 | break; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | return OP_UNDEFINED; | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | Opcode ARM_Disasm::DecodeLDRH(u32 insn) { | ||
| 1260 | u8 is_load = (insn >> 20) & 0x1; | ||
| 1261 | u8 bits_65 = (insn >> 5) & 0x3; | ||
| 1262 | if (is_load) { | ||
| 1263 | if (bits_65 == 0x1) { | ||
| 1264 | // Load unsigned halfword | ||
| 1265 | return OP_LDRH; | ||
| 1266 | } else if (bits_65 == 0x2) { | ||
| 1267 | // Load signed byte | ||
| 1268 | return OP_LDRSB; | ||
| 1269 | } | ||
| 1270 | // Signed halfword | ||
| 1271 | if (bits_65 != 0x3) { | ||
| 1272 | // This is an unexpected bit pattern. Create an undefined | ||
| 1273 | // instruction in case this is ever executed. | ||
| 1274 | return OP_UNDEFINED; | ||
| 1275 | } | ||
| 1276 | // Load signed halfword | ||
| 1277 | return OP_LDRSH; | ||
| 1278 | } | ||
| 1279 | // Store halfword | ||
| 1280 | if (bits_65 != 0x1) { | ||
| 1281 | // This is an unexpected bit pattern. Create an undefined | ||
| 1282 | // instruction in case this is ever executed. | ||
| 1283 | return OP_UNDEFINED; | ||
| 1284 | } | ||
| 1285 | // Store halfword | ||
| 1286 | return OP_STRH; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | Opcode ARM_Disasm::DecodeALU(u32 insn) { | ||
| 1290 | u8 is_immed = (insn >> 25) & 0x1; | ||
| 1291 | u8 opcode = (insn >> 21) & 0xf; | ||
| 1292 | u8 bit_s = (insn >> 20) & 1; | ||
| 1293 | u8 shift_is_reg = (insn >> 4) & 1; | ||
| 1294 | u8 bit7 = (insn >> 7) & 1; | ||
| 1295 | if (!is_immed && shift_is_reg && (bit7 != 0)) { | ||
| 1296 | // This is an unexpected bit pattern. Create an undefined | ||
| 1297 | // instruction in case this is ever executed. | ||
| 1298 | return OP_UNDEFINED; | ||
| 1299 | } | ||
| 1300 | switch (opcode) { | ||
| 1301 | case 0x0: | ||
| 1302 | return OP_AND; | ||
| 1303 | case 0x1: | ||
| 1304 | return OP_EOR; | ||
| 1305 | case 0x2: | ||
| 1306 | return OP_SUB; | ||
| 1307 | case 0x3: | ||
| 1308 | return OP_RSB; | ||
| 1309 | case 0x4: | ||
| 1310 | return OP_ADD; | ||
| 1311 | case 0x5: | ||
| 1312 | return OP_ADC; | ||
| 1313 | case 0x6: | ||
| 1314 | return OP_SBC; | ||
| 1315 | case 0x7: | ||
| 1316 | return OP_RSC; | ||
| 1317 | case 0x8: | ||
| 1318 | if (bit_s) | ||
| 1319 | return OP_TST; | ||
| 1320 | return OP_MRS; | ||
| 1321 | case 0x9: | ||
| 1322 | if (bit_s) | ||
| 1323 | return OP_TEQ; | ||
| 1324 | return OP_MSR; | ||
| 1325 | case 0xa: | ||
| 1326 | if (bit_s) | ||
| 1327 | return OP_CMP; | ||
| 1328 | return OP_MRS; | ||
| 1329 | case 0xb: | ||
| 1330 | if (bit_s) | ||
| 1331 | return OP_CMN; | ||
| 1332 | return OP_MSR; | ||
| 1333 | case 0xc: | ||
| 1334 | return OP_ORR; | ||
| 1335 | case 0xd: | ||
| 1336 | return OP_MOV; | ||
| 1337 | case 0xe: | ||
| 1338 | return OP_BIC; | ||
| 1339 | case 0xf: | ||
| 1340 | return OP_MVN; | ||
| 1341 | } | ||
| 1342 | // Unreachable | ||
| 1343 | return OP_INVALID; | ||
| 1344 | } | ||
diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h deleted file mode 100644 index 300e228ed..000000000 --- a/src/core/arm/disassembler/arm_disasm.h +++ /dev/null | |||
| @@ -1,238 +0,0 @@ | |||
| 1 | // Copyright 2006 The Android Open Source Project | ||
| 2 | |||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include <string> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | // Note: this list of opcodes must match the list used to initialize | ||
| 9 | // the opflags[] array in opcode.cpp. | ||
| 10 | enum Opcode { | ||
| 11 | OP_INVALID, | ||
| 12 | OP_UNDEFINED, | ||
| 13 | OP_ADC, | ||
| 14 | OP_ADD, | ||
| 15 | OP_AND, | ||
| 16 | OP_B, | ||
| 17 | OP_BL, | ||
| 18 | OP_BIC, | ||
| 19 | OP_BKPT, | ||
| 20 | OP_BLX, | ||
| 21 | OP_BX, | ||
| 22 | OP_CDP, | ||
| 23 | OP_CLREX, | ||
| 24 | OP_CLZ, | ||
| 25 | OP_CMN, | ||
| 26 | OP_CMP, | ||
| 27 | OP_EOR, | ||
| 28 | OP_LDC, | ||
| 29 | OP_LDM, | ||
| 30 | OP_LDR, | ||
| 31 | OP_LDRB, | ||
| 32 | OP_LDRBT, | ||
| 33 | OP_LDREX, | ||
| 34 | OP_LDREXB, | ||
| 35 | OP_LDREXD, | ||
| 36 | OP_LDREXH, | ||
| 37 | OP_LDRH, | ||
| 38 | OP_LDRSB, | ||
| 39 | OP_LDRSH, | ||
| 40 | OP_LDRT, | ||
| 41 | OP_MCR, | ||
| 42 | OP_MLA, | ||
| 43 | OP_MOV, | ||
| 44 | OP_MRC, | ||
| 45 | OP_MRS, | ||
| 46 | OP_MSR, | ||
| 47 | OP_MUL, | ||
| 48 | OP_MVN, | ||
| 49 | OP_NOP, | ||
| 50 | OP_ORR, | ||
| 51 | OP_PKH, | ||
| 52 | OP_PLD, | ||
| 53 | OP_QADD16, | ||
| 54 | OP_QADD8, | ||
| 55 | OP_QASX, | ||
| 56 | OP_QSAX, | ||
| 57 | OP_QSUB16, | ||
| 58 | OP_QSUB8, | ||
| 59 | OP_REV, | ||
| 60 | OP_REV16, | ||
| 61 | OP_REVSH, | ||
| 62 | OP_RSB, | ||
| 63 | OP_RSC, | ||
| 64 | OP_SADD16, | ||
| 65 | OP_SADD8, | ||
| 66 | OP_SASX, | ||
| 67 | OP_SBC, | ||
| 68 | OP_SEL, | ||
| 69 | OP_SEV, | ||
| 70 | OP_SHADD16, | ||
| 71 | OP_SHADD8, | ||
| 72 | OP_SHASX, | ||
| 73 | OP_SHSAX, | ||
| 74 | OP_SHSUB16, | ||
| 75 | OP_SHSUB8, | ||
| 76 | OP_SMLAD, | ||
| 77 | OP_SMLAL, | ||
| 78 | OP_SMLALD, | ||
| 79 | OP_SMLSD, | ||
| 80 | OP_SMLSLD, | ||
| 81 | OP_SMMLA, | ||
| 82 | OP_SMMLS, | ||
| 83 | OP_SMMUL, | ||
| 84 | OP_SMUAD, | ||
| 85 | OP_SMULL, | ||
| 86 | OP_SMUSD, | ||
| 87 | OP_SSAT, | ||
| 88 | OP_SSAT16, | ||
| 89 | OP_SSAX, | ||
| 90 | OP_SSUB16, | ||
| 91 | OP_SSUB8, | ||
| 92 | OP_STC, | ||
| 93 | OP_STM, | ||
| 94 | OP_STR, | ||
| 95 | OP_STRB, | ||
| 96 | OP_STRBT, | ||
| 97 | OP_STREX, | ||
| 98 | OP_STREXB, | ||
| 99 | OP_STREXD, | ||
| 100 | OP_STREXH, | ||
| 101 | OP_STRH, | ||
| 102 | OP_STRT, | ||
| 103 | OP_SUB, | ||
| 104 | OP_SWI, | ||
| 105 | OP_SWP, | ||
| 106 | OP_SWPB, | ||
| 107 | OP_SXTAB, | ||
| 108 | OP_SXTAB16, | ||
| 109 | OP_SXTAH, | ||
| 110 | OP_SXTB, | ||
| 111 | OP_SXTB16, | ||
| 112 | OP_SXTH, | ||
| 113 | OP_TEQ, | ||
| 114 | OP_TST, | ||
| 115 | OP_UADD16, | ||
| 116 | OP_UADD8, | ||
| 117 | OP_UASX, | ||
| 118 | OP_UHADD16, | ||
| 119 | OP_UHADD8, | ||
| 120 | OP_UHASX, | ||
| 121 | OP_UHSAX, | ||
| 122 | OP_UHSUB16, | ||
| 123 | OP_UHSUB8, | ||
| 124 | OP_UMLAL, | ||
| 125 | OP_UMULL, | ||
| 126 | OP_UQADD16, | ||
| 127 | OP_UQADD8, | ||
| 128 | OP_UQASX, | ||
| 129 | OP_UQSAX, | ||
| 130 | OP_UQSUB16, | ||
| 131 | OP_UQSUB8, | ||
| 132 | OP_USAD8, | ||
| 133 | OP_USADA8, | ||
| 134 | OP_USAT, | ||
| 135 | OP_USAT16, | ||
| 136 | OP_USAX, | ||
| 137 | OP_USUB16, | ||
| 138 | OP_USUB8, | ||
| 139 | OP_UXTAB, | ||
| 140 | OP_UXTAB16, | ||
| 141 | OP_UXTAH, | ||
| 142 | OP_UXTB, | ||
| 143 | OP_UXTB16, | ||
| 144 | OP_UXTH, | ||
| 145 | OP_WFE, | ||
| 146 | OP_WFI, | ||
| 147 | OP_YIELD, | ||
| 148 | |||
| 149 | // Define thumb opcodes | ||
| 150 | OP_THUMB_UNDEFINED, | ||
| 151 | OP_THUMB_ADC, | ||
| 152 | OP_THUMB_ADD, | ||
| 153 | OP_THUMB_AND, | ||
| 154 | OP_THUMB_ASR, | ||
| 155 | OP_THUMB_B, | ||
| 156 | OP_THUMB_BIC, | ||
| 157 | OP_THUMB_BKPT, | ||
| 158 | OP_THUMB_BL, | ||
| 159 | OP_THUMB_BLX, | ||
| 160 | OP_THUMB_BX, | ||
| 161 | OP_THUMB_CMN, | ||
| 162 | OP_THUMB_CMP, | ||
| 163 | OP_THUMB_EOR, | ||
| 164 | OP_THUMB_LDMIA, | ||
| 165 | OP_THUMB_LDR, | ||
| 166 | OP_THUMB_LDRB, | ||
| 167 | OP_THUMB_LDRH, | ||
| 168 | OP_THUMB_LDRSB, | ||
| 169 | OP_THUMB_LDRSH, | ||
| 170 | OP_THUMB_LSL, | ||
| 171 | OP_THUMB_LSR, | ||
| 172 | OP_THUMB_MOV, | ||
| 173 | OP_THUMB_MUL, | ||
| 174 | OP_THUMB_MVN, | ||
| 175 | OP_THUMB_NEG, | ||
| 176 | OP_THUMB_ORR, | ||
| 177 | OP_THUMB_POP, | ||
| 178 | OP_THUMB_PUSH, | ||
| 179 | OP_THUMB_ROR, | ||
| 180 | OP_THUMB_SBC, | ||
| 181 | OP_THUMB_STMIA, | ||
| 182 | OP_THUMB_STR, | ||
| 183 | OP_THUMB_STRB, | ||
| 184 | OP_THUMB_STRH, | ||
| 185 | OP_THUMB_SUB, | ||
| 186 | OP_THUMB_SWI, | ||
| 187 | OP_THUMB_TST, | ||
| 188 | |||
| 189 | OP_END // must be last | ||
| 190 | }; | ||
| 191 | |||
| 192 | class ARM_Disasm { | ||
| 193 | public: | ||
| 194 | static std::string Disassemble(u32 addr, u32 insn); | ||
| 195 | static Opcode Decode(u32 insn); | ||
| 196 | |||
| 197 | private: | ||
| 198 | static Opcode Decode00(u32 insn); | ||
| 199 | static Opcode Decode01(u32 insn); | ||
| 200 | static Opcode Decode10(u32 insn); | ||
| 201 | static Opcode Decode11(u32 insn); | ||
| 202 | static Opcode DecodeSyncPrimitive(u32 insn); | ||
| 203 | static Opcode DecodeParallelAddSub(u32 insn); | ||
| 204 | static Opcode DecodePackingSaturationReversal(u32 insn); | ||
| 205 | static Opcode DecodeMUL(u32 insn); | ||
| 206 | static Opcode DecodeMSRImmAndHints(u32 insn); | ||
| 207 | static Opcode DecodeMediaMulDiv(u32 insn); | ||
| 208 | static Opcode DecodeMedia(u32 insn); | ||
| 209 | static Opcode DecodeLDRH(u32 insn); | ||
| 210 | static Opcode DecodeALU(u32 insn); | ||
| 211 | |||
| 212 | static std::string DisassembleALU(Opcode opcode, u32 insn); | ||
| 213 | static std::string DisassembleBranch(u32 addr, Opcode opcode, u32 insn); | ||
| 214 | static std::string DisassembleBX(u32 insn); | ||
| 215 | static std::string DisassembleBKPT(u32 insn); | ||
| 216 | static std::string DisassembleCLZ(u32 insn); | ||
| 217 | static std::string DisassembleMediaMulDiv(Opcode opcode, u32 insn); | ||
| 218 | static std::string DisassembleMemblock(Opcode opcode, u32 insn); | ||
| 219 | static std::string DisassembleMem(u32 insn); | ||
| 220 | static std::string DisassembleMemHalf(u32 insn); | ||
| 221 | static std::string DisassembleMCR(Opcode opcode, u32 insn); | ||
| 222 | static std::string DisassembleMLA(Opcode opcode, u32 insn); | ||
| 223 | static std::string DisassembleUMLAL(Opcode opcode, u32 insn); | ||
| 224 | static std::string DisassembleMUL(Opcode opcode, u32 insn); | ||
| 225 | static std::string DisassembleMRS(u32 insn); | ||
| 226 | static std::string DisassembleMSR(u32 insn); | ||
| 227 | static std::string DisassembleNoOperands(Opcode opcode, u32 insn); | ||
| 228 | static std::string DisassembleParallelAddSub(Opcode opcode, u32 insn); | ||
| 229 | static std::string DisassemblePKH(u32 insn); | ||
| 230 | static std::string DisassemblePLD(u32 insn); | ||
| 231 | static std::string DisassembleREV(Opcode opcode, u32 insn); | ||
| 232 | static std::string DisassembleREX(Opcode opcode, u32 insn); | ||
| 233 | static std::string DisassembleSAT(Opcode opcode, u32 insn); | ||
| 234 | static std::string DisassembleSEL(u32 insn); | ||
| 235 | static std::string DisassembleSWI(u32 insn); | ||
| 236 | static std::string DisassembleSWP(Opcode opcode, u32 insn); | ||
| 237 | static std::string DisassembleXT(Opcode opcode, u32 insn); | ||
| 238 | }; | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 8073bb705..f4fbb8d04 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "common/microprofile.h" | 12 | #include "common/microprofile.h" |
| 13 | #include "core/arm/disassembler/arm_disasm.h" | ||
| 14 | #include "core/arm/dyncom/arm_dyncom_dec.h" | 13 | #include "core/arm/dyncom/arm_dyncom_dec.h" |
| 15 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | 14 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" |
| 16 | #include "core/arm/dyncom/arm_dyncom_run.h" | 15 | #include "core/arm/dyncom/arm_dyncom_run.h" |
| @@ -828,10 +827,8 @@ static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, cons | |||
| 828 | 827 | ||
| 829 | int idx; | 828 | int idx; |
| 830 | if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { | 829 | if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { |
| 831 | std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); | 830 | LOG_ERROR(Core_ARM11, "Decode failure.\tPC: [0x%08" PRIX32 "]\tInstruction: %08" PRIX32, |
| 832 | LOG_ERROR(Core_ARM11, | 831 | phys_addr, inst); |
| 833 | "Decode failure.\tPC: [0x%08" PRIX32 "]\tInstruction: %s [%08" PRIX32 "]", | ||
| 834 | phys_addr, disasm.c_str(), inst); | ||
| 835 | LOG_ERROR(Core_ARM11, "cpsr=0x%" PRIX32 ", cpu->TFlag=%d, r15=0x%08" PRIX32, cpu->Cpsr, | 832 | LOG_ERROR(Core_ARM11, "cpsr=0x%" PRIX32 ", cpu->TFlag=%d, r15=0x%08" PRIX32, cpu->Cpsr, |
| 836 | cpu->TFlag, cpu->Reg[15]); | 833 | cpu->TFlag, cpu->Reg[15]); |
| 837 | CITRA_IGNORE_EXIT(-1); | 834 | CITRA_IGNORE_EXIT(-1); |