all repos — mgba @ e6ea94d2296eae963a48a18d009217a38d92bf9b

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	if (memory.format & ARM_MEMORY_SHIFTED_OFFSET) {
157		written = _decodeShift(memory.offset, false, buffer, blen);
158		ADVANCE(written);
159	}
160
161	if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
162		strncpy(buffer, "]", blen - 1);
163		ADVANCE(1);
164	}
165	if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
166		strncpy(buffer, "!", blen - 1);
167		ADVANCE(1);
168	}
169	return total;
170}
171
172static int _decodeShift(union ARMOperand op, bool reg, char* buffer, int blen) {
173	if (blen <= 1) {
174		return 0;
175	}
176	int total = 0;
177	strncpy(buffer, ", ", blen - 1);
178	ADVANCE(2);
179	int written;
180	switch (op.shifterOp) {
181	case ARM_SHIFT_LSL:
182		strncpy(buffer, "lsl ", blen - 1);
183		ADVANCE(4);
184		break;
185	case ARM_SHIFT_LSR:
186		strncpy(buffer, "lsr ", blen - 1);
187		ADVANCE(4);
188		break;
189	case ARM_SHIFT_ASR:
190		strncpy(buffer, "asr ", blen - 1);
191		ADVANCE(4);
192		break;
193	case ARM_SHIFT_ROR:
194		strncpy(buffer, "ror ", blen - 1);
195		ADVANCE(4);
196		break;
197	case ARM_SHIFT_RRX:
198		strncpy(buffer, "rrx", blen - 1);
199		ADVANCE(3);
200		return total;
201	}
202	if (!reg) {
203		written = snprintf(buffer, blen - 1, "#%i", op.shifterImm);
204	} else {
205		written = _decodeRegister(op.shifterReg, buffer, blen);
206	}
207	ADVANCE(written);
208	return total;
209}
210
211static const char* _armMnemonicStrings[] = {
212	"ill",
213	"adc",
214	"add",
215	"and",
216	"asr",
217	"b",
218	"bic",
219	"bkpt",
220	"bl",
221	"blh",
222	"bx",
223	"cmn",
224	"cmp",
225	"eor",
226	"ldm",
227	"ldr",
228	"lsl",
229	"lsr",
230	"mla",
231	"mov",
232	"mrs",
233	"msr",
234	"mul",
235	"mvn",
236	"neg",
237	"orr",
238	"ror",
239	"rsb",
240	"rsc",
241	"sbc",
242	"smlal",
243	"smull",
244	"stm",
245	"str",
246	"sub",
247	"swi",
248	"swp",
249	"teq",
250	"tst",
251	"umlal",
252	"umull",
253
254	"ill"
255};
256
257static const char* _armDirectionStrings[] = {
258	"da",
259	"ia",
260	"db",
261	"ib"
262};
263
264static const char* _armAccessTypeStrings[] = {
265	"",
266	"b",
267	"h",
268	"",
269	"",
270	"",
271	"",
272	"",
273
274	"",
275	"sb",
276	"sh",
277	"",
278	"",
279	"",
280	"",
281	"",
282
283	"",
284	"bt",
285	"",
286	"",
287	"t",
288	"",
289	"",
290	""
291};
292
293int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
294	const char* mnemonic = _armMnemonicStrings[info->mnemonic];
295	int written;
296	int total = 0;
297	const char* cond = "";
298	if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
299		cond = _armConditions[info->condition];
300	}
301	const char* flags = "";
302	switch (info->mnemonic) {
303	case ARM_MN_LDM:
304	case ARM_MN_STM:
305		flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
306		break;
307	case ARM_MN_LDR:
308	case ARM_MN_STR:
309	case ARM_MN_SWP:
310		flags = _armAccessTypeStrings[info->memory.width];
311		break;
312	case ARM_MN_ADD:
313	case ARM_MN_ADC:
314	case ARM_MN_AND:
315	case ARM_MN_BIC:
316	case ARM_MN_EOR:
317	case ARM_MN_MOV:
318	case ARM_MN_MVN:
319	case ARM_MN_ORR:
320	case ARM_MN_RSB:
321	case ARM_MN_RSC:
322	case ARM_MN_SBC:
323	case ARM_MN_SUB:
324		if (info->affectsCPSR && info->execMode == MODE_ARM) {
325			flags = "s";
326		}
327		break;
328	default:
329		break;
330	}
331	written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
332	ADVANCE(written);
333
334	switch (info->mnemonic) {
335	case ARM_MN_LDM:
336	case ARM_MN_STM:
337		written = _decodeRegister(info->memory.baseReg, buffer, blen);
338		ADVANCE(written);
339		if (info->memory.format & ARM_MEMORY_WRITEBACK) {
340			strncpy(buffer, "!", blen - 1);
341			ADVANCE(1);
342		}
343		strncpy(buffer, ", ", blen - 1);
344		ADVANCE(2);
345		written = _decodeRegisterList(info->op1.immediate, buffer, blen);
346		ADVANCE(written);
347		if (info->memory.format & ARM_MEMORY_SPSR_SWAP) {
348			strncpy(buffer, "^", blen - 1);
349			ADVANCE(1);
350		}
351		break;
352	case ARM_MN_B:
353		written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
354		ADVANCE(written);
355		break;
356	default:
357		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
358			written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
359			ADVANCE(written);
360		} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
361			written = _decodeMemory(info->memory, pc, buffer, blen);
362			ADVANCE(written);
363		} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
364			written = _decodeRegister(info->op1.reg, buffer, blen);
365			ADVANCE(written);
366		}
367		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) {
368			written = _decodeShift(info->op1, true, buffer, blen);
369			ADVANCE(written);
370		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_1) {
371			written = _decodeShift(info->op1, false, buffer, blen);
372			ADVANCE(written);
373		}
374		if (info->operandFormat & ARM_OPERAND_2) {
375			strncpy(buffer, ", ", blen);
376			ADVANCE(2);
377		}
378		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
379			written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
380			ADVANCE(written);
381		} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
382			written = _decodeMemory(info->memory, pc, buffer, blen);
383			ADVANCE(written);
384		} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
385			written = _decodeRegister(info->op2.reg, buffer, blen);
386			ADVANCE(written);
387		}
388		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) {
389			written = _decodeShift(info->op2, true, buffer, blen);
390			ADVANCE(written);
391		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_2) {
392			written = _decodeShift(info->op2, false, buffer, blen);
393			ADVANCE(written);
394		}
395		if (info->operandFormat & ARM_OPERAND_3) {
396			strncpy(buffer, ", ", blen - 1);
397			ADVANCE(2);
398		}
399		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
400			written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
401			ADVANCE(written);
402		} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
403			written = _decodeMemory(info->memory, pc, buffer, blen);
404			ADVANCE(written);
405		} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
406			written = _decodeRegister(info->op3.reg, buffer, blen);
407			ADVANCE(written);
408		}
409		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) {
410			written = _decodeShift(info->op3, true, buffer, blen);
411			ADVANCE(written);
412		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_3) {
413			written = _decodeShift(info->op3, false, buffer, blen);
414			ADVANCE(written);
415		}
416		if (info->operandFormat & ARM_OPERAND_4) {
417			strncpy(buffer, ", ", blen - 1);
418			ADVANCE(2);
419		}
420		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
421			written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
422			ADVANCE(written);
423		} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
424			written = _decodeMemory(info->memory, pc, buffer, blen);
425			ADVANCE(written);
426		} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
427			written = _decodeRegister(info->op4.reg, buffer, blen);
428			ADVANCE(written);
429		}
430		if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) {
431			written = _decodeShift(info->op4, true, buffer, blen);
432			ADVANCE(written);
433		} else if (info->operandFormat & ARM_OPERAND_SHIFT_IMMEDIATE_4) {
434			written = _decodeShift(info->op4, false, buffer, blen);
435			ADVANCE(written);
436		}
437		break;
438	}
439	buffer[blen - 1] = '\0';
440	return total;
441}