all repos — mgba @ 10ba7d16b30b675261ce65d9741119eb930250eb

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	"blh",
227	"bx",
228	"cmn",
229	"cmp",
230	"eor",
231	"ldm",
232	"ldr",
233	"lsl",
234	"lsr",
235	"mla",
236	"mov",
237	"mrs",
238	"msr",
239	"mul",
240	"mvn",
241	"neg",
242	"orr",
243	"ror",
244	"rsb",
245	"rsc",
246	"sbc",
247	"smlal",
248	"smull",
249	"stm",
250	"str",
251	"sub",
252	"swi",
253	"swp",
254	"teq",
255	"tst",
256	"umlal",
257	"umull",
258
259	"ill"
260};
261
262static const char* _armDirectionStrings[] = {
263	"da",
264	"ia",
265	"db",
266	"ib"
267};
268
269static const char* _armAccessTypeStrings[] = {
270	"",
271	"b",
272	"h",
273	"",
274	"",
275	"",
276	"",
277	"",
278
279	"",
280	"sb",
281	"sh",
282	"",
283	"",
284	"",
285	"",
286	"",
287
288	"",
289	"bt",
290	"",
291	"",
292	"t",
293	"",
294	"",
295	""
296};
297
298int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
299	const char* mnemonic = _armMnemonicStrings[info->mnemonic];
300	int written;
301	int total = 0;
302	const char* cond = "";
303	if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
304		cond = _armConditions[info->condition];
305	}
306	const char* flags = "";
307	switch (info->mnemonic) {
308	case ARM_MN_LDM:
309	case ARM_MN_STM:
310		flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
311		break;
312	case ARM_MN_LDR:
313	case ARM_MN_STR:
314	case ARM_MN_SWP:
315		flags = _armAccessTypeStrings[info->memory.width];
316		break;
317	case ARM_MN_ADD:
318	case ARM_MN_ADC:
319	case ARM_MN_AND:
320	case ARM_MN_BIC:
321	case ARM_MN_EOR:
322	case ARM_MN_MOV:
323	case ARM_MN_MVN:
324	case ARM_MN_ORR:
325	case ARM_MN_RSB:
326	case ARM_MN_RSC:
327	case ARM_MN_SBC:
328	case ARM_MN_SUB:
329		if (info->affectsCPSR && info->execMode == MODE_ARM) {
330			flags = "s";
331		}
332		break;
333	default:
334		break;
335	}
336	written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
337	ADVANCE(written);
338
339	switch (info->mnemonic) {
340	case ARM_MN_LDM:
341	case ARM_MN_STM:
342		written = _decodeRegister(info->memory.baseReg, buffer, blen);
343		ADVANCE(written);
344		if (info->memory.format & ARM_MEMORY_WRITEBACK) {
345			strncpy(buffer, "!", blen - 1);
346			ADVANCE(1);
347		}
348		strncpy(buffer, ", ", blen - 1);
349		ADVANCE(2);
350		written = _decodeRegisterList(info->op1.immediate, buffer, blen);
351		ADVANCE(written);
352		if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
353			strncpy(buffer, "^", blen - 1);
354			ADVANCE(1);
355		}
356		break;
357	case ARM_MN_B:
358		written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
359		ADVANCE(written);
360		break;
361	default:
362		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
363			written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
364			ADVANCE(written);
365		} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
366			written = _decodeMemory(info->memory, pc, buffer, blen);
367			ADVANCE(written);
368		} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
369			written = _decodeRegister(info->op1.reg, buffer, blen);
370			ADVANCE(written);
371		}
372		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
373			written = _decodeShift(info->op1, true, buffer, blen);
374			ADVANCE(written);
375		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
376			written = _decodeShift(info->op1, false, buffer, blen);
377			ADVANCE(written);
378		}
379		if (info->operandFormat & ARM_OPERAND_2) {
380			strncpy(buffer, ", ", blen);
381			ADVANCE(2);
382		}
383		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
384			written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
385			ADVANCE(written);
386		} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
387			written = _decodeMemory(info->memory, pc, buffer, blen);
388			ADVANCE(written);
389		} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
390			written = _decodeRegister(info->op2.reg, buffer, blen);
391			ADVANCE(written);
392		}
393		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
394			written = _decodeShift(info->op2, true, buffer, blen);
395			ADVANCE(written);
396		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
397			written = _decodeShift(info->op2, false, buffer, blen);
398			ADVANCE(written);
399		}
400		if (info->operandFormat & ARM_OPERAND_3) {
401			strncpy(buffer, ", ", blen - 1);
402			ADVANCE(2);
403		}
404		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
405			written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
406			ADVANCE(written);
407		} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
408			written = _decodeMemory(info->memory, pc, buffer, blen);
409			ADVANCE(written);
410		} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
411			written = _decodeRegister(info->op3.reg, buffer, blen);
412			ADVANCE(written);
413		}
414		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
415			written = _decodeShift(info->op3, true, buffer, blen);
416			ADVANCE(written);
417		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
418			written = _decodeShift(info->op3, false, buffer, blen);
419			ADVANCE(written);
420		}
421		if (info->operandFormat & ARM_OPERAND_4) {
422			strncpy(buffer, ", ", blen - 1);
423			ADVANCE(2);
424		}
425		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
426			written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
427			ADVANCE(written);
428		} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
429			written = _decodeMemory(info->memory, pc, buffer, blen);
430			ADVANCE(written);
431		} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
432			written = _decodeRegister(info->op4.reg, buffer, blen);
433			ADVANCE(written);
434		}
435		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
436			written = _decodeShift(info->op4, true, buffer, blen);
437			ADVANCE(written);
438		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
439			written = _decodeShift(info->op4, false, buffer, blen);
440			ADVANCE(written);
441		}
442		break;
443	}
444	buffer[blen - 1] = '\0';
445	return total;
446}