all repos — mgba @ 6b382caa0f2936df4918c05e8a414b9681523a9e

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	"",
232	"sb",
233	"sh",
234	"",
235	"",
236	"",
237	"",
238	"",
239
240	"",
241	"tb",
242	"",
243	"",
244	"t",
245	"",
246	"",
247	""
248};
249
250int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
251	const char* mnemonic = _armMnemonicStrings[info->mnemonic];
252	int written;
253	int total = 0;
254	const char* cond = "";
255	if (info->condition != ARM_CONDITION_AL && info->condition < ARM_CONDITION_NV) {
256		cond = _armConditions[info->condition];
257	}
258	const char* flags = "";
259	switch (info->mnemonic) {
260	case ARM_MN_LDM:
261	case ARM_MN_STM:
262		flags = _armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info->memory.format)];
263		break;
264	case ARM_MN_LDR:
265	case ARM_MN_STR:
266	case ARM_MN_SWP:
267		flags = _armAccessTypeStrings[info->memory.width];
268		break;
269	case ARM_MN_ADD:
270	case ARM_MN_ADC:
271	case ARM_MN_AND:
272	case ARM_MN_BIC:
273	case ARM_MN_EOR:
274	case ARM_MN_MOV:
275	case ARM_MN_MVN:
276	case ARM_MN_ORR:
277	case ARM_MN_RSB:
278	case ARM_MN_RSC:
279	case ARM_MN_SBC:
280	case ARM_MN_SUB:
281		if (info->affectsCPSR && info->execMode == MODE_ARM) {
282			flags = "s";
283		}
284		break;
285	default:
286		break;
287	}
288	written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, cond, flags);
289	ADVANCE(written);
290
291	switch (info->mnemonic) {
292	case ARM_MN_LDM:
293	case ARM_MN_STM:
294		written = _decodeRegister(info->memory.baseReg, buffer, blen);
295		ADVANCE(written);
296		if (info->memory.format & ARM_MEMORY_WRITEBACK) {
297			strncpy(buffer, "!", blen - 1);
298			ADVANCE(1);
299		}
300		strncpy(buffer, ", ", blen - 1);
301		ADVANCE(2);
302		written = _decodeRegisterList(info->op1.immediate, buffer, blen);
303		ADVANCE(written);
304		break;
305	case ARM_MN_B:
306		written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
307		ADVANCE(written);
308		break;
309	default:
310		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
311			written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate);
312			ADVANCE(written);
313		} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
314			written = _decodeMemory(info->memory, pc, buffer, blen);
315			ADVANCE(written);
316		} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
317			written = _decodeRegister(info->op1.reg, buffer, blen);
318			ADVANCE(written);
319		}
320		if (info->operandFormat & ARM_OPERAND_2) {
321			strncpy(buffer, ", ", blen);
322			ADVANCE(2);
323		}
324		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_2) {
325			written = snprintf(buffer, blen - 1, "#%i", info->op2.immediate);
326			ADVANCE(written);
327		} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
328			written = _decodeMemory(info->memory, pc, buffer, blen);
329			ADVANCE(written);
330		} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
331			written = _decodeRegister(info->op2.reg, buffer, blen);
332			ADVANCE(written);
333		}
334		if (info->operandFormat & ARM_OPERAND_3) {
335			strncpy(buffer, ", ", blen - 1);
336			ADVANCE(2);
337		}
338		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_3) {
339			written = snprintf(buffer, blen - 1, "#%i", info->op3.immediate);
340			ADVANCE(written);
341		} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
342			written = _decodeMemory(info->memory, pc, buffer, blen);
343			ADVANCE(written);
344		} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
345			written = _decodeRegister(info->op3.reg, buffer, blen);
346			ADVANCE(written);
347		}
348		if (info->operandFormat & ARM_OPERAND_4) {
349			strncpy(buffer, ", ", blen - 1);
350			ADVANCE(2);
351		}
352		if (info->operandFormat & ARM_OPERAND_IMMEDIATE_4) {
353			written = snprintf(buffer, blen - 1, "#%i", info->op4.immediate);
354			ADVANCE(written);
355		} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
356			written = _decodeMemory(info->memory, pc, buffer, blen);
357			ADVANCE(written);
358		} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
359			written = _decodeRegister(info->op4.reg, buffer, blen);
360			ADVANCE(written);
361		}
362		break;
363	}
364	buffer[blen - 1] = '\0';
365	return total;
366}