all repos — mgba @ 43ddcf56ccacd251713804c3e166c6833518ec0c

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 "decoder.h"
  7
  8#include "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 _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen);
 22static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen);
 23static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
 24
 25static const char* _armConditions[] = {
 26	"eq",
 27	"ne",
 28	"cs",
 29	"cc",
 30	"mi",
 31	"pl",
 32	"vs",
 33	"vc",
 34	"hi",
 35	"ls",
 36	"ge",
 37	"lt",
 38	"gt",
 39	"le",
 40	"al",
 41	"nv"
 42};
 43
 44static int _decodeRegister(int reg, char* buffer, int blen) {
 45	switch (reg) {
 46	case ARM_SP:
 47		strncpy(buffer, "sp", blen - 1);
 48		return 2;
 49	case ARM_LR:
 50		strncpy(buffer, "lr", blen - 1);
 51		return 2;
 52	case ARM_PC:
 53		strncpy(buffer, "pc", blen - 1);
 54		return 2;
 55	case ARM_CPSR:
 56		strncpy(buffer, "cpsr", blen - 1);
 57		return 4;
 58	case ARM_SPSR:
 59		strncpy(buffer, "spsr", blen - 1);
 60		return 4;
 61	default:
 62		return snprintf(buffer, blen - 1, "r%i", reg);
 63	}
 64}
 65
 66static int _decodeRegisterList(int list, char* buffer, int blen) {
 67	if (blen <= 0) {
 68		return 0;
 69	}
 70	int total = 0;
 71	strncpy(buffer, "{", blen - 1);
 72	ADVANCE(1);
 73	int i;
 74	int start = -1;
 75	int end = -1;
 76	int written;
 77	for (i = 0; i <= ARM_PC; ++i) {
 78		if (list & 1) {
 79			if (start < 0) {
 80				start = i;
 81				end = i;
 82			} else if (end + 1 == i) {
 83				end = i;
 84			} else {
 85				if (end > start) {
 86					written = _decodeRegister(start, buffer, blen);
 87					ADVANCE(written);
 88					strncpy(buffer, "-", blen - 1);
 89					ADVANCE(1);
 90				}
 91				written = _decodeRegister(end, buffer, blen);
 92				ADVANCE(written);
 93				strncpy(buffer, ",", blen - 1);
 94				ADVANCE(1);
 95				start = i;
 96				end = i;
 97			}
 98		}
 99		list >>= 1;
100	}
101	if (start >= 0) {
102		if (end > start) {
103			written = _decodeRegister(start, buffer, blen);
104			ADVANCE(written);
105			strncpy(buffer, "-", blen - 1);
106			ADVANCE(1);
107		}
108		written = _decodeRegister(end, buffer, blen);
109		ADVANCE(written);
110	}
111	strncpy(buffer, "}", blen - 1);
112	ADVANCE(1);
113	return total;
114}
115
116static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
117	return snprintf(buffer, blen - 1, "$%08X", address + pc);
118}
119
120static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
121	if (blen <= 1) {
122		return 0;
123	}
124	int total = 0;
125	strncpy(buffer, "[", blen - 1);
126	ADVANCE(1);
127	int written;
128	if (memory.format & ARM_MEMORY_REGISTER_BASE) {
129		if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
130			written = _decodePCRelative(memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate, pc & 0xFFFFFFFC, buffer, blen);
131			ADVANCE(written);
132		} else {
133			written = _decodeRegister(memory.baseReg, buffer, blen);
134			ADVANCE(written);
135			if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
136				strncpy(buffer, ", ", blen - 1);
137				ADVANCE(2);
138			}
139		}
140	}
141	if (memory.format & ARM_MEMORY_POST_INCREMENT) {
142		strncpy(buffer, "], ", blen - 1);
143		ADVANCE(3);
144	}
145	if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
146		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
147			written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate);
148			ADVANCE(written);
149		} else {
150			written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate);
151			ADVANCE(written);
152		}
153	} else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
154		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
155			strncpy(buffer, "-", blen - 1);
156			ADVANCE(1);
157		}
158		written = _decodeRegister(memory.offset.reg, buffer, blen);
159		ADVANCE(written);
160	}
161	if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
162		written = _decodeShift(memory.offset, false, buffer, blen);
163		ADVANCE(written);
164	}
165
166	if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
167		strncpy(buffer, "]", blen - 1);
168		ADVANCE(1);
169	}
170	if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
171		strncpy(buffer, "!", blen - 1);
172		ADVANCE(1);
173	}
174	return total;
175}
176
177static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
178	if (blen <= 1) {
179		return 0;
180	}
181	int total = 0;
182	strncpy(buffer, ", ", blen - 1);
183	ADVANCE(2);
184	int written;
185	switch (op.shifterOp) {
186	case ARM_SHIFT_LSL:
187		strncpy(buffer, "lsl ", blen - 1);
188		ADVANCE(4);
189		break;
190	case ARM_SHIFT_LSR:
191		strncpy(buffer, "lsr ", blen - 1);
192		ADVANCE(4);
193		break;
194	case ARM_SHIFT_ASR:
195		strncpy(buffer, "asr ", blen - 1);
196		ADVANCE(4);
197		break;
198	case ARM_SHIFT_ROR:
199		strncpy(buffer, "ror ", blen - 1);
200		ADVANCE(4);
201		break;
202	case ARM_SHIFT_RRX:
203		strncpy(buffer, "rrx", blen - 1);
204		ADVANCE(3);
205		return total;
206	}
207	if (!reg) {
208		written = snprintf(buffer, blen - 1, "#%i", op.shifterImm);
209	} else {
210		written = _decodeRegister(op.shifterReg, buffer, blen);
211	}
212	ADVANCE(written);
213	return total;
214}
215
216static const char* _armMnemonicStrings[] = {
217	"ill",
218	"adc",
219	"add",
220	"and",
221	"asr",
222	"b",
223	"bic",
224	"bkpt",
225	"bl",
226	"bx",
227	"cmn",
228	"cmp",
229	"eor",
230	"ldm",
231	"ldr",
232	"lsl",
233	"lsr",
234	"mla",
235	"mov",
236	"mrs",
237	"msr",
238	"mul",
239	"mvn",
240	"neg",
241	"orr",
242	"ror",
243	"rsb",
244	"rsc",
245	"sbc",
246	"smlal",
247	"smull",
248	"stm",
249	"str",
250	"sub",
251	"swi",
252	"swp",
253	"teq",
254	"tst",
255	"umlal",
256	"umull",
257
258	"ill"
259};
260
261static const char* _armDirectionStrings[] = {
262	"da",
263	"ia",
264	"db",
265	"ib"
266};
267
268static const char* _armAccessTypeStrings[] = {
269	"",
270	"b",
271	"h",
272	"",
273	"",
274	"",
275	"",
276	"",
277
278	"",
279	"sb",
280	"sh",
281	"",
282	"",
283	"",
284	"",
285	"",
286
287	"",
288	"bt",
289	"",
290	"",
291	"t",
292	"",
293	"",
294	""
295};
296
297int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
298	const char* mnemonic = _armMnemonicStrings[info->mnemonic];
299	int written;
300	int total = 0;
301	const char* cond = "";
302	if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
303		cond = _armConditions[info->condition];
304	}
305	const char* flags = "";
306	switch (info->mnemonic) {
307	case ARM_MN_LDM:
308	case ARM_MN_STM:
309		flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
310		break;
311	case ARM_MN_LDR:
312	case ARM_MN_STR:
313	case ARM_MN_SWP:
314		flags = _armAccessTypeStrings[info->memory.width];
315		break;
316	case ARM_MN_ADD:
317	case ARM_MN_ADC:
318	case ARM_MN_AND:
319	case ARM_MN_BIC:
320	case ARM_MN_EOR:
321	case ARM_MN_MOV:
322	case ARM_MN_MVN:
323	case ARM_MN_ORR:
324	case ARM_MN_RSB:
325	case ARM_MN_RSC:
326	case ARM_MN_SBC:
327	case ARM_MN_SUB:
328		if (info->affectsCPSR && info->execMode == MODE_ARM) {
329			flags = "s";
330		}
331		break;
332	default:
333		break;
334	}
335	written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
336	ADVANCE(written);
337
338	switch (info->mnemonic) {
339	case ARM_MN_LDM:
340	case ARM_MN_STM:
341		written = _decodeRegister(info->memory.baseReg, buffer, blen);
342		ADVANCE(written);
343		if (info->memory.format & ARM_MEMORY_WRITEBACK) {
344			strncpy(buffer, "!", blen - 1);
345			ADVANCE(1);
346		}
347		strncpy(buffer, ", ", blen - 1);
348		ADVANCE(2);
349		written = _decodeRegisterList(info->op1.immediate, buffer, blen);
350		ADVANCE(written);
351		if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
352			strncpy(buffer, "^", blen - 1);
353			ADVANCE(1);
354		}
355		break;
356	case ARM_MN_B:
357	case ARM_MN_BL:
358		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
359			written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
360			ADVANCE(written);
361		}
362		break;
363	default:
364		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
365			written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
366			ADVANCE(written);
367		} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
368			written = _decodeMemory(info->memory, pc, buffer, blen);
369			ADVANCE(written);
370		} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
371			written = _decodeRegister(info->op1.reg, buffer, blen);
372			ADVANCE(written);
373		}
374		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
375			written = _decodeShift(info->op1, true, buffer, blen);
376			ADVANCE(written);
377		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
378			written = _decodeShift(info->op1, false, buffer, blen);
379			ADVANCE(written);
380		}
381		if (info->operandFormat & ARM_OPERAND_2) {
382			strncpy(buffer, ", ", blen);
383			ADVANCE(2);
384		}
385		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
386			written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
387			ADVANCE(written);
388		} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
389			written = _decodeMemory(info->memory, pc, buffer, blen);
390			ADVANCE(written);
391		} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
392			written = _decodeRegister(info->op2.reg, buffer, blen);
393			ADVANCE(written);
394		}
395		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
396			written = _decodeShift(info->op2, true, buffer, blen);
397			ADVANCE(written);
398		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
399			written = _decodeShift(info->op2, false, buffer, blen);
400			ADVANCE(written);
401		}
402		if (info->operandFormat & ARM_OPERAND_3) {
403			strncpy(buffer, ", ", blen - 1);
404			ADVANCE(2);
405		}
406		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
407			written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
408			ADVANCE(written);
409		} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
410			written = _decodeMemory(info->memory, pc, buffer, blen);
411			ADVANCE(written);
412		} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
413			written = _decodeRegister(info->op3.reg, buffer, blen);
414			ADVANCE(written);
415		}
416		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
417			written = _decodeShift(info->op3, true, buffer, blen);
418			ADVANCE(written);
419		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
420			written = _decodeShift(info->op3, false, buffer, blen);
421			ADVANCE(written);
422		}
423		if (info->operandFormat & ARM_OPERAND_4) {
424			strncpy(buffer, ", ", blen - 1);
425			ADVANCE(2);
426		}
427		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
428			written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
429			ADVANCE(written);
430		} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
431			written = _decodeMemory(info->memory, pc, buffer, blen);
432			ADVANCE(written);
433		} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
434			written = _decodeRegister(info->op4.reg, buffer, blen);
435			ADVANCE(written);
436		}
437		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
438			written = _decodeShift(info->op4, true, buffer, blen);
439			ADVANCE(written);
440		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
441			written = _decodeShift(info->op4, false, buffer, blen);
442			ADVANCE(written);
443		}
444		break;
445	}
446	buffer[blen - 1] = '\0';
447	return total;
448}