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 "smlal",
284 "smull",
285 "stc",
286 "stm",
287 "str",
288 "sub",
289 "swi",
290 "swp",
291 "teq",
292 "tst",
293 "umlal",
294 "umull",
295
296 "ill"
297};
298
299static const char* _armDirectionStrings[] = {
300 "da",
301 "ia",
302 "db",
303 "ib"
304};
305
306static const char* _armAccessTypeStrings[] = {
307 "",
308 "b",
309 "h",
310 "",
311 "",
312 "",
313 "",
314 "",
315
316 "",
317 "sb",
318 "sh",
319 "",
320 "",
321 "",
322 "",
323 "",
324
325 "",
326 "bt",
327 "",
328 "",
329 "t",
330 "",
331 "",
332 ""
333};
334
335int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
336 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
337 int written;
338 int total = 0;
339 const char* cond = "";
340 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
341 cond = _armConditions[info->condition];
342 }
343 const char* flags = "";
344 switch (info->mnemonic) {
345 case ARM_MN_LDM:
346 case ARM_MN_STM:
347 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
348 break;
349 case ARM_MN_LDR:
350 case ARM_MN_STR:
351 case ARM_MN_SWP:
352 flags = _armAccessTypeStrings[info->memory.width];
353 break;
354 case ARM_MN_ADD:
355 case ARM_MN_ADC:
356 case ARM_MN_AND:
357 case ARM_MN_BIC:
358 case ARM_MN_EOR:
359 case ARM_MN_MOV:
360 case ARM_MN_MVN:
361 case ARM_MN_ORR:
362 case ARM_MN_RSB:
363 case ARM_MN_RSC:
364 case ARM_MN_SBC:
365 case ARM_MN_SUB:
366 if (info->affectsCPSR && info->execMode == MODE_ARM) {
367 flags = "s";
368 }
369 break;
370 default:
371 break;
372 }
373 written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
374 ADVANCE(written);
375
376 switch (info->mnemonic) {
377 case ARM_MN_LDM:
378 case ARM_MN_STM:
379 written = _decodeRegister(info->memory.baseReg, buffer, blen);
380 ADVANCE(written);
381 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
382 strncpy(buffer, "!", blen - 1);
383 ADVANCE(1);
384 }
385 strncpy(buffer, ", ", blen - 1);
386 ADVANCE(2);
387 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
388 ADVANCE(written);
389 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
390 strncpy(buffer, "^", blen - 1);
391 ADVANCE(1);
392 }
393 break;
394 case ARM_MN_B:
395 case ARM_MN_BL:
396 case ARM_MN_BLX:
397 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
398 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
399 ADVANCE(written);
400 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
401 written = _decodeRegister(info->op1.reg, buffer, blen);
402 ADVANCE(written);
403 if (info->op1.reg > ARM_PC) {
404 written = _decodePSR(info->op1.psrBits, buffer, blen);
405 ADVANCE(written);
406 }
407 }
408 break;
409 default:
410 if (info->operandFormat & ARM_OPERAND_COPROCESSOR) {
411 written = snprintf(buffer, blen - 1, "p%i, %i, ", info->cp.cp, info->cp.op1);
412 ADVANCE(written);
413 }
414 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
415 written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
416 ADVANCE(written);
417 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
418 written = _decodeMemory(info->memory, pc, buffer, blen);
419 ADVANCE(written);
420 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
421 written = _decodeRegister(info->op1.reg, buffer, blen);
422 ADVANCE(written);
423 if (info->op1.reg > ARM_PC) {
424 written = _decodePSR(info->op1.psrBits, buffer, blen);
425 ADVANCE(written);
426 }
427 } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_1) {
428 written = snprintf(buffer, blen - 1, "c%i", info->op1.reg);
429 }
430 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
431 written = _decodeShift(info->op1, true, buffer, blen);
432 ADVANCE(written);
433 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
434 written = _decodeShift(info->op1, false, buffer, blen);
435 ADVANCE(written);
436 }
437 if (info->operandFormat & ARM_OPERAND_2) {
438 strncpy(buffer, ", ", blen);
439 ADVANCE(2);
440 }
441 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
442 written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
443 ADVANCE(written);
444 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
445 written = _decodeMemory(info->memory, pc, buffer, blen);
446 ADVANCE(written);
447 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
448 written = _decodeRegister(info->op2.reg, buffer, blen);
449 ADVANCE(written);
450 } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_2) {
451 written = snprintf(buffer, blen - 1, "c%i", info->op2.reg);
452 ADVANCE(written);
453 }
454 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
455 written = _decodeShift(info->op2, true, buffer, blen);
456 ADVANCE(written);
457 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
458 written = _decodeShift(info->op2, false, buffer, blen);
459 ADVANCE(written);
460 }
461 if (info->operandFormat & ARM_OPERAND_3) {
462 strncpy(buffer, ", ", blen - 1);
463 ADVANCE(2);
464 }
465 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
466 written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
467 ADVANCE(written);
468 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
469 written = _decodeMemory(info->memory, pc, buffer, blen);
470 ADVANCE(written);
471 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
472 written = _decodeRegister(info->op3.reg, buffer, blen);
473 ADVANCE(written);
474 } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_3) {
475 written = snprintf(buffer, blen - 1, "c%i", info->op3.reg);
476 ADVANCE(written);
477 }
478 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
479 written = _decodeShift(info->op3, true, buffer, blen);
480 ADVANCE(written);
481 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
482 written = _decodeShift(info->op3, false, buffer, blen);
483 ADVANCE(written);
484 }
485 if (info->operandFormat & ARM_OPERAND_4) {
486 strncpy(buffer, ", ", blen - 1);
487 ADVANCE(2);
488 }
489 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
490 written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
491 ADVANCE(written);
492 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
493 written = _decodeMemory(info->memory, pc, buffer, blen);
494 ADVANCE(written);
495 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
496 written = _decodeRegister(info->op4.reg, buffer, blen);
497 ADVANCE(written);
498 } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_4) {
499 written = snprintf(buffer, blen - 1, "c%i", info->op4.reg);
500 ADVANCE(written);
501 }
502 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
503 written = _decodeShift(info->op4, true, buffer, blen);
504 ADVANCE(written);
505 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
506 written = _decodeShift(info->op4, false, buffer, blen);
507 ADVANCE(written);
508 }
509 if (info->cp.op2) {
510 written = snprintf(buffer, blen - 1, ", %i", info->cp.op2);
511 ADVANCE(written);
512 }
513 break;
514 }
515 buffer[blen - 1] = '\0';
516 return total;
517}