all repos — mgba @ b41e11d4c11ffb8b86df626794c31bc0ba10f261

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);
 18
 19static const char* _armConditions[] = {
 20	"eq",
 21	"ne",
 22	"cs",
 23	"cc",
 24	"mi",
 25	"pl",
 26	"vs",
 27	"vc",
 28	"hi",
 29	"ls",
 30	"ge",
 31	"lt",
 32	"gt",
 33	"le",
 34	"al",
 35	"nv"
 36};
 37
 38static int _decodeRegister(int reg, char* buffer, int blen) {
 39	switch (reg) {
 40	case ARM_SP:
 41		strncpy(buffer, "sp", blen - 1);
 42		return 2;
 43	case ARM_LR:
 44		strncpy(buffer, "lr", blen - 1);
 45		return 2;
 46	case ARM_PC:
 47		strncpy(buffer, "pc", blen - 1);
 48		return 2;
 49	case ARM_CPSR:
 50		strncpy(buffer, "cpsr", blen - 1);
 51		return 4;
 52	case ARM_SPSR:
 53		strncpy(buffer, "spsr", blen - 1);
 54		return 4;
 55	default:
 56		return snprintf(buffer, blen - 1, "r%i", reg);
 57	}
 58}
 59
 60static int _decodeRegisterList(int list, char* buffer, int blen) {
 61	if (blen <= 0) {
 62		return 0;
 63	}
 64	int total = 0;
 65	strncpy(buffer, "{", blen - 1);
 66	ADVANCE(1);
 67	int i;
 68	int start = -1;
 69	int end = -1;
 70	int written;
 71	for (i = 0; i <= ARM_PC; ++i) {
 72		if (list & 1) {
 73			if (start < 0) {
 74				start = i;
 75				end = i;
 76			} else if (end + 1 == i) {
 77				end = i;
 78			} else {
 79				if (end > start) {
 80					written = _decodeRegister(start, buffer, blen);
 81					ADVANCE(written);
 82					strncpy(buffer, "-", blen - 1);
 83					ADVANCE(1);
 84				}
 85				written = _decodeRegister(end, buffer, blen);
 86				ADVANCE(written);
 87				strncpy(buffer, ",", blen - 1);
 88				ADVANCE(1);
 89				start = i;
 90				end = i;
 91			}
 92		}
 93		list >>= 1;
 94	}
 95	if (start >= 0) {
 96		if (end > start) {
 97			written = _decodeRegister(start, buffer, blen);
 98			ADVANCE(written);
 99			strncpy(buffer, "-", blen - 1);
100			ADVANCE(1);
101		}
102		written = _decodeRegister(end, buffer, blen);
103		ADVANCE(written);
104	}
105	strncpy(buffer, "}", blen - 1);
106	ADVANCE(1);
107	return total;
108}
109
110static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
111	return snprintf(buffer, blen - 1, "$%08X", address + pc);
112}
113
114static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
115	if (blen <= 1) {
116		return 0;
117	}
118	int total = 0;
119	strncpy(buffer, "[", blen - 1);
120	ADVANCE(1);
121	int written;
122	if (memory.format & ARM_MEMORY_REGISTER_BASE) {
123		if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
124			written = _decodePCRelative(memory.offset.immediate, pc, buffer, blen);
125			ADVANCE(written);
126		} else {
127			written = _decodeRegister(memory.baseReg, buffer, blen);
128			ADVANCE(written);
129			if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
130				strncpy(buffer, ", ", blen - 1);
131				ADVANCE(2);
132			}
133		}
134	}
135	if (memory.format & ARM_MEMORY_POST_INCREMENT) {
136		strncpy(buffer, "], ", blen - 1);
137		ADVANCE(3);
138	}
139	if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
140		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
141			written = snprintf(buffer, blen - 1, "#-%i", memory.offset.immediate);
142			ADVANCE(written);
143		} else {
144			written = snprintf(buffer, blen - 1, "#%i", memory.offset.immediate);
145			ADVANCE(written);
146		}
147	} else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
148		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
149			strncpy(buffer, "-", blen - 1);
150			ADVANCE(1);
151		}
152		written = _decodeRegister(memory.offset.reg, buffer, blen);
153		ADVANCE(written);
154	}
155	// TODO: shifted registers
156
157	if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
158		strncpy(buffer, "]", blen - 1);
159		ADVANCE(1);
160	}
161	if ((memory.format & (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) == (ARM_MEMORY_PRE_INCREMENT | ARM_MEMORY_WRITEBACK)) {
162		strncpy(buffer, "!", blen - 1);
163		ADVANCE(1);
164	}
165	return total;
166}
167
168static const char* _armMnemonicStrings[] = {
169	"ill",
170	"adc",
171	"add",
172	"and",
173	"asr",
174	"b",
175	"bic",
176	"bkpt",
177	"bl",
178	"blh",
179	"bx",
180	"cmn",
181	"cmp",
182	"eor",
183	"ldm",
184	"ldr",
185	"lsl",
186	"lsr",
187	"mla",
188	"mov",
189	"mrs",
190	"msr",
191	"mul",
192	"mvn",
193	"neg",
194	"orr",
195	"ror",
196	"rsb",
197	"rsc",
198	"sbc",
199	"smlal",
200	"smull",
201	"stm",
202	"str",
203	"sub",
204	"swi",
205	"swp",
206	"teq",
207	"tst",
208	"umlal",
209	"umull",
210
211	"ill"
212};
213
214static const char* _armDirectionStrings[] = {
215	"da",
216	"ia",
217	"db",
218	"da"
219};
220
221static const char* _armAccessTypeStrings[] = {
222	"",
223	"b",
224	"h",
225	"",
226	"",
227	"",
228	"",
229	"",
230	"",
231	"sb",
232	"sh",
233	""
234	""
235};
236
237int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
238	const char* mnemonic = _armMnemonicStrings[info->mnemonic];
239	int written;
240	int total = 0;
241	const char* cond = "";
242	if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
243		cond = _armConditions[info->condition];
244	}
245	const char* flags = "";
246	switch (info->mnemonic) {
247	case ARM_MN_LDM:
248	case ARM_MN_STM:
249		flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
250		break;
251	case ARM_MN_LDR:
252	case ARM_MN_STR:
253	case ARM_MN_SWP:
254		flags = _armAccessTypeStrings[info->memory.width];
255		break;
256	case ARM_MN_ADD:
257	case ARM_MN_ADC:
258	case ARM_MN_AND:
259	case ARM_MN_BIC:
260	case ARM_MN_EOR:
261	case ARM_MN_MOV:
262	case ARM_MN_MVN:
263	case ARM_MN_ORR:
264	case ARM_MN_RSB:
265	case ARM_MN_RSC:
266	case ARM_MN_SBC:
267	case ARM_MN_SUB:
268		if (info->affectsCPSR && info->execMode == MODE_ARM) {
269			flags = "s";
270		}
271		break;
272	default:
273		break;
274	}
275	written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
276	ADVANCE(written);
277
278	switch (info->mnemonic) {
279	case ARM_MN_LDM:
280	case ARM_MN_STM:
281		written = _decodeRegister(info->memory.baseReg, buffer, blen);
282		ADVANCE(written);
283		if (info->memory.format & ARM_MEMORY_WRITEBACK) {
284			strncpy(buffer, "!", blen - 1);
285			ADVANCE(1);
286		}
287		strncpy(buffer, ", ", blen - 1);
288		ADVANCE(2);
289		written = _decodeRegisterList(info->op1.immediate, buffer, blen);
290		ADVANCE(written);
291		break;
292	case ARM_MN_B:
293		written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
294		ADVANCE(written);
295		break;
296	default:
297		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
298			written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
299			ADVANCE(written);
300		} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
301			written = _decodeMemory(info->memory, pc, buffer, blen);
302			ADVANCE(written);
303		} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
304			written = _decodeRegister(info->op1.reg, buffer, blen);
305			ADVANCE(written);
306		}
307		if (info->operandFormat & ARM_OPERAND_2) {
308			strncpy(buffer, ", ", blen);
309			ADVANCE(2);
310		}
311		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
312			written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
313			ADVANCE(written);
314		} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
315			written = _decodeMemory(info->memory, pc, buffer, blen);
316			ADVANCE(written);
317		} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
318			written = _decodeRegister(info->op2.reg, buffer, blen);
319			ADVANCE(written);
320		}
321		if (info->operandFormat & ARM_OPERAND_3) {
322			strncpy(buffer, ", ", blen - 1);
323			ADVANCE(2);
324		}
325		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
326			written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
327			ADVANCE(written);
328		} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
329			written = _decodeMemory(info->memory, pc, buffer, blen);
330			ADVANCE(written);
331		} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
332			written = _decodeRegister(info->op3.reg, buffer, blen);
333			ADVANCE(written);
334		}
335		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
336			written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
337			ADVANCE(written);
338		} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
339			written = _decodeMemory(info->memory, pc, buffer, blen);
340			ADVANCE(written);
341		} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
342			written = _decodeRegister(info->op4.reg, buffer, blen);
343			ADVANCE(written);
344		}
345		break;
346	}
347	buffer[blen - 1] = '\0';
348	return total;
349}