all repos — mgba @ b1393f129485a5180dc1081c7a135a8ecd508cd6

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