all repos — mgba @ 510a539a504ea914d7ea6f30ece1e15d11c02b39

mGBA Game Boy Advance Emulator

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