all repos — mgba @ 2b0dccb243593e459128b8b491c9f346a18a7ca9

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.format = ARM_MEMORY_REGISTER_BASE | \
230			ARM_MEMORY_POST_INCREMENT | DIRECTION;)
231
232#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME) \
233	COUNT_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## IA_R, NAME, ARM_MEMORY_INCREMENT_AFTER, 0)
234
235DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDM)
236DEFINE_LOAD_STORE_MULTIPLE_THUMB(STM)
237
238#define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
239	DEFINE_THUMB_DECODER(B ## COND, B, \
240		int8_t immediate = opcode; \
241		info->op1.immediate = immediate << 1; \
242		info->branches = 1; \
243		info->condition = ARM_CONDITION_ ## COND; \
244		info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
245
246DEFINE_CONDITIONAL_BRANCH_THUMB(EQ)
247DEFINE_CONDITIONAL_BRANCH_THUMB(NE)
248DEFINE_CONDITIONAL_BRANCH_THUMB(CS)
249DEFINE_CONDITIONAL_BRANCH_THUMB(CC)
250DEFINE_CONDITIONAL_BRANCH_THUMB(MI)
251DEFINE_CONDITIONAL_BRANCH_THUMB(PL)
252DEFINE_CONDITIONAL_BRANCH_THUMB(VS)
253DEFINE_CONDITIONAL_BRANCH_THUMB(VC)
254DEFINE_CONDITIONAL_BRANCH_THUMB(LS)
255DEFINE_CONDITIONAL_BRANCH_THUMB(HI)
256DEFINE_CONDITIONAL_BRANCH_THUMB(GE)
257DEFINE_CONDITIONAL_BRANCH_THUMB(LT)
258DEFINE_CONDITIONAL_BRANCH_THUMB(GT)
259DEFINE_CONDITIONAL_BRANCH_THUMB(LE)
260
261#define DEFINE_SP_MODIFY_THUMB(NAME, MNEMONIC) \
262	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
263		info->op1.reg = ARM_SP; \
264		info->op2.immediate = (opcode & 0x7F) << 2; \
265		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
266			ARM_OPERAND_AFFECTED_1 | \
267			ARM_OPERAND_IMMEDIATE_2;)
268
269DEFINE_SP_MODIFY_THUMB(ADD7, ADD)
270DEFINE_SP_MODIFY_THUMB(SUB4, SUB)
271
272DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POP, ARM_SP, LDM, ARM_MEMORY_INCREMENT_AFTER, 0)
273DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR, ARM_SP, LDM, ARM_MEMORY_INCREMENT_AFTER, 1 << ARM_PC)
274DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH, ARM_SP, STM, ARM_MEMORY_DECREMENT_BEFORE, 0)
275DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR, ARM_SP, STM, ARM_MEMORY_DECREMENT_BEFORE, 1 << ARM_LR)
276
277DEFINE_THUMB_DECODER(ILL, ILL, info->traps = 1;)
278DEFINE_THUMB_DECODER(BKPT, BKPT, info->traps = 1;)
279
280DEFINE_THUMB_DECODER(B, B,
281	int16_t immediate = (opcode & 0x07FF) << 5;
282	info->op1.immediate = (((int32_t) immediate) >> 4);
283	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
284	info->branches = 1;)
285
286DEFINE_THUMB_DECODER(BL1, BLH,
287	int16_t immediate = (opcode & 0x07FF) << 5;
288	info->op1.immediate = (((int32_t) immediate) << 7);
289	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
290
291DEFINE_THUMB_DECODER(BL2, BL,
292	info->op1.immediate = (opcode & 0x07FF) << 1;
293	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
294	info->branches = 1;)
295
296DEFINE_THUMB_DECODER(BX, BX,
297	info->op1.reg = (opcode >> 3) & 0xF;
298	info->operandFormat = ARM_OPERAND_REGISTER_1;
299	info->branches = 1;)
300
301DEFINE_THUMB_DECODER(SWI, SWI,
302	info->op1.immediate = opcode & 0xFF;
303	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
304	info->traps = 1;)
305
306typedef void (*ThumbDecoder)(uint16_t opcode, struct ARMInstructionInfo* info);
307
308static const ThumbDecoder _thumbDecoderTable[0x400] = {
309	DECLARE_THUMB_EMITTER_BLOCK(_ThumbDecode)
310};
311
312void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) {
313	info->opcode = opcode;
314	info->branches = 0;
315	info->traps = 0;
316	info->affectsCPSR = 0;
317	info->condition = ARM_CONDITION_AL;
318	info->sDataCycles = 0;
319	info->nDataCycles = 0;
320	info->sInstructionCycles = 1;
321	info->nInstructionCycles = 0;
322	info->iCycles = 0;
323	info->cCycles = 0;
324	ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6];
325	decoder(opcode, info);
326}
327
328const char* armMnemonicStrings[] = {
329	"ill",
330	"adc",
331	"add",
332	"and",
333	"asr",
334	"b",
335	"bic",
336	"bkpt",
337	"bl",
338	"blh",
339	"bx",
340	"cmn",
341	"cmp",
342	"eor",
343	"ldm",
344	"ldr",
345	"lsl",
346	"lsr",
347	"mov",
348	"mul",
349	"mvn",
350	"neg",
351	"orr",
352	"ror",
353    "sbc",
354    "stm",
355	"str",
356	"sub",
357	"swi",
358	"tst"
359};
360
361const char* armDirectionStrings[] = {
362	"da",
363	"ia",
364	"db",
365	"da"
366};
367
368const char* armAccessTypeStrings[] = {
369	"",
370	"b",
371	"h",
372	"",
373	"",
374	"",
375	"",
376	"",
377	"",
378	"sb",
379	"sh",
380	""
381	""
382};
383
384int ARMDisassembleThumb(uint16_t opcode, uint32_t pc, char* buffer, int blen) {
385	struct ARMInstructionInfo info;
386	ARMDecodeThumb(opcode, &info);
387	const char* mnemonic = armMnemonicStrings[info.mnemonic];
388	int written;
389	int total = 0;
390	const char* cond = "";
391	if (info.condition != ARM_CONDITION_AL && info.condition < ARM_CONDITION_NV) {
392		cond = _armConditions[info.condition];
393	}
394	const char* flags = "";
395	switch (info.mnemonic) {
396	case ARM_MN_LDM:
397	case ARM_MN_STM:
398		flags = armDirectionStrings[MEMORY_FORMAT_TO_DIRECTION(info.memory.format)];
399		break;
400	case ARM_MN_LDR:
401	case ARM_MN_STR:
402		flags = armAccessTypeStrings[info.memory.width];
403		break;
404	default:
405		break;
406	}
407	written = snprintf(buffer, blen - 1, "%s%s%s ", mnemonic, flags, cond);
408	ADVANCE(written);
409
410	switch (info.mnemonic) {
411	case ARM_MN_LDM:
412	case ARM_MN_STM:
413		written = _decodeRegister(info.memory.baseReg, buffer, blen);
414		ADVANCE(written);
415		strncpy(buffer, "!, ", blen - 1);
416		ADVANCE(3);
417		written = _decodeRegisterList(info.op1.immediate, buffer, blen);
418		ADVANCE(written);
419		break;
420	case ARM_MN_B:
421		written = _decodePCRelative(info.op1.immediate, pc, buffer, blen);
422		ADVANCE(written);
423		break;
424	default:
425		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_1) {
426			written = snprintf(buffer, blen - 1, "#%i", info.op1.immediate);
427			ADVANCE(written);
428		} else if (info.operandFormat & ARM_OPERAND_MEMORY_1) {
429			written = _decodeMemory(info.memory, pc, buffer, blen);
430			ADVANCE(written);
431		} else if (info.operandFormat & ARM_OPERAND_REGISTER_1) {
432			written = _decodeRegister(info.op1.reg, buffer, blen);
433			ADVANCE(written);
434		}
435		if (info.operandFormat & ARM_OPERAND_2) {
436			strncpy(buffer, ", ", blen);
437			ADVANCE(2);
438		}
439		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_2) {
440			written = snprintf(buffer, blen - 1, "#%i", info.op2.immediate);
441			ADVANCE(written);
442		} else if (info.operandFormat & ARM_OPERAND_MEMORY_2) {
443			written = _decodeMemory(info.memory, pc, buffer, blen);
444			ADVANCE(written);
445		} else if (info.operandFormat & ARM_OPERAND_REGISTER_2) {
446			written = _decodeRegister(info.op2.reg, buffer, blen);
447			ADVANCE(written);
448		}
449		if (info.operandFormat & ARM_OPERAND_3) {
450			strncpy(buffer, ", ", blen - 1);
451			ADVANCE(2);
452		}
453		if (info.operandFormat & ARM_OPERAND_IMMEDIATE_3) {
454			written = snprintf(buffer, blen - 1, "#%i", info.op3.immediate);
455			ADVANCE(written);
456		} else if (info.operandFormat & ARM_OPERAND_MEMORY_3) {
457			written = _decodeMemory(info.memory, pc, buffer, blen);
458			ADVANCE(written);
459		} else if (info.operandFormat & ARM_OPERAND_REGISTER_3) {
460			written = _decodeRegister(info.op1.reg, buffer, blen);
461			ADVANCE(written);
462		}
463		break;
464	}
465	buffer[blen - 1] = '\0';
466	return total;
467}