all repos — mgba @ 67d3eed8fbdfadfce9c3f5c0ac1c6b4ad323b9e4

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