all repos — mgba @ d245eb3f88f4bdeb1eb2dc94329e56f850fc6e6d

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