all repos — mgba @ c8e1a9cd59ba20c1187368e5e9f68bab47b885ea

mGBA Game Boy Advance Emulator

src/arm/decoder-thumb.c (view raw)

  1#include "decoder.h"
  2
  3#include "arm.h"
  4#include "emitter-thumb.h"
  5#include "isa-inlines.h"
  6
  7#include <stdio.h>
  8#include <string.h>
  9
 10#define DEFINE_THUMB_DECODER(NAME, MNEMONIC, BODY) \
 11	static void _ThumbDecode ## NAME (uint16_t opcode, struct ThumbInstructionInfo* info) { \
 12		UNUSED(opcode); \
 13		info->mnemonic = THUMB_MN_ ## MNEMONIC; \
 14		BODY; \
 15	}
 16
 17#define DEFINE_IMMEDIATE_5_DECODER_DATA_THUMB(NAME, IMMEDIATE, MNEMONIC) \
 18	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 19		info->op3.immediate = IMMEDIATE; \
 20		info->op1.reg = opcode & 0x0007; \
 21		info->op2.reg = (opcode >> 3) & 0x0007; \
 22		info->affectsCPSR = 1; \
 23		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 24			ARM_OPERAND_AFFECTED_1 | \
 25			ARM_OPERAND_REGISTER_2 | \
 26			ARM_OPERAND_IMMEDIATE_3;)
 27
 28#define DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC) \
 29	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 30		info->op1.reg = opcode & 0x0007; \
 31		info->memory.baseReg = (opcode >> 3) & 0x0007; \
 32		info->memory.offset.immediate = IMMEDIATE << 2; \
 33		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 34			ARM_OPERAND_AFFECTED_1 | \
 35			ARM_OPERAND_MEMORY_2; \
 36		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
 37			ARM_MEMORY_IMMEDIATE_OFFSET;)
 38
 39#define DEFINE_IMMEDIATE_5_DECODER_THUMB(NAME, MNEMONIC, TYPE) \
 40	COUNT_5(DEFINE_IMMEDIATE_5_DECODER_ ## TYPE ## _THUMB, NAME ## _, MNEMONIC)
 41
 42DEFINE_IMMEDIATE_5_DECODER_THUMB(LSL1, LSL, DATA)
 43DEFINE_IMMEDIATE_5_DECODER_THUMB(LSR1, LSR, DATA)
 44DEFINE_IMMEDIATE_5_DECODER_THUMB(ASR1, ASR, DATA)
 45DEFINE_IMMEDIATE_5_DECODER_THUMB(LDR1, LDR, MEM)
 46DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRB1, LDRB, MEM)
 47DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRH1, LDRH, MEM)
 48DEFINE_IMMEDIATE_5_DECODER_THUMB(STR1, STR, MEM)
 49DEFINE_IMMEDIATE_5_DECODER_THUMB(STRB1, STRB, MEM)
 50DEFINE_IMMEDIATE_5_DECODER_THUMB(STRH1, STRH, MEM)
 51
 52#define DEFINE_DATA_FORM_1_DECODER_EX_THUMB(NAME, RM, MNEMONIC) \
 53	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 54		info->op1.reg = opcode & 0x0007; \
 55		info->op2.reg = (opcode >> 3) & 0x0007; \
 56		info->op3.reg = RM; \
 57		info->affectsCPSR = 1; \
 58		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 59			ARM_OPERAND_AFFECTED_1 | \
 60			ARM_OPERAND_REGISTER_2 | \
 61			ARM_OPERAND_REGISTER_3;)
 62
 63#define DEFINE_DATA_FORM_1_DECODER_THUMB(NAME) \
 64	COUNT_3(DEFINE_DATA_FORM_1_DECODER_EX_THUMB, NAME ## 3_R, NAME)
 65
 66DEFINE_DATA_FORM_1_DECODER_THUMB(ADD) 
 67DEFINE_DATA_FORM_1_DECODER_THUMB(SUB)
 68
 69#define DEFINE_DATA_FORM_2_DECODER_EX_THUMB(NAME, IMMEDIATE, MNEMONIC) \
 70	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 71		info->op1.reg = opcode & 0x0007; \
 72		info->op2.reg = (opcode >> 3) & 0x0007; \
 73		info->op3.immediate = IMMEDIATE; \
 74		info->affectsCPSR = 1; \
 75		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 76			ARM_OPERAND_AFFECTED_1 | \
 77			ARM_OPERAND_REGISTER_2 | \
 78			ARM_OPERAND_IMMEDIATE_3;)
 79
 80#define DEFINE_DATA_FORM_2_DECODER_THUMB(NAME) \
 81	COUNT_3(DEFINE_DATA_FORM_2_DECODER_EX_THUMB, NAME ## 1_, NAME)
 82
 83DEFINE_DATA_FORM_2_DECODER_THUMB(ADD)
 84DEFINE_DATA_FORM_2_DECODER_THUMB(SUB)
 85
 86#define DEFINE_DATA_FORM_3_DECODER_EX_THUMB(NAME, RD, MNEMONIC, AFFECTED) \
 87	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 88		info->op1.reg = RD; \
 89		info->op2.immediate = opcode & 0x00FF; \
 90		info->affectsCPSR = 1; \
 91		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 92			AFFECTED | \
 93			ARM_OPERAND_IMMEDIATE_2;)
 94
 95#define DEFINE_DATA_FORM_3_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
 96	COUNT_3(DEFINE_DATA_FORM_3_DECODER_EX_THUMB, NAME ## _R, MNEMONIC, AFFECTED)
 97
 98DEFINE_DATA_FORM_3_DECODER_THUMB(ADD2, ADD, ARM_OPERAND_AFFECTED_1)
 99DEFINE_DATA_FORM_3_DECODER_THUMB(CMP1, CMP, ARM_OPERAND_NONE)
100DEFINE_DATA_FORM_3_DECODER_THUMB(MOV1, MOV, ARM_OPERAND_AFFECTED_1)
101DEFINE_DATA_FORM_3_DECODER_THUMB(SUB2, SUB, ARM_OPERAND_AFFECTED_1)
102
103#define DEFINE_DATA_FORM_5_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
104	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
105		info->op1.reg = opcode & 0x0007; \
106		info->op2.reg = (opcode >> 3) & 0x0007; \
107		info->affectsCPSR = 1; \
108		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
109			AFFECTED | \
110			ARM_OPERAND_REGISTER_2;)
111
112DEFINE_DATA_FORM_5_DECODER_THUMB(AND, AND, ARM_OPERAND_AFFECTED_1)
113DEFINE_DATA_FORM_5_DECODER_THUMB(EOR, EOR, ARM_OPERAND_AFFECTED_1)
114DEFINE_DATA_FORM_5_DECODER_THUMB(LSL2, LSL, ARM_OPERAND_AFFECTED_1)
115DEFINE_DATA_FORM_5_DECODER_THUMB(LSR2, LSR, ARM_OPERAND_AFFECTED_1)
116DEFINE_DATA_FORM_5_DECODER_THUMB(ASR2, ASR, ARM_OPERAND_AFFECTED_1)
117DEFINE_DATA_FORM_5_DECODER_THUMB(ADC, ADC, ARM_OPERAND_AFFECTED_1)
118DEFINE_DATA_FORM_5_DECODER_THUMB(SBC, SBC, ARM_OPERAND_AFFECTED_1)
119DEFINE_DATA_FORM_5_DECODER_THUMB(ROR, ROR, ARM_OPERAND_AFFECTED_1)
120DEFINE_DATA_FORM_5_DECODER_THUMB(TST, TST, ARM_OPERAND_AFFECTED_1)
121DEFINE_DATA_FORM_5_DECODER_THUMB(NEG, NEG, ARM_OPERAND_AFFECTED_1)
122DEFINE_DATA_FORM_5_DECODER_THUMB(CMP2, CMP, ARM_OPERAND_NONE)
123DEFINE_DATA_FORM_5_DECODER_THUMB(CMN, CMN, ARM_OPERAND_NONE)
124DEFINE_DATA_FORM_5_DECODER_THUMB(ORR, ORR, ARM_OPERAND_AFFECTED_1)
125DEFINE_DATA_FORM_5_DECODER_THUMB(MUL, MUL, ARM_OPERAND_AFFECTED_1)
126DEFINE_DATA_FORM_5_DECODER_THUMB(BIC, BIC, ARM_OPERAND_AFFECTED_1)
127DEFINE_DATA_FORM_5_DECODER_THUMB(MVN, MVN, ARM_OPERAND_AFFECTED_1) 
128
129#define DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME, H1, H2, MNEMONIC, AFFECTED, CPSR) \
130	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
131		info->op1.reg = (opcode & 0x0007) | H1; \
132		info->op2.reg = ((opcode >> 3) & 0x0007) | H2; \
133		info->accessesSpecialRegisters = info->op1.reg > 12 || info->op2.reg > 12; \
134		info->affectsCPSR = CPSR; \
135		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
136			AFFECTED | \
137			ARM_OPERAND_REGISTER_2;)
138
139
140#define DEFINE_DECODER_WITH_HIGH_THUMB(NAME, MNEMONIC, AFFECTED, CPSR) \
141	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 00, 0, 0, MNEMONIC, AFFECTED, CPSR) \
142	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 01, 0, 8, MNEMONIC, AFFECTED, CPSR) \
143	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 10, 8, 0, MNEMONIC, AFFECTED, CPSR) \
144	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 11, 8, 8, MNEMONIC, AFFECTED, CPSR)
145
146DEFINE_DECODER_WITH_HIGH_THUMB(ADD4, ADD, ARM_OPERAND_AFFECTED_1, 0)
147DEFINE_DECODER_WITH_HIGH_THUMB(CMP3, CMP, ARM_OPERAND_NONE, 1)
148DEFINE_DECODER_WITH_HIGH_THUMB(MOV3, MOV, ARM_OPERAND_AFFECTED_1, 0)
149
150#define DEFINE_IMMEDIATE_WITH_REGISTER_DATA_THUMB(NAME, RD, MNEMONIC, REG) \
151	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
152		info->op1.reg = RD; \
153		info->op2.reg = REG; \
154		info->op3.immediate = (opcode & 0x00FF) << 2; \
155		info->accessesSpecialRegisters = 1; \
156		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
157			ARM_OPERAND_AFFECTED_1 | \
158			ARM_OPERAND_REGISTER_2 | \
159			ARM_OPERAND_IMMEDIATE_3;)
160
161#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG) \
162	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
163		info->op1.reg = RD; \
164		info->memory.baseReg = REG; \
165		info->memory.offset.immediate = (opcode & 0x00FF) << 2; \
166		info->accessesSpecialRegisters = 1; \
167		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
168			ARM_OPERAND_AFFECTED_1 | \
169			ARM_OPERAND_MEMORY_2; \
170		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
171			ARM_MEMORY_IMMEDIATE_OFFSET;)
172
173#define DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(NAME, MNEMONIC, TYPE, REG) \
174	COUNT_3(DEFINE_IMMEDIATE_WITH_REGISTER_ ## TYPE ## _THUMB, NAME ## _R, MNEMONIC, REG)
175
176DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR3, LDR, MEM, ARM_PC)
177DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR4, LDR, MEM, ARM_SP)
178DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(STR3, STR, MEM, ARM_SP)
179
180DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD5, ADD, DATA, ARM_PC)
181DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD6, ADD, DATA, ARM_SP)
182
183#define DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB(NAME, RM, MNEMONIC) \
184	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
185		info->memory.offset.reg = RM; \
186		info->op1.reg = opcode & 0x0007; \
187		info->memory.baseReg = (opcode >> 3) & 0x0007; \
188		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
189			ARM_OPERAND_AFFECTED_1 | \
190			ARM_OPERAND_MEMORY_2; \
191		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
192			ARM_MEMORY_REGISTER_OFFSET;)
193
194#define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, MNEMONIC) \
195	COUNT_3(DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB, NAME ## _R, MNEMONIC)
196
197DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, LDR)
198DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, LDRB)
199DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, LDRH)
200DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, LDRSB)
201DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, LDRSH)
202DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, STR)
203DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, STRB)
204DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STRH)
205
206#define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, MNEMONIC, SPECIAL_REG, ADDITIONAL_REG) \
207	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
208		info->memory.baseReg = RN; \
209		info->accessesSpecialRegisters = SPECIAL_REG; \
210		info->op1.immediate = (opcode & 0xFF) | ADDITIONAL_REG; \
211		info->operandFormat = ARM_OPERAND_IMMEDIATE_1; \
212		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
213			ARM_MEMORY_POST_INCREMENT;)
214
215#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME) \
216	COUNT_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## _R, NAME, 0, 0)
217
218DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDMIA)
219DEFINE_LOAD_STORE_MULTIPLE_THUMB(STMIA)
220
221#define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
222	DEFINE_THUMB_DECODER(B ## COND, B, \
223		int8_t immediate = opcode; \
224		info->op1.immediate = immediate << 1; \
225		info->branches = 1; \
226		info->condition = ARM_CONDITION_ ## COND; \
227		info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
228
229DEFINE_CONDITIONAL_BRANCH_THUMB(EQ)
230DEFINE_CONDITIONAL_BRANCH_THUMB(NE)
231DEFINE_CONDITIONAL_BRANCH_THUMB(CS)
232DEFINE_CONDITIONAL_BRANCH_THUMB(CC)
233DEFINE_CONDITIONAL_BRANCH_THUMB(MI)
234DEFINE_CONDITIONAL_BRANCH_THUMB(PL)
235DEFINE_CONDITIONAL_BRANCH_THUMB(VS)
236DEFINE_CONDITIONAL_BRANCH_THUMB(VC)
237DEFINE_CONDITIONAL_BRANCH_THUMB(LS)
238DEFINE_CONDITIONAL_BRANCH_THUMB(HI)
239DEFINE_CONDITIONAL_BRANCH_THUMB(GE)
240DEFINE_CONDITIONAL_BRANCH_THUMB(LT)
241DEFINE_CONDITIONAL_BRANCH_THUMB(GT)
242DEFINE_CONDITIONAL_BRANCH_THUMB(LE)
243
244#define DEFINE_SP_MODIFY_THUMB(NAME, MNEMONIC) \
245	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
246		info->op1.reg = ARM_SP; \
247		info->op2.immediate = (opcode & 0x7F) << 2; \
248		info->accessesSpecialRegisters = 1; \
249		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
250			ARM_OPERAND_AFFECTED_1 | \
251			ARM_OPERAND_IMMEDIATE_2;)
252
253DEFINE_SP_MODIFY_THUMB(ADD7, ADD)
254DEFINE_SP_MODIFY_THUMB(SUB4, SUB)
255
256DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POP, ARM_SP, POP, 1, 0)
257DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR, ARM_SP, POP, 1, 1 << ARM_PC)
258DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH, ARM_SP, PUSH, 1, 0)
259DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR, ARM_SP, PUSH, 1, 1 << ARM_LR)
260
261DEFINE_THUMB_DECODER(ILL, ILL, info->traps = 1;)
262DEFINE_THUMB_DECODER(BKPT, BKPT, info->traps = 1;)
263
264DEFINE_THUMB_DECODER(B, B,
265	int16_t immediate = (opcode & 0x07FF) << 5;
266	info->op1.immediate = (((int32_t) immediate) >> 4);
267	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
268	info->branches = 1;)
269
270DEFINE_THUMB_DECODER(BL1, BLH,
271	int16_t immediate = (opcode & 0x07FF) << 5;
272	info->op1.immediate = (((int32_t) immediate) << 7);
273	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
274	info->accessesSpecialRegisters = 1;)
275
276DEFINE_THUMB_DECODER(BL2, BL,
277	info->op1.immediate = (opcode & 0x07FF) << 1;
278	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
279	info->accessesSpecialRegisters = 1;
280	info->branches = 1;)
281
282DEFINE_THUMB_DECODER(BX, BX,
283	info->op1.reg = (opcode >> 3) & 0xF;
284	info->operandFormat = ARM_OPERAND_REGISTER_1;
285	info->branches = 1;)
286
287DEFINE_THUMB_DECODER(SWI, SWI,
288	info->op1.immediate = opcode & 0xFF;
289	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
290	info->traps = 1;)
291
292typedef void (*ThumbDecoder)(uint16_t opcode, struct ThumbInstructionInfo* info);
293
294static const ThumbDecoder _thumbDecoderTable[0x400] = {
295	DECLARE_THUMB_EMITTER_BLOCK(_ThumbDecode)
296};
297
298void ARMDecodeThumb(uint16_t opcode, struct ThumbInstructionInfo* info) {
299	info->opcode = opcode;
300	info->branches = 0;
301	info->traps = 0;
302	info->accessesSpecialRegisters = 0;
303	info->affectsCPSR = 0;
304	info->condition = ARM_CONDITION_AL;
305	ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6];
306	decoder(opcode, info);
307}
308
309#define ADVANCE(AMOUNT) \
310	if (AMOUNT > blen) { \
311		buffer[blen - 1] = '\0'; \
312		return total; \
313	} \
314	total += AMOUNT; \
315	buffer += AMOUNT; \
316	blen -= AMOUNT;
317
318static int _decodeRegister(int reg, char* buffer, int blen) {
319	switch (reg) {
320	case ARM_SP:
321		strncpy(buffer, "sp", blen);
322		return 2;
323	case ARM_LR:
324		strncpy(buffer, "lr", blen);
325		return 2;
326	case ARM_PC:
327		strncpy(buffer, "pc", blen);
328		return 2;
329	default:
330		return snprintf(buffer, blen, "r%i", reg);
331	}
332}
333
334static int _decodeRegisterList(int list, char* buffer, int blen) {
335	if (blen <= 0) {
336		return 0;
337	}
338	int total = 0;
339	strncpy(buffer, "{", blen);
340	ADVANCE(1);
341	int i;
342	int start = -1;
343	int end = -1;
344	int written;
345	printf("%x\n", list);
346	for (i = 0; i <= ARM_PC; ++i) {
347		if (list & 1) {
348			if (start < 0) {
349				start = i;
350				end = i;
351			} else if (end + 1 == i) {
352				end = i;
353			} else {
354				if (end > start) {
355					written = _decodeRegister(start, buffer, blen);
356					ADVANCE(written);
357					strncpy(buffer, "-", blen);
358					ADVANCE(1);
359				}
360				written = _decodeRegister(end, buffer, blen);
361				ADVANCE(written);
362				strncpy(buffer, ",", blen);
363				ADVANCE(1);
364				start = i;
365				end = i;
366			}
367		}
368		list >>= 1;
369	}
370	if (start >= 0) {
371		if (end > start) {
372			written = _decodeRegister(start, buffer, blen);
373			ADVANCE(written);
374			strncpy(buffer, "-", blen);
375			ADVANCE(1);
376		}
377		written = _decodeRegister(end, buffer, blen);
378		ADVANCE(written);
379	}
380	strncpy(buffer, "}", blen);
381	ADVANCE(1);
382	return total;
383}
384
385static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
386	return snprintf(buffer, blen, "$%08X", address + pc);
387}
388
389static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
390	if (blen <= 0) {
391		return 0;
392	}
393	int total = 0;
394	strncpy(buffer, "[", blen);
395	ADVANCE(1);
396	int written;
397	if (memory.format & ARM_MEMORY_REGISTER_BASE) {
398		if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
399			written = _decodePCRelative(memory.offset.immediate, pc, buffer, blen);
400			ADVANCE(written);
401		} else {
402			written = _decodeRegister(memory.baseReg, buffer, blen);
403			ADVANCE(written);
404			if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
405				strncpy(buffer, ", ", blen);
406				ADVANCE(2);
407			}
408		}
409	}
410	if (memory.format & ARM_MEMORY_POST_INCREMENT) {
411		strncpy(buffer, "], ", blen);
412		ADVANCE(3);
413	}
414	if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
415		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
416			written = snprintf(buffer, blen, "#-%i", memory.offset.immediate);
417			ADVANCE(written);
418		} else {
419			written = snprintf(buffer, blen, "#%i", memory.offset.immediate);
420			ADVANCE(written);
421		}
422	} else if (memory.format & ARM_MEMORY_REGISTER_OFFSET) {
423		if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
424			strncpy(buffer, "-", blen);
425			ADVANCE(1);
426		}
427		written = _decodeRegister(memory.offset.reg, buffer, blen);
428		ADVANCE(written);
429	}
430	// TODO: shifted registers
431
432	if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
433		strncpy(buffer, "]", blen);
434		ADVANCE(1);
435	}
436	if (memory.format & ARM_MEMORY_PRE_INCREMENT) {
437		strncpy(buffer, "!", blen);
438		ADVANCE(1);
439	}
440	return total;
441}
442
443static const char* _armConditions[] = {
444	"eq",
445	"ne",
446	"cs",
447	"cc",
448	"mi",
449	"pl",
450	"vs",
451	"vc",
452	"hi",
453	"ls",
454	"ge",
455	"lt",
456	"gt",
457	"le",
458	"al",
459	"nv"
460};
461
462static const char* _thumbMnemonicStrings[] = {
463	"ill",
464	"adc",
465	"add",
466	"and",
467	"asr",
468	"b",
469	"bic",
470	"bkpt",
471	"bl",
472	"blh",
473	"bx",
474	"cmn",
475	"cmp",
476	"eor",
477	"ldmia",
478	"ldr",
479	"ldrb",
480	"ldrh",
481	"ldrsb",
482	"ldrsh",
483	"lsl",
484	"lsr",
485	"mov",
486	"mul",
487	"mvn",
488	"neg",
489	"orr",
490	"pop",
491	"push",
492	"ror",
493    "sbc",
494    "stmia",
495	"str",
496	"strb",
497	"strh",
498	"sub",
499	"swi",
500	"tst"
501};
502
503int ARMDisassembleThumb(uint16_t opcode, uint32_t pc, char* buffer, int blen) {
504	struct ThumbInstructionInfo info;
505	ARMDecodeThumb(opcode, &info);
506	const char* mnemonic = _thumbMnemonicStrings[info.mnemonic];
507	int written;
508	int total = 0;
509	const char* cond = "";
510	if (info.condition != ARM_CONDITION_AL && info.condition < ARM_CONDITION_NV) {
511		cond = _armConditions[info.condition];
512	}
513	written = snprintf(buffer, blen, "%s%s ", mnemonic, cond);
514	ADVANCE(written);
515
516	switch (info.mnemonic) {
517	case THUMB_MN_LDMIA:
518	case THUMB_MN_STMIA:
519		written = _decodeRegister(info.memory.baseReg, buffer, blen);
520		ADVANCE(written);
521		strncpy(buffer, "!, ", blen);
522		ADVANCE(3);
523		// Fall through
524	case THUMB_MN_POP:
525	case THUMB_MN_PUSH:
526		written = _decodeRegisterList(info.op1.immediate, buffer, blen);
527		ADVANCE(written);
528		break;
529	case THUMB_MN_B:
530		written = _decodePCRelative(info.op1.immediate, pc, buffer, blen);
531		ADVANCE(written);
532		break;
533	default:
534		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_1) {
535			written = snprintf(buffer, blen, "#%i", info.op1.immediate);
536			ADVANCE(written);
537		} else if (info.operandFormat & ARM_OPERAND_MEMORY_1) {
538			written = _decodeMemory(info.memory, pc, buffer, blen);
539			ADVANCE(written);
540		} else if (info.operandFormat & ARM_OPERAND_REGISTER_1) {
541			written = _decodeRegister(info.op1.reg, buffer, blen);
542			ADVANCE(written);
543		}
544		if (info.operandFormat & ARM_OPERAND_2) {
545			strncpy(buffer, ", ", blen);
546			ADVANCE(2);
547		}
548		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_2) {
549			written = snprintf(buffer, blen, "#%i", info.op2.immediate);
550			ADVANCE(written);
551		} else if (info.operandFormat & ARM_OPERAND_MEMORY_2) {
552			written = _decodeMemory(info.memory, pc, buffer, blen);
553			ADVANCE(written);
554		} else if (info.operandFormat & ARM_OPERAND_REGISTER_2) {
555			written = _decodeRegister(info.op2.reg, buffer, blen);
556			ADVANCE(written);
557		}
558		if (info.operandFormat & ARM_OPERAND_3) {
559			strncpy(buffer, ", ", blen);
560			ADVANCE(2);
561		}
562		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_3) {
563			written = snprintf(buffer, blen, "#%i", info.op3.immediate);
564			ADVANCE(written);
565		} else if (info.operandFormat & ARM_OPERAND_MEMORY_3) {
566			written = _decodeMemory(info.memory, pc, buffer, blen);
567			ADVANCE(written);
568		} else if (info.operandFormat & ARM_OPERAND_REGISTER_3) {
569			written = _decodeRegister(info.op1.reg, buffer, blen);
570			ADVANCE(written);
571		}
572		break;
573	}
574	buffer[total] = '\0';
575	return total;
576}