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