all repos — mgba @ daf2193894ffe708a68ec7fcc2c2d5e801af1617

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	"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}