src/arm/decoder.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/arm/decoder.h>
7
8#include <mgba/internal/arm/decoder-inlines.h>
9#include <mgba/internal/debugger/symbols.h>
10#include <mgba-util/string.h>
11
12#ifdef USE_DEBUGGERS
13#define ADVANCE(AMOUNT) \
14 if (AMOUNT >= blen) { \
15 buffer[blen - 1] = '\0'; \
16 return total; \
17 } \
18 total += AMOUNT; \
19 buffer += AMOUNT; \
20 blen -= AMOUNT;
21
22static int _decodeRegister(int reg, char* buffer, int blen);
23static int _decodeRegisterList(int list, char* buffer, int blen);
24static int _decodePSR(int bits, char* buffer, int blen);
25static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen);
26static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen);
27static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
28
29static const char* _armConditions[] = {
30 "eq",
31 "ne",
32 "cs",
33 "cc",
34 "mi",
35 "pl",
36 "vs",
37 "vc",
38 "hi",
39 "ls",
40 "ge",
41 "lt",
42 "gt",
43 "le",
44 "al",
45 "nv"
46};
47
48static int _decodeRegister(int reg, char* buffer, int blen) {
49 switch (reg) {
50 case ARM_SP:
51 strlcpy(buffer, "sp", blen);
52 return 2;
53 case ARM_LR:
54 strlcpy(buffer, "lr", blen);
55 return 2;
56 case ARM_PC:
57 strlcpy(buffer, "pc", blen);
58 return 2;
59 case ARM_CPSR:
60 strlcpy(buffer, "cpsr", blen);
61 return 4;
62 case ARM_SPSR:
63 strlcpy(buffer, "spsr", blen);
64 return 4;
65 default:
66 return snprintf(buffer, blen, "r%i", reg);
67 }
68}
69
70static int _decodeRegisterList(int list, char* buffer, int blen) {
71 if (blen <= 0) {
72 return 0;
73 }
74 int total = 0;
75 strlcpy(buffer, "{", blen);
76 ADVANCE(1);
77 int i;
78 int start = -1;
79 int end = -1;
80 int written;
81 for (i = 0; i <= ARM_PC; ++i) {
82 if (list & 1) {
83 if (start < 0) {
84 start = i;
85 end = i;
86 } else if (end + 1 == i) {
87 end = i;
88 } else {
89 if (end > start) {
90 written = _decodeRegister(start, buffer, blen);
91 ADVANCE(written);
92 strlcpy(buffer, "-", blen);
93 ADVANCE(1);
94 }
95 written = _decodeRegister(end, buffer, blen);
96 ADVANCE(written);
97 strlcpy(buffer, ",", blen);
98 ADVANCE(1);
99 start = i;
100 end = i;
101 }
102 }
103 list >>= 1;
104 }
105 if (start >= 0) {
106 if (end > start) {
107 written = _decodeRegister(start, buffer, blen);
108 ADVANCE(written);
109 strlcpy(buffer, "-", blen);
110 ADVANCE(1);
111 }
112 written = _decodeRegister(end, buffer, blen);
113 ADVANCE(written);
114 }
115 strlcpy(buffer, "}", blen);
116 ADVANCE(1);
117 return total;
118}
119
120static int _decodePSR(int psrBits, char* buffer, int blen) {
121 if (!psrBits) {
122 return 0;
123 }
124 int total = 0;
125 strlcpy(buffer, "_", blen);
126 ADVANCE(1);
127 if (psrBits & ARM_PSR_C) {
128 strlcpy(buffer, "c", blen);
129 ADVANCE(1);
130 }
131 if (psrBits & ARM_PSR_X) {
132 strlcpy(buffer, "x", blen);
133 ADVANCE(1);
134 }
135 if (psrBits & ARM_PSR_S) {
136 strlcpy(buffer, "s", blen);
137 ADVANCE(1);
138 }
139 if (psrBits & ARM_PSR_F) {
140 strlcpy(buffer, "f", blen);
141 ADVANCE(1);
142 }
143 return total;
144}
145
146static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) {
147 address += pc;
148 const char* label = NULL;
149 if (symbols) {
150 label = mDebuggerSymbolReverseLookup(symbols, address, -1);
151 if (!label && thumbBranch) {
152 label = mDebuggerSymbolReverseLookup(symbols, address | 1, -1);
153 }
154 }
155 if (label) {
156 return strlcpy(buffer, label, blen);
157 } else {
158 return snprintf(buffer, blen, "0x%08X", address);
159 }
160}
161
162static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen) {
163 if (blen <= 1) {
164 return 0;
165 }
166 int total = 0;
167 bool elideClose = false;
168 char comment[64];
169 int written;
170 comment[0] = '\0';
171 if (memory.format & ARM_MEMORY_REGISTER_BASE) {
172 if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
173 uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
174 if (!cpu || memory.format & ARM_MEMORY_STORE) {
175 strlcpy(buffer, "[", blen);
176 ADVANCE(1);
177 written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen);
178 ADVANCE(written);
179 } else {
180 uint32_t value;
181 _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, comment, sizeof(comment));
182 addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB
183 switch (memory.width & 7) {
184 case 1:
185 value = cpu->memory.load8(cpu, addrBase, NULL);
186 break;
187 case 2:
188 value = cpu->memory.load16(cpu, addrBase, NULL);
189 break;
190 case 4:
191 value = cpu->memory.load32(cpu, addrBase, NULL);
192 break;
193 }
194 const char* label = NULL;
195 if (symbols) {
196 label = mDebuggerSymbolReverseLookup(symbols, value, -1);
197 }
198 if (label) {
199 written = snprintf(buffer, blen, "=%s", label);
200 } else {
201 written = snprintf(buffer, blen, "=0x%08X", value);
202 }
203 ADVANCE(written);
204 elideClose = true;
205 }
206 } else {
207 strlcpy(buffer, "[", blen);
208 ADVANCE(1);
209 written = _decodeRegister(memory.baseReg, buffer, blen);
210 ADVANCE(written);
211 if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
212 strlcpy(buffer, ", ", blen);
213 ADVANCE(2);
214 }
215 }
216 } else {
217 strlcpy(buffer, "[", blen);
218 ADVANCE(1);
219 }
220 if (memory.format & ARM_MEMORY_POST_INCREMENT) {
221 strlcpy(buffer, "], ", blen);
222 ADVANCE(3);
223 elideClose = true;
224 }
225 if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
226 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
227 written = snprintf(buffer, blen, "#-%i", memory.offset.immediate);
228 ADVANCE(written);
229 } else {
230 written = snprintf(buffer, blen, "#%i", memory.offset.immediate);
231 ADVANCE(written);
232 }
233 } else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
234 if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
235 strlcpy(buffer, "-", blen);
236 ADVANCE(1);
237 }
238 written = _decodeRegister(memory.offset.reg, buffer, blen);
239 ADVANCE(written);
240 }
241 if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
242 written = _decodeShift(memory.offset, false, buffer, blen);
243 ADVANCE(written);
244 }
245
246 if (!elideClose) {
247 strlcpy(buffer, "]", blen);
248 ADVANCE(1);
249 }
250 if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
251 strlcpy(buffer, "!", blen);
252 ADVANCE(1);
253 }
254 if (comment[0]) {
255 written = snprintf(buffer, blen, " @ %s", comment);
256 ADVANCE(written);
257 }
258 return total;
259}
260
261static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
262 if (blen <= 1) {
263 return 0;
264 }
265 int total = 0;
266 strlcpy(buffer, ", ", blen);
267 ADVANCE(2);
268 int written;
269 switch (op.shifterOp) {
270 case ARM_SHIFT_LSL:
271 strlcpy(buffer, "lsl ", blen);
272 ADVANCE(4);
273 break;
274 case ARM_SHIFT_LSR:
275 strlcpy(buffer, "lsr ", blen);
276 ADVANCE(4);
277 break;
278 case ARM_SHIFT_ASR:
279 strlcpy(buffer, "asr ", blen);
280 ADVANCE(4);
281 break;
282 case ARM_SHIFT_ROR:
283 strlcpy(buffer, "ror ", blen);
284 ADVANCE(4);
285 break;
286 case ARM_SHIFT_RRX:
287 strlcpy(buffer, "rrx", blen);
288 ADVANCE(3);
289 return total;
290 }
291 if (!reg) {
292 written = snprintf(buffer, blen, "#%i", op.shifterImm);
293 } else {
294 written = _decodeRegister(op.shifterReg, buffer, blen);
295 }
296 ADVANCE(written);
297 return total;
298}
299
300static const char* _armMnemonicStrings[] = {
301 "ill",
302 "adc",
303 "add",
304 "and",
305 "asr",
306 "b",
307 "bic",
308 "bkpt",
309 "bl",
310 "bx",
311 "cmn",
312 "cmp",
313 "eor",
314 "ldm",
315 "ldr",
316 "lsl",
317 "lsr",
318 "mla",
319 "mov",
320 "mrs",
321 "msr",
322 "mul",
323 "mvn",
324 "neg",
325 "orr",
326 "ror",
327 "rsb",
328 "rsc",
329 "sbc",
330 "smlal",
331 "smull",
332 "stm",
333 "str",
334 "sub",
335 "swi",
336 "swp",
337 "teq",
338 "tst",
339 "umlal",
340 "umull",
341
342 "ill"
343};
344
345static const char* _armDirectionStrings[] = {
346 "da",
347 "ia",
348 "db",
349 "ib"
350};
351
352static const char* _armAccessTypeStrings[] = {
353 "",
354 "b",
355 "h",
356 "",
357 "",
358 "",
359 "",
360 "",
361
362 "",
363 "sb",
364 "sh",
365 "",
366 "",
367 "",
368 "",
369 "",
370
371 "",
372 "bt",
373 "",
374 "",
375 "t",
376 "",
377 "",
378 ""
379};
380
381int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) {
382 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
383 int written;
384 int total = 0;
385 const char* cond = "";
386 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
387 cond = _armConditions[info->condition];
388 }
389 const char* flags = "";
390 switch (info->mnemonic) {
391 case ARM_MN_LDM:
392 case ARM_MN_STM:
393 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
394 break;
395 case ARM_MN_LDR:
396 case ARM_MN_STR:
397 case ARM_MN_SWP:
398 flags = _armAccessTypeStrings[info->memory.width];
399 break;
400 case ARM_MN_ADD:
401 case ARM_MN_ADC:
402 case ARM_MN_AND:
403 case ARM_MN_ASR:
404 case ARM_MN_BIC:
405 case ARM_MN_EOR:
406 case ARM_MN_LSL:
407 case ARM_MN_LSR:
408 case ARM_MN_MLA:
409 case ARM_MN_MOV:
410 case ARM_MN_MUL:
411 case ARM_MN_MVN:
412 case ARM_MN_ORR:
413 case ARM_MN_ROR:
414 case ARM_MN_RSB:
415 case ARM_MN_RSC:
416 case ARM_MN_SBC:
417 case ARM_MN_SMLAL:
418 case ARM_MN_SMULL:
419 case ARM_MN_SUB:
420 case ARM_MN_UMLAL:
421 case ARM_MN_UMULL:
422 if (info->affectsCPSR && info->execMode == MODE_ARM) {
423 flags = "s";
424 }
425 break;
426 default:
427 break;
428 }
429 written = snprintf(buffer, blen, "%s%s%s ", mnemonic, cond, flags);
430 ADVANCE(written);
431
432 switch (info->mnemonic) {
433 case ARM_MN_LDM:
434 case ARM_MN_STM:
435 written = _decodeRegister(info->memory.baseReg, buffer, blen);
436 ADVANCE(written);
437 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
438 strlcpy(buffer, "!", blen);
439 ADVANCE(1);
440 }
441 strlcpy(buffer, ", ", blen);
442 ADVANCE(2);
443 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
444 ADVANCE(written);
445 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
446 strlcpy(buffer, "^", blen);
447 ADVANCE(1);
448 }
449 break;
450 case ARM_MN_B:
451 case ARM_MN_BL:
452 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
453 written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen);
454 ADVANCE(written);
455 }
456 break;
457 default:
458 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
459 written = snprintf(buffer, blen, "#%i", info->op1.immediate);
460 ADVANCE(written);
461 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
462 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
463 ADVANCE(written);
464 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
465 written = _decodeRegister(info->op1.reg, buffer, blen);
466 ADVANCE(written);
467 if (info->op1.reg > ARM_PC) {
468 written = _decodePSR(info->op1.psrBits, buffer, blen);
469 ADVANCE(written);
470 }
471 }
472 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
473 written = _decodeShift(info->op1, true, buffer, blen);
474 ADVANCE(written);
475 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
476 written = _decodeShift(info->op1, false, buffer, blen);
477 ADVANCE(written);
478 }
479 if (info->operandFormat & ARM_OPERAND_2) {
480 strlcpy(buffer, ", ", blen);
481 ADVANCE(2);
482 }
483 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
484 written = snprintf(buffer, blen, "#%i", info->op2.immediate);
485 ADVANCE(written);
486 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
487 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
488 ADVANCE(written);
489 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
490 written = _decodeRegister(info->op2.reg, buffer, blen);
491 ADVANCE(written);
492 }
493 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
494 written = _decodeShift(info->op2, true, buffer, blen);
495 ADVANCE(written);
496 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
497 written = _decodeShift(info->op2, false, buffer, blen);
498 ADVANCE(written);
499 }
500 if (info->operandFormat & ARM_OPERAND_3) {
501 strlcpy(buffer, ", ", blen);
502 ADVANCE(2);
503 }
504 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
505 written = snprintf(buffer, blen, "#%i", info->op3.immediate);
506 ADVANCE(written);
507 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
508 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
509 ADVANCE(written);
510 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
511 written = _decodeRegister(info->op3.reg, buffer, blen);
512 ADVANCE(written);
513 }
514 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
515 written = _decodeShift(info->op3, true, buffer, blen);
516 ADVANCE(written);
517 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
518 written = _decodeShift(info->op3, false, buffer, blen);
519 ADVANCE(written);
520 }
521 if (info->operandFormat & ARM_OPERAND_4) {
522 strlcpy(buffer, ", ", blen);
523 ADVANCE(2);
524 }
525 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
526 written = snprintf(buffer, blen, "#%i", info->op4.immediate);
527 ADVANCE(written);
528 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
529 written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
530 ADVANCE(written);
531 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
532 written = _decodeRegister(info->op4.reg, buffer, blen);
533 ADVANCE(written);
534 }
535 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
536 written = _decodeShift(info->op4, true, buffer, blen);
537 ADVANCE(written);
538 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
539 written = _decodeShift(info->op4, false, buffer, blen);
540 ADVANCE(written);
541 }
542 break;
543 }
544 buffer[blen - 1] = '\0';
545 return total;
546}
547#endif
548
549uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc) {
550 uint32_t address = 0;
551 int32_t offset = 0;
552 if (info->memory.format & ARM_MEMORY_REGISTER_BASE) {
553 if (info->memory.baseReg == ARM_PC && info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
554 address = pc;
555 } else {
556 address = regs->gprs[info->memory.baseReg];
557 }
558 }
559 if (info->memory.format & ARM_MEMORY_POST_INCREMENT) {
560 return address;
561 }
562 if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
563 offset = info->memory.offset.immediate;
564 } else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) {
565 offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg];
566 }
567 if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
568 uint8_t shiftSize = info->memory.offset.shifterImm;
569 switch (info->memory.offset.shifterOp) {
570 case ARM_SHIFT_LSL:
571 offset <<= shiftSize;
572 break;
573 case ARM_SHIFT_LSR:
574 offset = ((uint32_t) offset) >> shiftSize;
575 break;
576 case ARM_SHIFT_ASR:
577 offset >>= shiftSize;
578 break;
579 case ARM_SHIFT_ROR:
580 offset = ROR(offset, shiftSize);
581 break;
582 case ARM_SHIFT_RRX:
583 offset = (regs->cpsr.c << 31) | ((uint32_t) offset >> 1);
584 break;
585 default:
586 break;
587 };
588 }
589 return address + (info->memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -offset : offset);
590}