all repos — mgba @ 0a4b47cccfcbbe60a8af3616ff930b09b50b9682

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