all repos — mgba @ cb0f95b07053e63e817bd05df0a36bf917667d09

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