all repos — mgba @ 67d3eed8fbdfadfce9c3f5c0ac1c6b4ad323b9e4

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	int written;
168	if (memory.format & ARM_MEMORY_REGISTER_BASE) {
169		if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
170			uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
171			if (!cpu) {
172				strlcpy(buffer, "[", blen);
173				ADVANCE(1);
174				written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen);
175				ADVANCE(written);
176			} else {
177				uint32_t value;
178				addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB
179				switch (memory.width & 7) {
180				case 1:
181					value = cpu->memory.load8(cpu, addrBase, NULL);
182					break;
183				case 2:
184					value = cpu->memory.load16(cpu, addrBase, NULL);
185					break;
186				case 4:
187					value = cpu->memory.load32(cpu, addrBase, NULL);
188					break;
189				}
190				const char* label = NULL;
191				if (symbols) {
192					label = mDebuggerSymbolReverseLookup(symbols, value, -1);
193				}
194				if (label) {
195					written = snprintf(buffer, blen, "=%s", label);
196				} else {
197					written = snprintf(buffer, blen, "=0x%08X", value);
198				}
199				ADVANCE(written);
200				elideClose = true;
201			}
202		} else {
203			strlcpy(buffer, "[", blen);
204			ADVANCE(1);
205			written = _decodeRegister(memory.baseReg, buffer, blen);
206			ADVANCE(written);
207			if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
208				strlcpy(buffer, ", ", blen);
209				ADVANCE(2);
210			}
211		}
212	} else {
213		strlcpy(buffer, "[", blen);
214		ADVANCE(1);
215	}
216	if (memory.format & ARM_MEMORY_POST_INCREMENT) {
217		strlcpy(buffer, "], ", blen);
218		ADVANCE(3);
219		elideClose = true;
220	}
221	if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
222		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
223			written = snprintf(buffer, blen, "#-%i", memory.offset.immediate);
224			ADVANCE(written);
225		} else {
226			written = snprintf(buffer, blen, "#%i", memory.offset.immediate);
227			ADVANCE(written);
228		}
229	} else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
230		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
231			strlcpy(buffer, "-", blen);
232			ADVANCE(1);
233		}
234		written = _decodeRegister(memory.offset.reg, buffer, blen);
235		ADVANCE(written);
236	}
237	if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
238		written = _decodeShift(memory.offset, false, buffer, blen);
239		ADVANCE(written);
240	}
241
242	if (!elideClose) {
243		strlcpy(buffer, "]", blen);
244		ADVANCE(1);
245	}
246	if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
247		strlcpy(buffer, "!", blen);
248		ADVANCE(1);
249	}
250	return total;
251}
252
253static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
254	if (blen <= 1) {
255		return 0;
256	}
257	int total = 0;
258	strlcpy(buffer, ", ", blen);
259	ADVANCE(2);
260	int written;
261	switch (op.shifterOp) {
262	case ARM_SHIFT_LSL:
263		strlcpy(buffer, "lsl ", blen);
264		ADVANCE(4);
265		break;
266	case ARM_SHIFT_LSR:
267		strlcpy(buffer, "lsr ", blen);
268		ADVANCE(4);
269		break;
270	case ARM_SHIFT_ASR:
271		strlcpy(buffer, "asr ", blen);
272		ADVANCE(4);
273		break;
274	case ARM_SHIFT_ROR:
275		strlcpy(buffer, "ror ", blen);
276		ADVANCE(4);
277		break;
278	case ARM_SHIFT_RRX:
279		strlcpy(buffer, "rrx", blen);
280		ADVANCE(3);
281		return total;
282	}
283	if (!reg) {
284		written = snprintf(buffer, blen, "#%i", op.shifterImm);
285	} else {
286		written = _decodeRegister(op.shifterReg, buffer, blen);
287	}
288	ADVANCE(written);
289	return total;
290}
291
292static const char* _armMnemonicStrings[] = {
293	"ill",
294	"adc",
295	"add",
296	"and",
297	"asr",
298	"b",
299	"bic",
300	"bkpt",
301	"bl",
302	"bx",
303	"cmn",
304	"cmp",
305	"eor",
306	"ldm",
307	"ldr",
308	"lsl",
309	"lsr",
310	"mla",
311	"mov",
312	"mrs",
313	"msr",
314	"mul",
315	"mvn",
316	"neg",
317	"orr",
318	"ror",
319	"rsb",
320	"rsc",
321	"sbc",
322	"smlal",
323	"smull",
324	"stm",
325	"str",
326	"sub",
327	"swi",
328	"swp",
329	"teq",
330	"tst",
331	"umlal",
332	"umull",
333
334	"ill"
335};
336
337static const char* _armDirectionStrings[] = {
338	"da",
339	"ia",
340	"db",
341	"ib"
342};
343
344static const char* _armAccessTypeStrings[] = {
345	"",
346	"b",
347	"h",
348	"",
349	"",
350	"",
351	"",
352	"",
353
354	"",
355	"sb",
356	"sh",
357	"",
358	"",
359	"",
360	"",
361	"",
362
363	"",
364	"bt",
365	"",
366	"",
367	"t",
368	"",
369	"",
370	""
371};
372
373int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) {
374	const char* mnemonic = _armMnemonicStrings[info->mnemonic];
375	int written;
376	int total = 0;
377	const char* cond = "";
378	if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
379		cond = _armConditions[info->condition];
380	}
381	const char* flags = "";
382	switch (info->mnemonic) {
383	case ARM_MN_LDM:
384	case ARM_MN_STM:
385		flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
386		break;
387	case ARM_MN_LDR:
388	case ARM_MN_STR:
389	case ARM_MN_SWP:
390		flags = _armAccessTypeStrings[info->memory.width];
391		break;
392	case ARM_MN_ADD:
393	case ARM_MN_ADC:
394	case ARM_MN_AND:
395	case ARM_MN_ASR:
396	case ARM_MN_BIC:
397	case ARM_MN_EOR:
398	case ARM_MN_LSL:
399	case ARM_MN_LSR:
400	case ARM_MN_MLA:
401	case ARM_MN_MOV:
402	case ARM_MN_MUL:
403	case ARM_MN_MVN:
404	case ARM_MN_ORR:
405	case ARM_MN_ROR:
406	case ARM_MN_RSB:
407	case ARM_MN_RSC:
408	case ARM_MN_SBC:
409	case ARM_MN_SMLAL:
410	case ARM_MN_SMULL:
411	case ARM_MN_SUB:
412	case ARM_MN_UMLAL:
413	case ARM_MN_UMULL:
414		if (info->affectsCPSR && info->execMode == MODE_ARM) {
415			flags = "s";
416		}
417		break;
418	default:
419		break;
420	}
421	written = snprintf(buffer, blen, "%s%s%s ", mnemonic, cond, flags);
422	ADVANCE(written);
423
424	switch (info->mnemonic) {
425	case ARM_MN_LDM:
426	case ARM_MN_STM:
427		written = _decodeRegister(info->memory.baseReg, buffer, blen);
428		ADVANCE(written);
429		if (info->memory.format & ARM_MEMORY_WRITEBACK) {
430			strlcpy(buffer, "!", blen);
431			ADVANCE(1);
432		}
433		strlcpy(buffer, ", ", blen);
434		ADVANCE(2);
435		written = _decodeRegisterList(info->op1.immediate, buffer, blen);
436		ADVANCE(written);
437		if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
438			strlcpy(buffer, "^", blen);
439			ADVANCE(1);
440		}
441		break;
442	case ARM_MN_B:
443	case ARM_MN_BL:
444		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
445			written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen);
446			ADVANCE(written);
447		}
448		break;
449	default:
450		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
451			written = snprintf(buffer, blen, "#%i", info->op1.immediate);
452			ADVANCE(written);
453		} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
454			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
455			ADVANCE(written);
456		} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
457			written = _decodeRegister(info->op1.reg, buffer, blen);
458			ADVANCE(written);
459			if (info->op1.reg > ARM_PC) {
460				written = _decodePSR(info->op1.psrBits, buffer, blen);
461				ADVANCE(written);
462			}
463		}
464		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
465			written = _decodeShift(info->op1, true, buffer, blen);
466			ADVANCE(written);
467		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
468			written = _decodeShift(info->op1, false, buffer, blen);
469			ADVANCE(written);
470		}
471		if (info->operandFormat & ARM_OPERAND_2) {
472			strlcpy(buffer, ", ", blen);
473			ADVANCE(2);
474		}
475		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
476			written = snprintf(buffer, blen, "#%i", info->op2.immediate);
477			ADVANCE(written);
478		} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
479			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
480			ADVANCE(written);
481		} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
482			written = _decodeRegister(info->op2.reg, buffer, blen);
483			ADVANCE(written);
484		}
485		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
486			written = _decodeShift(info->op2, true, buffer, blen);
487			ADVANCE(written);
488		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
489			written = _decodeShift(info->op2, false, buffer, blen);
490			ADVANCE(written);
491		}
492		if (info->operandFormat & ARM_OPERAND_3) {
493			strlcpy(buffer, ", ", blen);
494			ADVANCE(2);
495		}
496		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
497			written = snprintf(buffer, blen, "#%i", info->op3.immediate);
498			ADVANCE(written);
499		} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
500			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
501			ADVANCE(written);
502		} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
503			written = _decodeRegister(info->op3.reg, buffer, blen);
504			ADVANCE(written);
505		}
506		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
507			written = _decodeShift(info->op3, true, buffer, blen);
508			ADVANCE(written);
509		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
510			written = _decodeShift(info->op3, false, buffer, blen);
511			ADVANCE(written);
512		}
513		if (info->operandFormat & ARM_OPERAND_4) {
514			strlcpy(buffer, ", ", blen);
515			ADVANCE(2);
516		}
517		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
518			written = snprintf(buffer, blen, "#%i", info->op4.immediate);
519			ADVANCE(written);
520		} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
521			written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
522			ADVANCE(written);
523		} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
524			written = _decodeRegister(info->op4.reg, buffer, blen);
525			ADVANCE(written);
526		}
527		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
528			written = _decodeShift(info->op4, true, buffer, blen);
529			ADVANCE(written);
530		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
531			written = _decodeShift(info->op4, false, buffer, blen);
532			ADVANCE(written);
533		}
534		break;
535	}
536	buffer[blen - 1] = '\0';
537	return total;
538}
539
540uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc) {
541	uint32_t address = 0;
542	int32_t offset = 0;
543	if (info->memory.format & ARM_MEMORY_REGISTER_BASE) {
544		if (info->memory.baseReg == ARM_PC && info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
545			address = pc;
546		} else {
547			address = regs->gprs[info->memory.baseReg];
548		}
549	}
550	if (info->memory.format & ARM_MEMORY_POST_INCREMENT) {
551		return address;
552	}
553	if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
554		offset = info->memory.offset.immediate;
555	} else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) {
556		offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg];
557	}
558	if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
559		uint8_t shiftSize = info->memory.offset.shifterImm;
560		switch (info->memory.offset.shifterOp) {
561			case ARM_SHIFT_LSL:
562				offset <<= shiftSize;
563				break;
564			case ARM_SHIFT_LSR:
565				offset = ((uint32_t) offset) >> shiftSize;
566				break;
567			case ARM_SHIFT_ASR:
568				offset >>= shiftSize;
569				break;
570			case ARM_SHIFT_ROR:
571				offset = ROR(offset, shiftSize);
572				break;
573			case ARM_SHIFT_RRX:
574				offset = (regs->cpsr.c << 31) | ((uint32_t) offset >> 1);
575				break;
576			default:
577				break;
578		};
579	}
580	return address + (info->memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -offset : offset);
581}