all repos — mgba @ b1b5cf8a11d8f19753312b554abc8752708a7347

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