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 "bx",
255 "cmn",
256 "cmp",
257 "eor",
258 "ldm",
259 "ldr",
260 "lsl",
261 "lsr",
262 "mla",
263 "mov",
264 "mrs",
265 "msr",
266 "mul",
267 "mvn",
268 "neg",
269 "orr",
270 "ror",
271 "rsb",
272 "rsc",
273 "sbc",
274 "smlal",
275 "smull",
276 "stm",
277 "str",
278 "sub",
279 "swi",
280 "swp",
281 "teq",
282 "tst",
283 "umlal",
284 "umull",
285
286 "ill"
287};
288
289static const char* _armDirectionStrings[] = {
290 "da",
291 "ia",
292 "db",
293 "ib"
294};
295
296static const char* _armAccessTypeStrings[] = {
297 "",
298 "b",
299 "h",
300 "",
301 "",
302 "",
303 "",
304 "",
305
306 "",
307 "sb",
308 "sh",
309 "",
310 "",
311 "",
312 "",
313 "",
314
315 "",
316 "bt",
317 "",
318 "",
319 "t",
320 "",
321 "",
322 ""
323};
324
325int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
326 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
327 int written;
328 int total = 0;
329 const char* cond = "";
330 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
331 cond = _armConditions[info->condition];
332 }
333 const char* flags = "";
334 switch (info->mnemonic) {
335 case ARM_MN_LDM:
336 case ARM_MN_STM:
337 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
338 break;
339 case ARM_MN_LDR:
340 case ARM_MN_STR:
341 case ARM_MN_SWP:
342 flags = _armAccessTypeStrings[info->memory.width];
343 break;
344 case ARM_MN_ADD:
345 case ARM_MN_ADC:
346 case ARM_MN_AND:
347 case ARM_MN_ASR:
348 case ARM_MN_BIC:
349 case ARM_MN_EOR:
350 case ARM_MN_LSL:
351 case ARM_MN_LSR:
352 case ARM_MN_MLA:
353 case ARM_MN_MOV:
354 case ARM_MN_MUL:
355 case ARM_MN_MVN:
356 case ARM_MN_ORR:
357 case ARM_MN_ROR:
358 case ARM_MN_RSB:
359 case ARM_MN_RSC:
360 case ARM_MN_SBC:
361 case ARM_MN_SMLAL:
362 case ARM_MN_SMULL:
363 case ARM_MN_SUB:
364 case ARM_MN_UMLAL:
365 case ARM_MN_UMULL:
366 if (info->affectsCPSR && info->execMode == MODE_ARM) {
367 flags = "s";
368 }
369 break;
370 default:
371 break;
372 }
373 written = snprintf(buffer, blen, "%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 strlcpy(buffer, "!", blen);
383 ADVANCE(1);
384 }
385 strlcpy(buffer, ", ", blen);
386 ADVANCE(2);
387 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
388 ADVANCE(written);
389 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
390 strlcpy(buffer, "^", blen);
391 ADVANCE(1);
392 }
393 break;
394 case ARM_MN_B:
395 case ARM_MN_BL:
396 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
397 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
398 ADVANCE(written);
399 }
400 break;
401 default:
402 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
403 written = snprintf(buffer, blen, "#%i", info->op1.immediate);
404 ADVANCE(written);
405 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
406 written = _decodeMemory(info->memory, 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 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
417 written = _decodeShift(info->op1, true, buffer, blen);
418 ADVANCE(written);
419 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
420 written = _decodeShift(info->op1, false, buffer, blen);
421 ADVANCE(written);
422 }
423 if (info->operandFormat & ARM_OPERAND_2) {
424 strlcpy(buffer, ", ", blen);
425 ADVANCE(2);
426 }
427 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
428 written = snprintf(buffer, blen, "#%i", info->op2.immediate);
429 ADVANCE(written);
430 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
431 written = _decodeMemory(info->memory, pc, buffer, blen);
432 ADVANCE(written);
433 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
434 written = _decodeRegister(info->op2.reg, buffer, blen);
435 ADVANCE(written);
436 }
437 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
438 written = _decodeShift(info->op2, true, buffer, blen);
439 ADVANCE(written);
440 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
441 written = _decodeShift(info->op2, false, buffer, blen);
442 ADVANCE(written);
443 }
444 if (info->operandFormat & ARM_OPERAND_3) {
445 strlcpy(buffer, ", ", blen);
446 ADVANCE(2);
447 }
448 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
449 written = snprintf(buffer, blen, "#%i", info->op3.immediate);
450 ADVANCE(written);
451 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
452 written = _decodeMemory(info->memory, pc, buffer, blen);
453 ADVANCE(written);
454 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
455 written = _decodeRegister(info->op3.reg, buffer, blen);
456 ADVANCE(written);
457 }
458 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
459 written = _decodeShift(info->op3, true, buffer, blen);
460 ADVANCE(written);
461 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
462 written = _decodeShift(info->op3, false, buffer, blen);
463 ADVANCE(written);
464 }
465 if (info->operandFormat & ARM_OPERAND_4) {
466 strlcpy(buffer, ", ", blen);
467 ADVANCE(2);
468 }
469 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
470 written = snprintf(buffer, blen, "#%i", info->op4.immediate);
471 ADVANCE(written);
472 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
473 written = _decodeMemory(info->memory, pc, buffer, blen);
474 ADVANCE(written);
475 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
476 written = _decodeRegister(info->op4.reg, buffer, blen);
477 ADVANCE(written);
478 }
479 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
480 written = _decodeShift(info->op4, true, buffer, blen);
481 ADVANCE(written);
482 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
483 written = _decodeShift(info->op4, false, buffer, blen);
484 ADVANCE(written);
485 }
486 break;
487 }
488 buffer[blen - 1] = '\0';
489 return total;
490}
491
492uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc) {
493 uint32_t address = 0;
494 int32_t offset = 0;
495 if (info->memory.format & ARM_MEMORY_REGISTER_BASE) {
496 if (info->memory.baseReg == ARM_PC && info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
497 address = pc;
498 } else {
499 address = regs->gprs[info->memory.baseReg];
500 }
501 }
502 if (info->memory.format & ARM_MEMORY_POST_INCREMENT) {
503 return address;
504 }
505 if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
506 offset = info->memory.offset.immediate;
507 } else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) {
508 offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg];
509 }
510 if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
511 uint8_t shiftSize = info->memory.offset.shifterImm;
512 switch (info->memory.offset.shifterOp) {
513 case ARM_SHIFT_LSL:
514 offset <<= shiftSize;
515 break;
516 case ARM_SHIFT_LSR:
517 offset = ((uint32_t) offset) >> shiftSize;
518 break;
519 case ARM_SHIFT_ASR:
520 offset >>= shiftSize;
521 break;
522 case ARM_SHIFT_ROR:
523 offset = ROR(offset, shiftSize);
524 break;
525 case ARM_SHIFT_RRX:
526 offset = (regs->cpsr.c << 31) | ((uint32_t) offset >> 1);
527 break;
528 default:
529 break;
530 };
531 }
532 return address + (info->memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -offset : offset);
533}