all repos — mgba @ 17a2e2a2141db116c1663deea071540cd75887f5

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