all repos — mgba @ 447750dc2e53fa4986a26e5ddcca90f5861be49a

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/internal/debugger/symbols.h>
 10#include <mgba-util/string.h>
 11
 12#define ADVANCE(AMOUNT) \
 13	if (AMOUNT >= blen) { \
 14		buffer[blen - 1] = '\0'; \
 15		return total; \
 16	} \
 17	total += AMOUNT; \
 18	buffer += AMOUNT; \
 19	blen -= AMOUNT;
 20
 21static int _decodeRegister(int reg, char* buffer, int blen);
 22static int _decodeRegisterList(int list, char* buffer, int blen);
 23static int _decodePSR(int bits, char* buffer, int blen);
 24static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen);
 25static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen);
 26static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
 27
 28static const char* _armConditions[] = {
 29	"eq",
 30	"ne",
 31	"cs",
 32	"cc",
 33	"mi",
 34	"pl",
 35	"vs",
 36	"vc",
 37	"hi",
 38	"ls",
 39	"ge",
 40	"lt",
 41	"gt",
 42	"le",
 43	"al",
 44	"nv"
 45};
 46
 47static int _decodeRegister(int reg, char* buffer, int blen) {
 48	switch (reg) {
 49	case ARM_SP:
 50		strlcpy(buffer, "sp", blen);
 51		return 2;
 52	case ARM_LR:
 53		strlcpy(buffer, "lr", blen);
 54		return 2;
 55	case ARM_PC:
 56		strlcpy(buffer, "pc", blen);
 57		return 2;
 58	case ARM_CPSR:
 59		strlcpy(buffer, "cpsr", blen);
 60		return 4;
 61	case ARM_SPSR:
 62		strlcpy(buffer, "spsr", blen);
 63		return 4;
 64	default:
 65		return snprintf(buffer, blen, "r%i", reg);
 66	}
 67}
 68
 69static int _decodeRegisterList(int list, char* buffer, int blen) {
 70	if (blen <= 0) {
 71		return 0;
 72	}
 73	int total = 0;
 74	strlcpy(buffer, "{", blen);
 75	ADVANCE(1);
 76	int i;
 77	int start = -1;
 78	int end = -1;
 79	int written;
 80	for (i = 0; i <= ARM_PC; ++i) {
 81		if (list & 1) {
 82			if (start < 0) {
 83				start = i;
 84				end = i;
 85			} else if (end + 1 == i) {
 86				end = i;
 87			} else {
 88				if (end > start) {
 89					written = _decodeRegister(start, buffer, blen);
 90					ADVANCE(written);
 91					strlcpy(buffer, "-", blen);
 92					ADVANCE(1);
 93				}
 94				written = _decodeRegister(end, buffer, blen);
 95				ADVANCE(written);
 96				strlcpy(buffer, ",", blen);
 97				ADVANCE(1);
 98				start = i;
 99				end = i;
100			}
101		}
102		list >>= 1;
103	}
104	if (start >= 0) {
105		if (end > start) {
106			written = _decodeRegister(start, buffer, blen);
107			ADVANCE(written);
108			strlcpy(buffer, "-", blen);
109			ADVANCE(1);
110		}
111		written = _decodeRegister(end, buffer, blen);
112		ADVANCE(written);
113	}
114	strlcpy(buffer, "}", blen);
115	ADVANCE(1);
116	return total;
117}
118
119static int _decodePSR(int psrBits, char* buffer, int blen) {
120	if (!psrBits) {
121		return 0;
122	}
123	int total = 0;
124	strlcpy(buffer, "_", blen);
125	ADVANCE(1);
126	if (psrBits & ARM_PSR_C) {
127		strlcpy(buffer, "c", blen);
128		ADVANCE(1);
129	}
130	if (psrBits & ARM_PSR_X) {
131		strlcpy(buffer, "x", blen);
132		ADVANCE(1);
133	}
134	if (psrBits & ARM_PSR_S) {
135		strlcpy(buffer, "s", blen);
136		ADVANCE(1);
137	}
138	if (psrBits & ARM_PSR_F) {
139		strlcpy(buffer, "f", blen);
140		ADVANCE(1);
141	}
142	return total;
143}
144
145static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) {
146	address += pc;
147	const char* label = NULL;
148	if (symbols) {
149		label = mDebuggerSymbolReverseLookup(symbols, address, -1);
150		if (!label && thumbBranch) {
151			label = mDebuggerSymbolReverseLookup(symbols, address | 1, -1);
152		}
153	}
154	if (label) {
155		return strlcpy(buffer, label, blen);
156	} else {
157		return snprintf(buffer, blen, "0x%08X", address);
158	}
159}
160
161static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen) {
162	if (blen <= 1) {
163		return 0;
164	}
165	int total = 0;
166	bool elideClose = false;
167	char comment[64];
168	int written;
169	comment[0] = '\0';
170	if (memory.format & ARM_MEMORY_REGISTER_BASE) {
171		if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
172			uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
173			if (!cpu || memory.format & ARM_MEMORY_STORE) {
174				strlcpy(buffer, "[", blen);
175				ADVANCE(1);
176				written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen);
177				ADVANCE(written);
178			} else {
179				uint32_t value;
180				_decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, comment, sizeof(comment));
181				addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB
182				switch (memory.width & 7) {
183				case 1:
184					value = cpu->memory.load8(cpu, addrBase, NULL);
185					break;
186				case 2:
187					value = cpu->memory.load16(cpu, addrBase, NULL);
188					break;
189				case 4:
190					value = cpu->memory.load32(cpu, addrBase, NULL);
191					break;
192				}
193				const char* label = NULL;
194				if (symbols) {
195					label = mDebuggerSymbolReverseLookup(symbols, value, -1);
196				}
197				if (label) {
198					written = snprintf(buffer, blen, "=%s", label);
199				} else {
200					written = snprintf(buffer, blen, "=0x%08X", value);
201				}
202				ADVANCE(written);
203				elideClose = true;
204			}
205		} else {
206			strlcpy(buffer, "[", blen);
207			ADVANCE(1);
208			written = _decodeRegister(memory.baseReg, buffer, blen);
209			ADVANCE(written);
210			if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
211				strlcpy(buffer, ", ", blen);
212				ADVANCE(2);
213			}
214		}
215	} else {
216		strlcpy(buffer, "[", blen);
217		ADVANCE(1);
218	}
219	if (memory.format & ARM_MEMORY_POST_INCREMENT) {
220		strlcpy(buffer, "], ", blen);
221		ADVANCE(3);
222		elideClose = true;
223	}
224	if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
225		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
226			written = snprintf(buffer, blen, "#-%i", memory.offset.immediate);
227			ADVANCE(written);
228		} else {
229			written = snprintf(buffer, blen, "#%i", memory.offset.immediate);
230			ADVANCE(written);
231		}
232	} else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
233		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
234			strlcpy(buffer, "-", blen);
235			ADVANCE(1);
236		}
237		written = _decodeRegister(memory.offset.reg, buffer, blen);
238		ADVANCE(written);
239	}
240	if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
241		written = _decodeShift(memory.offset, false, buffer, blen);
242		ADVANCE(written);
243	}
244
245	if (!elideClose) {
246		strlcpy(buffer, "]", blen);
247		ADVANCE(1);
248	}
249	if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
250		strlcpy(buffer, "!", blen);
251		ADVANCE(1);
252	}
253	if (comment[0]) {
254		written = snprintf(buffer, blen, "  @ %s", comment);
255		ADVANCE(written);
256	}
257	return total;
258}
259
260static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
261	if (blen <= 1) {
262		return 0;
263	}
264	int total = 0;
265	strlcpy(buffer, ", ", blen);
266	ADVANCE(2);
267	int written;
268	switch (op.shifterOp) {
269	case ARM_SHIFT_LSL:
270		strlcpy(buffer, "lsl ", blen);
271		ADVANCE(4);
272		break;
273	case ARM_SHIFT_LSR:
274		strlcpy(buffer, "lsr ", blen);
275		ADVANCE(4);
276		break;
277	case ARM_SHIFT_ASR:
278		strlcpy(buffer, "asr ", blen);
279		ADVANCE(4);
280		break;
281	case ARM_SHIFT_ROR:
282		strlcpy(buffer, "ror ", blen);
283		ADVANCE(4);
284		break;
285	case ARM_SHIFT_RRX:
286		strlcpy(buffer, "rrx", blen);
287		ADVANCE(3);
288		return total;
289	}
290	if (!reg) {
291		written = snprintf(buffer, blen, "#%i", op.shifterImm);
292	} else {
293		written = _decodeRegister(op.shifterReg, buffer, blen);
294	}
295	ADVANCE(written);
296	return total;
297}
298
299static const char* _armMnemonicStrings[] = {
300	"ill",
301	"adc",
302	"add",
303	"and",
304	"asr",
305	"b",
306	"bic",
307	"bkpt",
308	"bl",
309	"bx",
310	"cmn",
311	"cmp",
312	"eor",
313	"ldm",
314	"ldr",
315	"lsl",
316	"lsr",
317	"mla",
318	"mov",
319	"mrs",
320	"msr",
321	"mul",
322	"mvn",
323	"neg",
324	"orr",
325	"ror",
326	"rsb",
327	"rsc",
328	"sbc",
329	"smlal",
330	"smull",
331	"stm",
332	"str",
333	"sub",
334	"swi",
335	"swp",
336	"teq",
337	"tst",
338	"umlal",
339	"umull",
340
341	"ill"
342};
343
344static const char* _armDirectionStrings[] = {
345	"da",
346	"ia",
347	"db",
348	"ib"
349};
350
351static const char* _armAccessTypeStrings[] = {
352	"",
353	"b",
354	"h",
355	"",
356	"",
357	"",
358	"",
359	"",
360
361	"",
362	"sb",
363	"sh",
364	"",
365	"",
366	"",
367	"",
368	"",
369
370	"",
371	"bt",
372	"",
373	"",
374	"t",
375	"",
376	"",
377	""
378};
379
380int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) {
381	const char* mnemonic = _armMnemonicStrings[info->mnemonic];
382	int written;
383	int total = 0;
384	const char* cond = "";
385	if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
386		cond = _armConditions[info->condition];
387	}
388	const char* flags = "";
389	switch (info->mnemonic) {
390	case ARM_MN_LDM:
391	case ARM_MN_STM:
392		flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
393		break;
394	case ARM_MN_LDR:
395	case ARM_MN_STR:
396	case ARM_MN_SWP:
397		flags = _armAccessTypeStrings[info->memory.width];
398		break;
399	case ARM_MN_ADD:
400	case ARM_MN_ADC:
401	case ARM_MN_AND:
402	case ARM_MN_ASR:
403	case ARM_MN_BIC:
404	case ARM_MN_EOR:
405	case ARM_MN_LSL:
406	case ARM_MN_LSR:
407	case ARM_MN_MLA:
408	case ARM_MN_MOV:
409	case ARM_MN_MUL:
410	case ARM_MN_MVN:
411	case ARM_MN_ORR:
412	case ARM_MN_ROR:
413	case ARM_MN_RSB:
414	case ARM_MN_RSC:
415	case ARM_MN_SBC:
416	case ARM_MN_SMLAL:
417	case ARM_MN_SMULL:
418	case ARM_MN_SUB:
419	case ARM_MN_UMLAL:
420	case ARM_MN_UMULL:
421		if (info->affectsCPSR && info->execMode == MODE_ARM) {
422			flags = "s";
423		}
424		break;
425	default:
426		break;
427	}
428	written = snprintf(buffer, blen, "%s%s%s ", mnemonic, cond, flags);
429	ADVANCE(written);
430
431	switch (info->mnemonic) {
432	case ARM_MN_LDM:
433	case ARM_MN_STM:
434		written = _decodeRegister(info->memory.baseReg, buffer, blen);
435		ADVANCE(written);
436		if (info->memory.format & ARM_MEMORY_WRITEBACK) {
437			strlcpy(buffer, "!", blen);
438			ADVANCE(1);
439		}
440		strlcpy(buffer, ", ", blen);
441		ADVANCE(2);
442		written = _decodeRegisterList(info->op1.immediate, buffer, blen);
443		ADVANCE(written);
444		if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
445			strlcpy(buffer, "^", blen);
446			ADVANCE(1);
447		}
448		break;
449	case ARM_MN_B:
450	case ARM_MN_BL:
451		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
452			written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen);
453			ADVANCE(written);
454		}
455		break;
456	default:
457		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
458			written = snprintf(buffer, blen, "#%i", info->op1.immediate);
459			ADVANCE(written);
460		} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
461			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
462			ADVANCE(written);
463		} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
464			written = _decodeRegister(info->op1.reg, buffer, blen);
465			ADVANCE(written);
466			if (info->op1.reg > ARM_PC) {
467				written = _decodePSR(info->op1.psrBits, buffer, blen);
468				ADVANCE(written);
469			}
470		}
471		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
472			written = _decodeShift(info->op1, true, buffer, blen);
473			ADVANCE(written);
474		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
475			written = _decodeShift(info->op1, false, buffer, blen);
476			ADVANCE(written);
477		}
478		if (info->operandFormat & ARM_OPERAND_2) {
479			strlcpy(buffer, ", ", blen);
480			ADVANCE(2);
481		}
482		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
483			written = snprintf(buffer, blen, "#%i", info->op2.immediate);
484			ADVANCE(written);
485		} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
486			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
487			ADVANCE(written);
488		} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
489			written = _decodeRegister(info->op2.reg, buffer, blen);
490			ADVANCE(written);
491		}
492		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
493			written = _decodeShift(info->op2, true, buffer, blen);
494			ADVANCE(written);
495		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
496			written = _decodeShift(info->op2, false, buffer, blen);
497			ADVANCE(written);
498		}
499		if (info->operandFormat & ARM_OPERAND_3) {
500			strlcpy(buffer, ", ", blen);
501			ADVANCE(2);
502		}
503		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
504			written = snprintf(buffer, blen, "#%i", info->op3.immediate);
505			ADVANCE(written);
506		} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
507			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
508			ADVANCE(written);
509		} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
510			written = _decodeRegister(info->op3.reg, buffer, blen);
511			ADVANCE(written);
512		}
513		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
514			written = _decodeShift(info->op3, true, buffer, blen);
515			ADVANCE(written);
516		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
517			written = _decodeShift(info->op3, false, buffer, blen);
518			ADVANCE(written);
519		}
520		if (info->operandFormat & ARM_OPERAND_4) {
521			strlcpy(buffer, ", ", blen);
522			ADVANCE(2);
523		}
524		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
525			written = snprintf(buffer, blen, "#%i", info->op4.immediate);
526			ADVANCE(written);
527		} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
528			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
529			ADVANCE(written);
530		} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
531			written = _decodeRegister(info->op4.reg, buffer, blen);
532			ADVANCE(written);
533		}
534		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
535			written = _decodeShift(info->op4, true, buffer, blen);
536			ADVANCE(written);
537		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
538			written = _decodeShift(info->op4, false, buffer, blen);
539			ADVANCE(written);
540		}
541		break;
542	}
543	buffer[blen - 1] = '\0';
544	return total;
545}
546
547uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc) {
548	uint32_t address = 0;
549	int32_t offset = 0;
550	if (info->memory.format & ARM_MEMORY_REGISTER_BASE) {
551		if (info->memory.baseReg == ARM_PC && info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
552			address = pc;
553		} else {
554			address = regs->gprs[info->memory.baseReg];
555		}
556	}
557	if (info->memory.format & ARM_MEMORY_POST_INCREMENT) {
558		return address;
559	}
560	if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
561		offset = info->memory.offset.immediate;
562	} else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) {
563		offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg];
564	}
565	if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
566		uint8_t shiftSize = info->memory.offset.shifterImm;
567		switch (info->memory.offset.shifterOp) {
568			case ARM_SHIFT_LSL:
569				offset <<= shiftSize;
570				break;
571			case ARM_SHIFT_LSR:
572				offset = ((uint32_t) offset) >> shiftSize;
573				break;
574			case ARM_SHIFT_ASR:
575				offset >>= shiftSize;
576				break;
577			case ARM_SHIFT_ROR:
578				offset = ROR(offset, shiftSize);
579				break;
580			case ARM_SHIFT_RRX:
581				offset = (regs->cpsr.c << 31) | ((uint32_t) offset >> 1);
582				break;
583			default:
584				break;
585		};
586	}
587	return address + (info->memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -offset : offset);
588}