all repos — mgba @ 262e46b8a6a430e3cc104a58b8fffedb1afa186f

mGBA Game Boy Advance Emulator

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

  1/* Copyright (c) 2013-2014 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "decoder.h"
  7
  8#include "decoder-inlines.h"
  9#include "emitter-thumb.h"
 10#include "isa-inlines.h"
 11
 12#define DEFINE_THUMB_DECODER(NAME, MNEMONIC, BODY) \
 13	static void _ThumbDecode ## NAME (uint16_t opcode, struct ARMInstructionInfo* info) { \
 14		UNUSED(opcode); \
 15		info->mnemonic = ARM_MN_ ## MNEMONIC; \
 16		BODY; \
 17	}
 18
 19#define DEFINE_IMMEDIATE_5_DECODER_DATA_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
 20	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 21		info->op3.immediate = IMMEDIATE; \
 22		info->op1.reg = opcode & 0x0007; \
 23		info->op2.reg = (opcode >> 3) & 0x0007; \
 24		info->affectsCPSR = 1; \
 25		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 26			ARM_OPERAND_AFFECTED_1 | \
 27			ARM_OPERAND_REGISTER_2 | \
 28			ARM_OPERAND_IMMEDIATE_3;)
 29
 30#define DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, CYCLES, WIDTH) \
 31	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 32		info->op1.reg = opcode & 0x0007; \
 33		info->memory.baseReg = (opcode >> 3) & 0x0007; \
 34		info->memory.offset.immediate = IMMEDIATE * WIDTH; \
 35		info->memory.width = (enum ARMMemoryAccessType) WIDTH; \
 36		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 37			ARM_OPERAND_AFFECTED_1 | \
 38			ARM_OPERAND_MEMORY_2; \
 39		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
 40			ARM_MEMORY_IMMEDIATE_OFFSET; \
 41		CYCLES)
 42
 43#define DEFINE_IMMEDIATE_5_DECODER_MEM_LOAD_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
 44	DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, LOAD_CYCLES, WIDTH)
 45
 46#define DEFINE_IMMEDIATE_5_DECODER_MEM_STORE_THUMB(NAME, IMMEDIATE, MNEMONIC, WIDTH) \
 47	DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, IMMEDIATE, MNEMONIC, STORE_CYCLES, WIDTH)
 48
 49#define DEFINE_IMMEDIATE_5_DECODER_THUMB(NAME, MNEMONIC, TYPE, WIDTH) \
 50	COUNT_CALL_5(DEFINE_IMMEDIATE_5_DECODER_ ## TYPE ## _THUMB, NAME ## _, MNEMONIC, WIDTH)
 51
 52DEFINE_IMMEDIATE_5_DECODER_THUMB(LSL1, LSL, DATA,)
 53DEFINE_IMMEDIATE_5_DECODER_THUMB(LSR1, LSR, DATA,)
 54DEFINE_IMMEDIATE_5_DECODER_THUMB(ASR1, ASR, DATA,)
 55DEFINE_IMMEDIATE_5_DECODER_THUMB(LDR1, LDR, MEM_LOAD, 4)
 56DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRB1, LDR, MEM_LOAD, 1)
 57DEFINE_IMMEDIATE_5_DECODER_THUMB(LDRH1, LDR, MEM_LOAD, 2)
 58DEFINE_IMMEDIATE_5_DECODER_THUMB(STR1, STR, MEM_STORE, 4)
 59DEFINE_IMMEDIATE_5_DECODER_THUMB(STRB1, STR, MEM_STORE, 1)
 60DEFINE_IMMEDIATE_5_DECODER_THUMB(STRH1, STR, MEM_STORE, 2)
 61
 62#define DEFINE_DATA_FORM_1_DECODER_EX_THUMB(NAME, RM, MNEMONIC) \
 63	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 64		info->op1.reg = opcode & 0x0007; \
 65		info->op2.reg = (opcode >> 3) & 0x0007; \
 66		info->op3.reg = RM; \
 67		info->affectsCPSR = 1; \
 68		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 69			ARM_OPERAND_AFFECTED_1 | \
 70			ARM_OPERAND_REGISTER_2 | \
 71			ARM_OPERAND_REGISTER_3;)
 72
 73#define DEFINE_DATA_FORM_1_DECODER_THUMB(NAME) \
 74	COUNT_CALL_3(DEFINE_DATA_FORM_1_DECODER_EX_THUMB, NAME ## 3_R, NAME)
 75
 76DEFINE_DATA_FORM_1_DECODER_THUMB(ADD)
 77DEFINE_DATA_FORM_1_DECODER_THUMB(SUB)
 78
 79#define DEFINE_DATA_FORM_2_DECODER_EX_THUMB(NAME, IMMEDIATE, MNEMONIC) \
 80	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 81		info->op1.reg = opcode & 0x0007; \
 82		info->op2.reg = (opcode >> 3) & 0x0007; \
 83		info->op3.immediate = IMMEDIATE; \
 84		info->affectsCPSR = 1; \
 85		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
 86			ARM_OPERAND_AFFECTED_1 | \
 87			ARM_OPERAND_REGISTER_2 | \
 88			ARM_OPERAND_IMMEDIATE_3;)
 89
 90#define DEFINE_DATA_FORM_2_DECODER_THUMB(NAME) \
 91	COUNT_CALL_3(DEFINE_DATA_FORM_2_DECODER_EX_THUMB, NAME ## 1_, NAME)
 92
 93DEFINE_DATA_FORM_2_DECODER_THUMB(ADD)
 94DEFINE_DATA_FORM_2_DECODER_THUMB(SUB)
 95
 96#define DEFINE_DATA_FORM_3_DECODER_EX_THUMB(NAME, RD, MNEMONIC, AFFECTED) \
 97	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
 98		info->op1.reg = RD; \
 99		info->op2.immediate = opcode & 0x00FF; \
100		info->affectsCPSR = 1; \
101		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
102			AFFECTED | \
103			ARM_OPERAND_IMMEDIATE_2;)
104
105#define DEFINE_DATA_FORM_3_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
106	COUNT_CALL_3(DEFINE_DATA_FORM_3_DECODER_EX_THUMB, NAME ## _R, MNEMONIC, AFFECTED)
107
108DEFINE_DATA_FORM_3_DECODER_THUMB(ADD2, ADD, ARM_OPERAND_AFFECTED_1)
109DEFINE_DATA_FORM_3_DECODER_THUMB(CMP1, CMP, ARM_OPERAND_NONE)
110DEFINE_DATA_FORM_3_DECODER_THUMB(MOV1, MOV, ARM_OPERAND_AFFECTED_1)
111DEFINE_DATA_FORM_3_DECODER_THUMB(SUB2, SUB, ARM_OPERAND_AFFECTED_1)
112
113#define DEFINE_DATA_FORM_5_DECODER_THUMB(NAME, MNEMONIC, AFFECTED) \
114	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
115		info->op1.reg = opcode & 0x0007; \
116		info->op2.reg = (opcode >> 3) & 0x0007; \
117		info->affectsCPSR = 1; \
118		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
119			AFFECTED | \
120			ARM_OPERAND_REGISTER_2;)
121
122DEFINE_DATA_FORM_5_DECODER_THUMB(AND, AND, ARM_OPERAND_AFFECTED_1)
123DEFINE_DATA_FORM_5_DECODER_THUMB(EOR, EOR, ARM_OPERAND_AFFECTED_1)
124DEFINE_DATA_FORM_5_DECODER_THUMB(LSL2, LSL, ARM_OPERAND_AFFECTED_1)
125DEFINE_DATA_FORM_5_DECODER_THUMB(LSR2, LSR, ARM_OPERAND_AFFECTED_1)
126DEFINE_DATA_FORM_5_DECODER_THUMB(ASR2, ASR, ARM_OPERAND_AFFECTED_1)
127DEFINE_DATA_FORM_5_DECODER_THUMB(ADC, ADC, ARM_OPERAND_AFFECTED_1)
128DEFINE_DATA_FORM_5_DECODER_THUMB(SBC, SBC, ARM_OPERAND_AFFECTED_1)
129DEFINE_DATA_FORM_5_DECODER_THUMB(ROR, ROR, ARM_OPERAND_AFFECTED_1)
130DEFINE_DATA_FORM_5_DECODER_THUMB(TST, TST, ARM_OPERAND_NONE)
131DEFINE_DATA_FORM_5_DECODER_THUMB(NEG, NEG, ARM_OPERAND_AFFECTED_1)
132DEFINE_DATA_FORM_5_DECODER_THUMB(CMP2, CMP, ARM_OPERAND_NONE)
133DEFINE_DATA_FORM_5_DECODER_THUMB(CMN, CMN, ARM_OPERAND_NONE)
134DEFINE_DATA_FORM_5_DECODER_THUMB(ORR, ORR, ARM_OPERAND_AFFECTED_1)
135DEFINE_DATA_FORM_5_DECODER_THUMB(MUL, MUL, ARM_OPERAND_AFFECTED_1)
136DEFINE_DATA_FORM_5_DECODER_THUMB(BIC, BIC, ARM_OPERAND_AFFECTED_1)
137DEFINE_DATA_FORM_5_DECODER_THUMB(MVN, MVN, ARM_OPERAND_AFFECTED_1)
138
139#define DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME, H1, H2, MNEMONIC, AFFECTED, CPSR) \
140	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
141		info->op1.reg = (opcode & 0x0007) | H1; \
142		info->op2.reg = ((opcode >> 3) & 0x0007) | H2; \
143		if (info->op1.reg == ARM_PC) { \
144			info->branchType = ARM_BRANCH_INDIRECT; \
145		} \
146		info->affectsCPSR = CPSR; \
147		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
148			AFFECTED | \
149			ARM_OPERAND_REGISTER_2;)
150
151
152#define DEFINE_DECODER_WITH_HIGH_THUMB(NAME, MNEMONIC, AFFECTED, CPSR) \
153	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 00, 0, 0, MNEMONIC, AFFECTED, CPSR) \
154	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 01, 0, 8, MNEMONIC, AFFECTED, CPSR) \
155	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 10, 8, 0, MNEMONIC, AFFECTED, CPSR) \
156	DEFINE_DECODER_WITH_HIGH_EX_THUMB(NAME ## 11, 8, 8, MNEMONIC, AFFECTED, CPSR)
157
158DEFINE_DECODER_WITH_HIGH_THUMB(ADD4, ADD, ARM_OPERAND_AFFECTED_1, 0)
159DEFINE_DECODER_WITH_HIGH_THUMB(CMP3, CMP, ARM_OPERAND_NONE, 1)
160DEFINE_DECODER_WITH_HIGH_THUMB(MOV3, MOV, ARM_OPERAND_AFFECTED_1, 0)
161
162#define DEFINE_IMMEDIATE_WITH_REGISTER_DATA_THUMB(NAME, RD, MNEMONIC, REG) \
163	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
164		info->op1.reg = RD; \
165		info->op2.reg = REG; \
166		info->op3.immediate = (opcode & 0x00FF) << 2; \
167		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
168			ARM_OPERAND_AFFECTED_1 | \
169			ARM_OPERAND_REGISTER_2 | \
170			ARM_OPERAND_IMMEDIATE_3;)
171
172#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, CYCLES) \
173	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
174		info->op1.reg = RD; \
175		info->memory.baseReg = REG; \
176		info->memory.offset.immediate = (opcode & 0x00FF) << 2; \
177		info->memory.width = ARM_ACCESS_WORD; \
178		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
179			ARM_OPERAND_AFFECTED_1 | \
180			ARM_OPERAND_MEMORY_2; \
181		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
182			ARM_MEMORY_IMMEDIATE_OFFSET; \
183		CYCLES;)
184
185#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_LOAD_THUMB(NAME, RD, MNEMONIC, REG) \
186	DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, LOAD_CYCLES)
187
188#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_STORE_THUMB(NAME, RD, MNEMONIC, REG) \
189	DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, RD, MNEMONIC, REG, STORE_CYCLES)
190
191#define DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(NAME, MNEMONIC, TYPE, REG) \
192	COUNT_CALL_3(DEFINE_IMMEDIATE_WITH_REGISTER_ ## TYPE ## _THUMB, NAME ## _R, MNEMONIC, REG)
193
194DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR3, LDR, MEM_LOAD, ARM_PC)
195DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR4, LDR, MEM_LOAD, ARM_SP)
196DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(STR3, STR, MEM_STORE, ARM_SP)
197
198DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD5, ADD, DATA, ARM_PC)
199DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD6, ADD, DATA, ARM_SP)
200
201#define DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB(NAME, RM, MNEMONIC, CYCLES, TYPE) \
202	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
203		info->memory.offset.reg = RM; \
204		info->op1.reg = opcode & 0x0007; \
205		info->memory.baseReg = (opcode >> 3) & 0x0007; \
206		info->memory.width = TYPE; \
207		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
208			ARM_OPERAND_AFFECTED_1 | /* TODO: Remove this for STR */ \
209			ARM_OPERAND_MEMORY_2; \
210		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
211			ARM_MEMORY_REGISTER_OFFSET; \
212		CYCLES;)
213
214#define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, MNEMONIC, CYCLES, TYPE) \
215	COUNT_CALL_3(DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB, NAME ## _R, MNEMONIC, CYCLES, TYPE)
216
217DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, LDR, LOAD_CYCLES, ARM_ACCESS_WORD)
218DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, LDR, LOAD_CYCLES, ARM_ACCESS_BYTE)
219DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, LDR, LOAD_CYCLES, ARM_ACCESS_HALFWORD)
220DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_BYTE)
221DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_HALFWORD)
222DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, STR, STORE_CYCLES, ARM_ACCESS_WORD)
223DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, STR, STORE_CYCLES, ARM_ACCESS_BYTE)
224DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STR, STORE_CYCLES, ARM_ACCESS_HALFWORD)
225
226// TODO: Estimate memory cycles
227#define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, MNEMONIC, DIRECTION, ADDITIONAL_REG) \
228	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
229		info->memory.baseReg = RN; \
230		info->op1.immediate = (opcode & 0xFF) | ADDITIONAL_REG; \
231		if (info->op1.immediate & (1 << ARM_PC)) { \
232			info->branchType = ARM_BRANCH_INDIRECT; \
233		} \
234		info->operandFormat = ARM_OPERAND_MEMORY_1; \
235		info->memory.format = ARM_MEMORY_REGISTER_BASE | \
236			ARM_MEMORY_WRITEBACK | \
237			DIRECTION;)
238
239#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME) \
240	COUNT_CALL_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## IA_R, NAME, ARM_MEMORY_INCREMENT_AFTER, 0)
241
242DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDM)
243DEFINE_LOAD_STORE_MULTIPLE_THUMB(STM)
244
245#define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
246	DEFINE_THUMB_DECODER(B ## COND, B, \
247		int8_t immediate = opcode; \
248		info->op1.immediate = immediate << 1; \
249		info->branchType = ARM_BRANCH; \
250		info->condition = ARM_CONDITION_ ## COND; \
251		info->operandFormat = ARM_OPERAND_IMMEDIATE_1;)
252
253DEFINE_CONDITIONAL_BRANCH_THUMB(EQ)
254DEFINE_CONDITIONAL_BRANCH_THUMB(NE)
255DEFINE_CONDITIONAL_BRANCH_THUMB(CS)
256DEFINE_CONDITIONAL_BRANCH_THUMB(CC)
257DEFINE_CONDITIONAL_BRANCH_THUMB(MI)
258DEFINE_CONDITIONAL_BRANCH_THUMB(PL)
259DEFINE_CONDITIONAL_BRANCH_THUMB(VS)
260DEFINE_CONDITIONAL_BRANCH_THUMB(VC)
261DEFINE_CONDITIONAL_BRANCH_THUMB(LS)
262DEFINE_CONDITIONAL_BRANCH_THUMB(HI)
263DEFINE_CONDITIONAL_BRANCH_THUMB(GE)
264DEFINE_CONDITIONAL_BRANCH_THUMB(LT)
265DEFINE_CONDITIONAL_BRANCH_THUMB(GT)
266DEFINE_CONDITIONAL_BRANCH_THUMB(LE)
267
268#define DEFINE_SP_MODIFY_THUMB(NAME, MNEMONIC) \
269	DEFINE_THUMB_DECODER(NAME, MNEMONIC, \
270		info->op1.reg = ARM_SP; \
271		info->op2.immediate = (opcode & 0x7F) << 2; \
272		info->operandFormat = ARM_OPERAND_REGISTER_1 | \
273			ARM_OPERAND_AFFECTED_1 | \
274			ARM_OPERAND_IMMEDIATE_2;)
275
276DEFINE_SP_MODIFY_THUMB(ADD7, ADD)
277DEFINE_SP_MODIFY_THUMB(SUB4, SUB)
278
279DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POP, ARM_SP, LDM, ARM_MEMORY_INCREMENT_AFTER, 0)
280DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR, ARM_SP, LDM, ARM_MEMORY_INCREMENT_AFTER, 1 << ARM_PC)
281DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH, ARM_SP, STM, ARM_MEMORY_DECREMENT_BEFORE, 0)
282DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR, ARM_SP, STM, ARM_MEMORY_DECREMENT_BEFORE, 1 << ARM_LR)
283
284DEFINE_THUMB_DECODER(ILL, ILL, info->traps = 1;)
285DEFINE_THUMB_DECODER(BKPT, BKPT, info->traps = 1;)
286
287DEFINE_THUMB_DECODER(B, B,
288	int16_t immediate = (opcode & 0x07FF) << 5;
289	info->op1.immediate = (((int32_t) immediate) >> 4);
290	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
291	info->branchType = ARM_BRANCH;)
292
293DEFINE_THUMB_DECODER(BL1, BL,
294	int16_t immediate = (opcode & 0x07FF) << 5;
295	info->op1.reg = ARM_LR;
296	info->op2.reg = ARM_PC;
297	info->op3.immediate = (((int32_t) immediate) << 7);
298	info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 |
299		ARM_OPERAND_REGISTER_2 | ARM_OPERAND_AFFECTED_2 |
300		ARM_OPERAND_IMMEDIATE_3;)
301
302DEFINE_THUMB_DECODER(BL2, BL,
303	info->op1.reg = ARM_PC;
304	info->op2.reg = ARM_LR;
305	info->op3.immediate = (opcode & 0x07FF) << 1;
306	info->operandFormat = ARM_OPERAND_REGISTER_1 | ARM_OPERAND_AFFECTED_1 |
307		ARM_OPERAND_REGISTER_2 | ARM_OPERAND_IMMEDIATE_3;
308	info->branchType = ARM_BRANCH_LINKED;)
309
310DEFINE_THUMB_DECODER(BX, BX,
311	info->op1.reg = (opcode >> 3) & 0xF;
312	info->operandFormat = ARM_OPERAND_REGISTER_1;
313	info->branchType = ARM_BRANCH_INDIRECT;)
314
315DEFINE_THUMB_DECODER(SWI, SWI,
316	info->op1.immediate = opcode & 0xFF;
317	info->operandFormat = ARM_OPERAND_IMMEDIATE_1;
318	info->traps = 1;)
319
320typedef void (*ThumbDecoder)(uint16_t opcode, struct ARMInstructionInfo* info);
321
322static const ThumbDecoder _thumbDecoderTable[0x400] = {
323	DECLARE_THUMB_EMITTER_BLOCK(_ThumbDecode)
324};
325
326void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) {
327	info->execMode = MODE_THUMB;
328	info->opcode = opcode;
329	info->branchType = ARM_BRANCH_NONE;
330	info->traps = 0;
331	info->affectsCPSR = 0;
332	info->condition = ARM_CONDITION_AL;
333	info->sDataCycles = 0;
334	info->nDataCycles = 0;
335	info->sInstructionCycles = 1;
336	info->nInstructionCycles = 0;
337	info->iCycles = 0;
338	info->cCycles = 0;
339	ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6];
340	decoder(opcode, info);
341}
342
343bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, struct ARMInstructionInfo* out) {
344	if (info1->execMode != MODE_THUMB || info1->mnemonic != ARM_MN_BL) {
345		return false;
346	}
347	if (info2->execMode != MODE_THUMB || info2->mnemonic != ARM_MN_BL) {
348		return false;
349	}
350	if (info1->op1.reg != ARM_LR || info1->op2.reg != ARM_PC) {
351		return false;
352	}
353	if (info2->op1.reg != ARM_PC || info2->op2.reg != ARM_LR) {
354		return false;
355	}
356	out->op1.immediate = info1->op3.immediate | info2->op3.immediate;
357	out->operandFormat = ARM_OPERAND_IMMEDIATE_1;
358	out->execMode = MODE_THUMB;
359	out->mnemonic = ARM_MN_BL;
360	out->branchType = ARM_BRANCH_LINKED;
361	out->traps = 0;
362	out->affectsCPSR = 0;
363	out->condition = ARM_CONDITION_AL;
364	out->sDataCycles = 0;
365	out->nDataCycles = 0;
366	out->sInstructionCycles = 2;
367	out->nInstructionCycles = 0;
368	out->iCycles = 0;
369	out->cCycles = 0;
370	return true;
371}