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 "bx",
254 "cmn",
255 "cmp",
256 "eor",
257 "ldm",
258 "ldr",
259 "lsl",
260 "lsr",
261 "mla",
262 "mov",
263 "mrs",
264 "msr",
265 "mul",
266 "mvn",
267 "neg",
268 "orr",
269 "ror",
270 "rsb",
271 "rsc",
272 "sbc",
273 "smlal",
274 "smull",
275 "stm",
276 "str",
277 "sub",
278 "swi",
279 "swp",
280 "teq",
281 "tst",
282 "umlal",
283 "umull",
284
285 "ill"
286};
287
288static const char* _armDirectionStrings[] = {
289 "da",
290 "ia",
291 "db",
292 "ib"
293};
294
295static const char* _armAccessTypeStrings[] = {
296 "",
297 "b",
298 "h",
299 "",
300 "",
301 "",
302 "",
303 "",
304
305 "",
306 "sb",
307 "sh",
308 "",
309 "",
310 "",
311 "",
312 "",
313
314 "",
315 "bt",
316 "",
317 "",
318 "t",
319 "",
320 "",
321 ""
322};
323
324int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
325 const char* mnemonic = _armMnemonicStrings[info->mnemonic];
326 int written;
327 int total = 0;
328 const char* cond = "";
329 if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
330 cond = _armConditions[info->condition];
331 }
332 const char* flags = "";
333 switch (info->mnemonic) {
334 case ARM_MN_LDM:
335 case ARM_MN_STM:
336 flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
337 break;
338 case ARM_MN_LDR:
339 case ARM_MN_STR:
340 case ARM_MN_SWP:
341 flags = _armAccessTypeStrings[info->memory.width];
342 break;
343 case ARM_MN_ADD:
344 case ARM_MN_ADC:
345 case ARM_MN_AND:
346 case ARM_MN_BIC:
347 case ARM_MN_EOR:
348 case ARM_MN_MOV:
349 case ARM_MN_MVN:
350 case ARM_MN_ORR:
351 case ARM_MN_RSB:
352 case ARM_MN_RSC:
353 case ARM_MN_SBC:
354 case ARM_MN_SUB:
355 if (info->affectsCPSR && info->execMode == MODE_ARM) {
356 flags = "s";
357 }
358 break;
359 default:
360 break;
361 }
362 written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
363 ADVANCE(written);
364
365 switch (info->mnemonic) {
366 case ARM_MN_LDM:
367 case ARM_MN_STM:
368 written = _decodeRegister(info->memory.baseReg, buffer, blen);
369 ADVANCE(written);
370 if (info->memory.format & ARM_MEMORY_WRITEBACK) {
371 strncpy(buffer, "!", blen - 1);
372 ADVANCE(1);
373 }
374 strncpy(buffer, ", ", blen - 1);
375 ADVANCE(2);
376 written = _decodeRegisterList(info->op1.immediate, buffer, blen);
377 ADVANCE(written);
378 if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
379 strncpy(buffer, "^", blen - 1);
380 ADVANCE(1);
381 }
382 break;
383 case ARM_MN_B:
384 case ARM_MN_BL:
385 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
386 written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
387 ADVANCE(written);
388 }
389 break;
390 default:
391 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
392 written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
393 ADVANCE(written);
394 } else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
395 written = _decodeMemory(info->memory, pc, buffer, blen);
396 ADVANCE(written);
397 } else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
398 written = _decodeRegister(info->op1.reg, buffer, blen);
399 ADVANCE(written);
400 if (info->op1.reg > ARM_PC) {
401 written = _decodePSR(info->op1.psrBits, buffer, blen);
402 ADVANCE(written);
403 }
404 }
405 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
406 written = _decodeShift(info->op1, true, buffer, blen);
407 ADVANCE(written);
408 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
409 written = _decodeShift(info->op1, false, buffer, blen);
410 ADVANCE(written);
411 }
412 if (info->operandFormat & ARM_OPERAND_2) {
413 strncpy(buffer, ", ", blen);
414 ADVANCE(2);
415 }
416 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
417 written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
418 ADVANCE(written);
419 } else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
420 written = _decodeMemory(info->memory, pc, buffer, blen);
421 ADVANCE(written);
422 } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
423 written = _decodeRegister(info->op2.reg, buffer, blen);
424 ADVANCE(written);
425 }
426 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
427 written = _decodeShift(info->op2, true, buffer, blen);
428 ADVANCE(written);
429 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
430 written = _decodeShift(info->op2, false, buffer, blen);
431 ADVANCE(written);
432 }
433 if (info->operandFormat & ARM_OPERAND_3) {
434 strncpy(buffer, ", ", blen - 1);
435 ADVANCE(2);
436 }
437 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
438 written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
439 ADVANCE(written);
440 } else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
441 written = _decodeMemory(info->memory, pc, buffer, blen);
442 ADVANCE(written);
443 } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
444 written = _decodeRegister(info->op3.reg, buffer, blen);
445 ADVANCE(written);
446 }
447 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
448 written = _decodeShift(info->op3, true, buffer, blen);
449 ADVANCE(written);
450 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
451 written = _decodeShift(info->op3, false, buffer, blen);
452 ADVANCE(written);
453 }
454 if (info->operandFormat & ARM_OPERAND_4) {
455 strncpy(buffer, ", ", blen - 1);
456 ADVANCE(2);
457 }
458 if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
459 written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
460 ADVANCE(written);
461 } else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
462 written = _decodeMemory(info->memory, pc, buffer, blen);
463 ADVANCE(written);
464 } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
465 written = _decodeRegister(info->op4.reg, buffer, blen);
466 ADVANCE(written);
467 }
468 if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
469 written = _decodeShift(info->op4, true, buffer, blen);
470 ADVANCE(written);
471 } else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
472 written = _decodeShift(info->op4, false, buffer, blen);
473 ADVANCE(written);
474 }
475 break;
476 }
477 buffer[blen - 1] = '\0';
478 return total;
479}