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