all repos — mgba @ 8b44ea61ab5c0a866f2e3b4bb004b757967ae2ac

mGBA Game Boy Advance Emulator

src/arm/decoder.c (view raw)

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