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