all repos — mgba @ 45c6299b3b18ef85aacc00c0d5af3f65e4324100

mGBA Game Boy Advance Emulator

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

  1#include "decoder.h"
  2
  3#include "arm.h"
  4#include "decoder-inlines.h"
  5#include "emitter-thumb.h"
  6#include "isa-inlines.h"
  7
  8#include <stdio.h>
  9#include <string.h>
 10
 11#define DEFINE_THUMB_DECODER(NAME, MNEMONIC, BODY) \
 12	static void _ThumbDecode ## NAME (uint16_t opcode, struct ARMInstructionInfo* info) { \
 13		UNUSED(opcode); \
 14		info->mnemonic = ARM_MN_ ## MNEMONIC; \
 15		BODY; \
 16	}
 17
 18#define DEFINE_IMMEDIATE_5_DECODER_DATA_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
 19	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 20		info->op3.immediate = IMMEDIATE; \
 21		info->op1.reg = opcode & 0x0007; \
 22		info->op2.reg = (opcode >> 3) & 0x0007; \
 23		info->affectsCPSR = 1; \
 24		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 25			ARM_OPERAND_AFFECTED_1 | \
 26			ARM_OPERAND_REGISTER_2 | \
 27			ARM_OPERAND_IMMEDIATE_3;)
 28
 29#define DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, CYCLES, WIDTH) \
 30	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 31		info->op1.reg = opcode & 0x0007; \
 32		info->memory.baseReg = (opcode >> 3) & 0x0007; \
 33		info->memory.offset.immediate = IMMEDIATE * WIDTH; \
 34		info->memory.width = (enum ARMMemoryAccessType) WIDTH; \
 35		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 36			ARM_OPERAND_AFFECTED_1 | \
 37			ARM_OPERAND_MEMORY_2; \
 38		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
 39			ARM_MEMORY_IMMEDIATE_OFFSET; \
 40		CYCLES)
 41
 42#define DEFINE_IMMEDIATE_5_DECODER_MEM_LOAD_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
 43	DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, LOAD_CYCLES, WIDTH)
 44
 45#define DEFINE_IMMEDIATE_5_DECODER_MEM_STORE_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
 46	DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, STORE_CYCLES, WIDTH)
 47
 48#define DEFINE_IMMEDIATE_5_DECODER_THUMB(NAME, MNEMONIC, TYPE, WIDTH) \
 49	COUNT_5(DEFINE_IMMEDIATE_5_DECODER_ ## TYPE ## _THUMB, NAME ## _, MNEMONIC, WIDTH)
 50
 51DEFINE_IMMEDIATE_5_DECODER_THUMB(LSL1, LSL, DATA,)
 52DEFINE_IMMEDIATE_5_DECODER_THUMB(LSR1, LSR, DATA,)
 53DEFINE_IMMEDIATE_5_DECODER_THUMB(ASR1, ASR, DATA,)
 54DEFINE_IMMEDIATE_5_DECODER_THUMB(LDR1, LDR, MEM_LOAD, 4)
 55DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRB1, LDR, MEM_LOAD, 1)
 56DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRH1, LDR, MEM_LOAD, 2)
 57DEFINE_IMMEDIATE_5_DECODER_THUMB(STR1, STR, MEM_STORE, 4)
 58DEFINE_IMMEDIATE_5_DECODER_THUMB(STRB1, STR, MEM_STORE, 1)
 59DEFINE_IMMEDIATE_5_DECODER_THUMB(STRH1, STR, MEM_STORE, 2)
 60
 61#define DEFINE_DATA_FORM_1_DECODER_EX_THUMB(NAME, RM, MNEMONIC) \
 62	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 63		info->op1.reg = opcode & 0x0007; \
 64		info->op2.reg = (opcode >> 3) & 0x0007; \
 65		info->op3.reg = RM; \
 66		info->affectsCPSR = 1; \
 67		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 68			ARM_OPERAND_AFFECTED_1 | \
 69			ARM_OPERAND_REGISTER_2 | \
 70			ARM_OPERAND_REGISTER_3;)
 71
 72#define DEFINE_DATA_FORM_1_DECODER_THUMB(NAME) \
 73	COUNT_3(DEFINE_DATA_FORM_1_DECODER_EX_THUMB, NAME ## 3_R, NAME)
 74
 75DEFINE_DATA_FORM_1_DECODER_THUMB(ADD)
 76DEFINE_DATA_FORM_1_DECODER_THUMB(SUB)
 77
 78#define DEFINE_DATA_FORM_2_DECODER_EX_THUMB(NAME, IMMEDIATE, MNEMONIC) \
 79	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 80		info->op1.reg = opcode & 0x0007; \
 81		info->op2.reg = (opcode >> 3) & 0x0007; \
 82		info->op3.immediate = IMMEDIATE; \
 83		info->affectsCPSR = 1; \
 84		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 85			ARM_OPERAND_AFFECTED_1 | \
 86			ARM_OPERAND_REGISTER_2 | \
 87			ARM_OPERAND_IMMEDIATE_3;)
 88
 89#define DEFINE_DATA_FORM_2_DECODER_THUMB(NAME) \
 90	COUNT_3(DEFINE_DATA_FORM_2_DECODER_EX_THUMB, NAME ## 1_, NAME)
 91
 92DEFINE_DATA_FORM_2_DECODER_THUMB(ADD)
 93DEFINE_DATA_FORM_2_DECODER_THUMB(SUB)
 94
 95#define DEFINE_DATA_FORM_3_DECODER_EX_THUMB(NAME, RD, MNEMONIC, AFFECTED) \
 96	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 97		info->op1.reg = RD; \
 98		info->op2.immediate = opcode & 0x00FF; \
 99		info->affectsCPSR = 1; \
100		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
101			AFFECTED | \
102			ARM_OPERAND_IMMEDIATE_2;)
103
104#define DEFINE_DATA_FORM_3_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
105	COUNT_3(DEFINE_DATA_FORM_3_DECODER_EX_THUMB, NAME ## _R, MNEMONIC, AFFECTED)
106
107DEFINE_DATA_FORM_3_DECODER_THUMB(ADD2, ADD, ARM_OPERAND_AFFECTED_1)
108DEFINE_DATA_FORM_3_DECODER_THUMB(CMP1, CMP, ARM_OPERAND_NONE)
109DEFINE_DATA_FORM_3_DECODER_THUMB(MOV1, MOV, ARM_OPERAND_AFFECTED_1)
110DEFINE_DATA_FORM_3_DECODER_THUMB(SUB2, SUB, ARM_OPERAND_AFFECTED_1)
111
112#define DEFINE_DATA_FORM_5_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
113	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
114		info->op1.reg = opcode & 0x0007; \
115		info->op2.reg = (opcode >> 3) & 0x0007; \
116		info->affectsCPSR = 1; \
117		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
118			AFFECTED | \
119			ARM_OPERAND_REGISTER_2;)
120
121DEFINE_DATA_FORM_5_DECODER_THUMB(AND, AND, ARM_OPERAND_AFFECTED_1)
122DEFINE_DATA_FORM_5_DECODER_THUMB(EOR, EOR, ARM_OPERAND_AFFECTED_1)
123DEFINE_DATA_FORM_5_DECODER_THUMB(LSL2, LSL, ARM_OPERAND_AFFECTED_1)
124DEFINE_DATA_FORM_5_DECODER_THUMB(LSR2, LSR, ARM_OPERAND_AFFECTED_1)
125DEFINE_DATA_FORM_5_DECODER_THUMB(ASR2, ASR, ARM_OPERAND_AFFECTED_1)
126DEFINE_DATA_FORM_5_DECODER_THUMB(ADC, ADC, ARM_OPERAND_AFFECTED_1)
127DEFINE_DATA_FORM_5_DECODER_THUMB(SBC, SBC, ARM_OPERAND_AFFECTED_1)
128DEFINE_DATA_FORM_5_DECODER_THUMB(ROR, ROR, ARM_OPERAND_AFFECTED_1)
129DEFINE_DATA_FORM_5_DECODER_THUMB(TST, TST, ARM_OPERAND_NONE)
130DEFINE_DATA_FORM_5_DECODER_THUMB(NEG, NEG, ARM_OPERAND_AFFECTED_1)
131DEFINE_DATA_FORM_5_DECODER_THUMB(CMP2, CMP, ARM_OPERAND_NONE)
132DEFINE_DATA_FORM_5_DECODER_THUMB(CMN, CMN, ARM_OPERAND_NONE)
133DEFINE_DATA_FORM_5_DECODER_THUMB(ORR, ORR, ARM_OPERAND_AFFECTED_1)
134DEFINE_DATA_FORM_5_DECODER_THUMB(MUL, MUL, ARM_OPERAND_AFFECTED_1)
135DEFINE_DATA_FORM_5_DECODER_THUMB(BIC, BIC, ARM_OPERAND_AFFECTED_1)
136DEFINE_DATA_FORM_5_DECODER_THUMB(MVN, MVN, ARM_OPERAND_AFFECTED_1)
137
138#define DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME, H1, H2, MNEMONIC, AFFECTED, CPSR) \
139	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
140		info->op1.reg = (opcode & 0x0007) | H1; \
141		info->op2.reg = ((opcode >> 3) & 0x0007) | H2; \
142		info->branches = info->op1.reg == ARM_PC; \
143		info->affectsCPSR = CPSR; \
144		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
145			AFFECTED | \
146			ARM_OPERAND_REGISTER_2;)
147
148
149#define DEFINE_DECODER_WITH_HIGH_THUMB(NAME, MNEMONIC, AFFECTED, CPSR) \
150	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 00, 0, 0, MNEMONIC, AFFECTED, CPSR) \
151	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 01, 0, 8, MNEMONIC, AFFECTED, CPSR) \
152	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 10, 8, 0, MNEMONIC, AFFECTED, CPSR) \
153	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 11, 8, 8, MNEMONIC, AFFECTED, CPSR)
154
155DEFINE_DECODER_WITH_HIGH_THUMB(ADD4, ADD, ARM_OPERAND_AFFECTED_1, 0)
156DEFINE_DECODER_WITH_HIGH_THUMB(CMP3, CMP, ARM_OPERAND_NONE, 1)
157DEFINE_DECODER_WITH_HIGH_THUMB(MOV3, MOV, ARM_OPERAND_AFFECTED_1, 0)
158
159#define DEFINE_IMMEDIATE_WITH_REGISTER_DATA_THUMB(NAME, RD, MNEMONIC, REG) \
160	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
161		info->op1.reg = RD; \
162		info->op2.reg = REG; \
163		info->op3.immediate = (opcode & 0x00FF) << 2; \
164		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
165			ARM_OPERAND_AFFECTED_1 | \
166			ARM_OPERAND_REGISTER_2 | \
167			ARM_OPERAND_IMMEDIATE_3;)
168
169#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, CYCLES) \
170	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
171		info->op1.reg = RD; \
172		info->memory.baseReg = REG; \
173		info->memory.offset.immediate = (opcode & 0x00FF) << 2; \
174		info->memory.width = ARM_ACCESS_WORD; \
175		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
176			ARM_OPERAND_AFFECTED_1 | \
177			ARM_OPERAND_MEMORY_2; \
178		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
179			ARM_MEMORY_IMMEDIATE_OFFSET; \
180		CYCLES;)
181
182#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_LOAD_THUMB(NAME, RD, MNEMONIC, REG) \
183	DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, LOAD_CYCLES)
184
185#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_STORE_THUMB(NAME, RD, MNEMONIC, REG) \
186	DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, STORE_CYCLES)
187
188#define DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(NAME, MNEMONIC, TYPE, REG) \
189	COUNT_3(DEFINE_IMMEDIATE_WITH_REGISTER_ ## TYPE ## _THUMB, NAME ## _R, MNEMONIC, REG)
190
191DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR3, LDR, MEM_LOAD, ARM_PC)
192DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR4, LDR, MEM_LOAD, ARM_SP)
193DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(STR3, STR, MEM_STORE, ARM_SP)
194
195DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD5, ADD, DATA, ARM_PC)
196DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD6, ADD, DATA, ARM_SP)
197
198#define DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB(NAME, RM, MNEMONIC, CYCLES, TYPE) \
199	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
200		info->memory.offset.reg = RM; \
201		info->op1.reg = opcode & 0x0007; \
202		info->memory.baseReg = (opcode >> 3) & 0x0007; \
203		info->memory.width = TYPE; \
204		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
205			ARM_OPERAND_AFFECTED_1 | \
206			ARM_OPERAND_MEMORY_2; \
207		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
208			ARM_MEMORY_REGISTER_OFFSET; \
209		CYCLES;)
210
211#define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, MNEMONIC, CYCLES, TYPE) \
212	COUNT_3(DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB, NAME ## _R, MNEMONIC, CYCLES, TYPE)
213
214DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, LDR, LOAD_CYCLES, ARM_ACCESS_WORD)
215DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, LDR, LOAD_CYCLES, ARM_ACCESS_BYTE)
216DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, LDR, LOAD_CYCLES, ARM_ACCESS_HALFWORD)
217DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_BYTE)
218DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_HALFWORD)
219DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, STR, STORE_CYCLES, ARM_ACCESS_WORD)
220DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, STR, STORE_CYCLES, ARM_ACCESS_BYTE)
221DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STR, STORE_CYCLES, ARM_ACCESS_HALFWORD)
222
223#define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, MNEMONIC, DIRECTION, ADDITIONAL_REG) \
224	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
225		info->memory.baseReg = RN; \
226		info->op1.immediate = (opcode & 0xFF) | ADDITIONAL_REG; \
227		info->branches = info->op1.immediate & (1 << ARM_PC); \
228		info->operandFormat = ARM_OPERAND_MEMORY_1; \
229		info->memory.direction = DIRECTION; \
230		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
231			ARM_MEMORY_POST_INCREMENT;)
232
233#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME) \
234	COUNT_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## IA_R, NAME, ARM_INCREMENT_AFTER, 0)
235
236DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDM)
237DEFINE_LOAD_STORE_MULTIPLE_THUMB(STM)
238
239#define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
240	DEFINE_THUMB_DECODER(B ## COND, B, \
241		int8_t immediate = opcode; \
242		info->op1.immediate = immediate << 1; \
243		info->branches = 1; \
244		info->condition = ARM_CONDITION_ ## COND; \
245		info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
246
247DEFINE_CONDITIONAL_BRANCH_THUMB(EQ)
248DEFINE_CONDITIONAL_BRANCH_THUMB(NE)
249DEFINE_CONDITIONAL_BRANCH_THUMB(CS)
250DEFINE_CONDITIONAL_BRANCH_THUMB(CC)
251DEFINE_CONDITIONAL_BRANCH_THUMB(MI)
252DEFINE_CONDITIONAL_BRANCH_THUMB(PL)
253DEFINE_CONDITIONAL_BRANCH_THUMB(VS)
254DEFINE_CONDITIONAL_BRANCH_THUMB(VC)
255DEFINE_CONDITIONAL_BRANCH_THUMB(LS)
256DEFINE_CONDITIONAL_BRANCH_THUMB(HI)
257DEFINE_CONDITIONAL_BRANCH_THUMB(GE)
258DEFINE_CONDITIONAL_BRANCH_THUMB(LT)
259DEFINE_CONDITIONAL_BRANCH_THUMB(GT)
260DEFINE_CONDITIONAL_BRANCH_THUMB(LE)
261
262#define DEFINE_SP_MODIFY_THUMB(NAME, MNEMONIC) \
263	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
264		info->op1.reg = ARM_SP; \
265		info->op2.immediate = (opcode & 0x7F) << 2; \
266		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
267			ARM_OPERAND_AFFECTED_1 | \
268			ARM_OPERAND_IMMEDIATE_2;)
269
270DEFINE_SP_MODIFY_THUMB(ADD7, ADD)
271DEFINE_SP_MODIFY_THUMB(SUB4, SUB)
272
273DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POP, ARM_SP, LDM, ARM_INCREMENT_AFTER, 0)
274DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR, ARM_SP, LDM, ARM_INCREMENT_AFTER, 1 << ARM_PC)
275DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH, ARM_SP, STM, ARM_DECREMENT_BEFORE, 0)
276DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR, ARM_SP, STM, ARM_DECREMENT_BEFORE, 1 << ARM_LR)
277
278DEFINE_THUMB_DECODER(ILL, ILL, info->traps = 1;)
279DEFINE_THUMB_DECODER(BKPT, BKPT, info->traps = 1;)
280
281DEFINE_THUMB_DECODER(B, B,
282	int16_t immediate = (opcode & 0x07FF) << 5;
283	info->op1.immediate = (((int32_t) immediate) >> 4);
284	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
285	info->branches = 1;)
286
287DEFINE_THUMB_DECODER(BL1, BLH,
288	int16_t immediate = (opcode & 0x07FF) << 5;
289	info->op1.immediate = (((int32_t) immediate) << 7);
290	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
291
292DEFINE_THUMB_DECODER(BL2, BL,
293	info->op1.immediate = (opcode & 0x07FF) << 1;
294	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
295	info->branches = 1;)
296
297DEFINE_THUMB_DECODER(BX, BX,
298	info->op1.reg = (opcode >> 3) & 0xF;
299	info->operandFormat = ARM_OPERAND_REGISTER_1;
300	info->branches = 1;)
301
302DEFINE_THUMB_DECODER(SWI, SWI,
303	info->op1.immediate = opcode & 0xFF;
304	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
305	info->traps = 1;)
306
307typedef void (*ThumbDecoder)(uint16_t opcode, struct ARMInstructionInfo* info);
308
309static const ThumbDecoder _thumbDecoderTable[0x400] = {
310	DECLARE_THUMB_EMITTER_BLOCK(_ThumbDecode)
311};
312
313void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) {
314	info->opcode = opcode;
315	info->branches = 0;
316	info->traps = 0;
317	info->affectsCPSR = 0;
318	info->condition = ARM_CONDITION_AL;
319	info->sDataCycles = 0;
320	info->nDataCycles = 0;
321	info->sInstructionCycles = 1;
322	info->nInstructionCycles = 0;
323	info->iCycles = 0;
324	info->cCycles = 0;
325	ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6];
326	decoder(opcode, info);
327}
328
329const char* armMnemonicStrings[] = {
330	"ill",
331	"adc",
332	"add",
333	"and",
334	"asr",
335	"b",
336	"bic",
337	"bkpt",
338	"bl",
339	"blh",
340	"bx",
341	"cmn",
342	"cmp",
343	"eor",
344	"ldm",
345	"ldr",
346	"lsl",
347	"lsr",
348	"mov",
349	"mul",
350	"mvn",
351	"neg",
352	"orr",
353	"ror",
354    "sbc",
355    "stm",
356	"str",
357	"sub",
358	"swi",
359	"tst"
360};
361
362const char* armDirectionStrings[] = {
363	"da",
364	"ia",
365	"db",
366	"da"
367};
368
369const char* armAccessTypeStrings[] = {
370	"",
371	"b",
372	"h",
373	"",
374	"",
375	"",
376	"",
377	"",
378	"",
379	"sb",
380	"sh",
381	""
382	""
383};
384
385int ARMDisassembleThumb(uint16_t opcode, uint32_t pc, char* buffer, int blen) {
386	struct ARMInstructionInfo info;
387	ARMDecodeThumb(opcode, &info);
388	const char* mnemonic = armMnemonicStrings[info.mnemonic];
389	int written;
390	int total = 0;
391	const char* cond = "";
392	if (info.condition != ARM_CONDITION_AL && info.condition < ARM_CONDITION_NV) {
393		cond = _armConditions[info.condition];
394	}
395	const char* flags = "";
396	switch (info.mnemonic) {
397	case ARM_MN_LDM:
398	case ARM_MN_STM:
399		flags = armDirectionStrings[info.memory.direction];
400		break;
401	case ARM_MN_LDR:
402	case ARM_MN_STR:
403		flags = armAccessTypeStrings[info.memory.direction];
404		break;
405	default:
406		break;
407	}
408	written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, flags, cond);
409	ADVANCE(written);
410
411	switch (info.mnemonic) {
412	case ARM_MN_LDM:
413	case ARM_MN_STM:
414		written = _decodeRegister(info.memory.baseReg, buffer, blen);
415		ADVANCE(written);
416		strncpy(buffer, "!, ", blen - 1);
417		ADVANCE(3);
418		written = _decodeRegisterList(info.op1.immediate, buffer, blen);
419		ADVANCE(written);
420		break;
421	case ARM_MN_B:
422		written = _decodePCRelative(info.op1.immediate, pc, buffer, blen);
423		ADVANCE(written);
424		break;
425	default:
426		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_1) {
427			written = snprintf(buffer, blen - 1, "#%i", info.op1.immediate);
428			ADVANCE(written);
429		} else if (info.operandFormat & ARM_OPERAND_MEMORY_1) {
430			written = _decodeMemory(info.memory, pc, buffer, blen);
431			ADVANCE(written);
432		} else if (info.operandFormat & ARM_OPERAND_REGISTER_1) {
433			written = _decodeRegister(info.op1.reg, buffer, blen);
434			ADVANCE(written);
435		}
436		if (info.operandFormat & ARM_OPERAND_2) {
437			strncpy(buffer, ", ", blen);
438			ADVANCE(2);
439		}
440		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_2) {
441			written = snprintf(buffer, blen - 1, "#%i", info.op2.immediate);
442			ADVANCE(written);
443		} else if (info.operandFormat & ARM_OPERAND_MEMORY_2) {
444			written = _decodeMemory(info.memory, pc, buffer, blen);
445			ADVANCE(written);
446		} else if (info.operandFormat & ARM_OPERAND_REGISTER_2) {
447			written = _decodeRegister(info.op2.reg, buffer, blen);
448			ADVANCE(written);
449		}
450		if (info.operandFormat & ARM_OPERAND_3) {
451			strncpy(buffer, ", ", blen - 1);
452			ADVANCE(2);
453		}
454		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_3) {
455			written = snprintf(buffer, blen - 1, "#%i", info.op3.immediate);
456			ADVANCE(written);
457		} else if (info.operandFormat & ARM_OPERAND_MEMORY_3) {
458			written = _decodeMemory(info.memory, pc, buffer, blen);
459			ADVANCE(written);
460		} else if (info.operandFormat & ARM_OPERAND_REGISTER_3) {
461			written = _decodeRegister(info.op1.reg, buffer, blen);
462			ADVANCE(written);
463		}
464		break;
465	}
466	buffer[blen - 1] = '\0';
467	return total;
468}