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) & 0x0007; \
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) \
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) & 0x0007) * 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
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)
47DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDRB1, LDR, LOAD_CYCLES, 1)
48DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDRH1, LDR, LOAD_CYCLES, 2)
49DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STR1, STR, STORE_CYCLES, 4)
50DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STRB1, STR, STORE_CYCLES, 1)
51DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STRH1, STR, STORE_CYCLES, 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) \
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_1 | \
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)
168DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(LDR4, LDR, ARM_SP, LOAD_CYCLES)
169DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(STR3, STR, ARM_SP, STORE_CYCLES)
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) \
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_1 | /* TODO: Remove this for STR */ \
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)
188DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, LDR, LOAD_CYCLES, ARM_ACCESS_BYTE)
189DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, LDR, LOAD_CYCLES, ARM_ACCESS_HALFWORD)
190DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_BYTE)
191DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_HALFWORD)
192DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, STR, STORE_CYCLES, ARM_ACCESS_WORD)
193DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, STR, STORE_CYCLES, ARM_ACCESS_BYTE)
194DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STR, STORE_CYCLES, ARM_ACCESS_HALFWORD)
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; \
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 info->execMode = MODE_THUMB;
303 info->opcode = opcode;
304 info->branchType = ARM_BRANCH_NONE;
305 info->traps = 0;
306 info->affectsCPSR = 0;
307 info->condition = ARM_CONDITION_AL;
308 info->sDataCycles = 0;
309 info->nDataCycles = 0;
310 info->sInstructionCycles = 1;
311 info->nInstructionCycles = 0;
312 info->iCycles = 0;
313 info->cCycles = 0;
314 ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6];
315 decoder(opcode, info);
316}
317
318bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2, struct ARMInstructionInfo* out) {
319 if (info1->execMode != MODE_THUMB || info1->mnemonic != ARM_MN_BL) {
320 return false;
321 }
322 if (info2->execMode != MODE_THUMB || info2->mnemonic != ARM_MN_BL) {
323 return false;
324 }
325 if (info1->op1.reg != ARM_LR || info1->op2.reg != ARM_PC) {
326 return false;
327 }
328 if (info2->op1.reg != ARM_PC || info2->op2.reg != ARM_LR) {
329 return false;
330 }
331 out->op1.immediate = info1->op3.immediate | info2->op3.immediate;
332 out->operandFormat = ARM_OPERAND_IMMEDIATE_1;
333 out->execMode = MODE_THUMB;
334 out->mnemonic = ARM_MN_BL;
335 out->branchType = ARM_BRANCH_LINKED;
336 out->traps = 0;
337 out->affectsCPSR = 0;
338 out->condition = ARM_CONDITION_AL;
339 out->sDataCycles = 0;
340 out->nDataCycles = 0;
341 out->sInstructionCycles = 2;
342 out->nInstructionCycles = 0;
343 out->iCycles = 0;
344 out->cCycles = 0;
345 return true;
346}