1 /* thumbemu.c -- Thumb instruction emulation.
2 Copyright (C) 1996, Cygnus Software Technologies Ltd.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* We can provide simple Thumb simulation by decoding the Thumb
19 instruction into its corresponding ARM instruction, and using the
20 existing ARM simulator. */
22 #ifndef MODET /* required for the Thumb instruction support */
24 #error "MODET needs to be defined for the Thumb world to work"
34 /* Attempt to emulate an ARMv6 instruction.
35 Stores t_branch into PVALUE upon success or t_undefined otherwise. */
38 handle_v6_thumb_insn (ARMul_State
* state
,
47 * pvalid
= t_undefined
;
51 switch (tinstr
& 0xFFC0)
53 case 0xb660: /* cpsie */
54 case 0xb670: /* cpsid */
55 case 0x4600: /* cpy */
56 case 0xba00: /* rev */
57 case 0xba40: /* rev16 */
58 case 0xbac0: /* revsh */
59 case 0xb650: /* setend */
61 printf ("Unhandled v6 thumb insn: %04x\n", tinstr
);
62 * pvalid
= t_undefined
;
65 case 0xb200: /* sxth */
66 Rm
= state
->Reg
[(tinstr
& 0x38) >> 3];
68 state
->Reg
[(tinstr
& 0x7)] = (Rm
& 0xffff) | 0xffff0000;
70 state
->Reg
[(tinstr
& 0x7)] = Rm
& 0xffff;
72 case 0xb240: /* sxtb */
73 Rm
= state
->Reg
[(tinstr
& 0x38) >> 3];
75 state
->Reg
[(tinstr
& 0x7)] = (Rm
& 0xff) | 0xffffff00;
77 state
->Reg
[(tinstr
& 0x7)] = Rm
& 0xff;
79 case 0xb280: /* uxth */
80 Rm
= state
->Reg
[(tinstr
& 0x38) >> 3];
81 state
->Reg
[(tinstr
& 0x7)] = Rm
& 0xffff;
83 case 0xb2c0: /* uxtb */
84 Rm
= state
->Reg
[(tinstr
& 0x38) >> 3];
85 state
->Reg
[(tinstr
& 0x7)] = Rm
& 0xff;
88 /* Indicate that the instruction has been processed. */
92 /* Decode a 16bit Thumb instruction. The instruction is in the low
93 16-bits of the tinstr field, with the following Thumb instruction
94 held in the high 16-bits. Passing in two Thumb instructions allows
95 easier simulation of the special dual BL instruction. */
98 ARMul_ThumbDecode (ARMul_State
* state
,
103 tdstate valid
= t_decoded
; /* default assumes a valid instruction */
106 if (state
->bigendSig
)
108 next_instr
= tinstr
& 0xFFFF;
113 next_instr
= tinstr
>> 16;
117 #if 1 /* debugging to catch non updates */
118 *ainstr
= 0xDEADC0DE;
121 switch ((tinstr
& 0xF800) >> 11)
127 *ainstr
= 0xE1B00000 /* base opcode */
128 | ((tinstr
& 0x1800) >> (11 - 5)) /* shift type */
129 | ((tinstr
& 0x07C0) << (7 - 6)) /* imm5 */
130 | ((tinstr
& 0x0038) >> 3) /* Rs */
131 | ((tinstr
& 0x0007) << 12); /* Rd */
133 case 3: /* ADD/SUB */
136 ARMword subset
[4] = {
137 0xE0900000, /* ADDS Rd,Rs,Rn */
138 0xE0500000, /* SUBS Rd,Rs,Rn */
139 0xE2900000, /* ADDS Rd,Rs,#imm3 */
140 0xE2500000 /* SUBS Rd,Rs,#imm3 */
142 /* It is quicker indexing into a table, than performing switch
144 *ainstr
= subset
[(tinstr
& 0x0600) >> 9] /* base opcode */
145 | ((tinstr
& 0x01C0) >> 6) /* Rn or imm3 */
146 | ((tinstr
& 0x0038) << (16 - 3)) /* Rs */
147 | ((tinstr
& 0x0007) << (12 - 0)); /* Rd */
156 ARMword subset
[4] = {
157 0xE3B00000, /* MOVS Rd,#imm8 */
158 0xE3500000, /* CMP Rd,#imm8 */
159 0xE2900000, /* ADDS Rd,Rd,#imm8 */
160 0xE2500000, /* SUBS Rd,Rd,#imm8 */
162 *ainstr
= subset
[(tinstr
& 0x1800) >> 11] /* base opcode */
163 | ((tinstr
& 0x00FF) >> 0) /* imm8 */
164 | ((tinstr
& 0x0700) << (16 - 8)) /* Rn */
165 | ((tinstr
& 0x0700) << (12 - 8)); /* Rd */
168 case 8: /* Arithmetic and high register transfers */
169 /* TODO: Since the subsets for both Format 4 and Format 5
170 instructions are made up of different ARM encodings, we could
171 save the following conditional, and just have one large
173 if ((tinstr
& (1 << 10)) == 0)
180 { t_norm
, t_shift
, t_neg
, t_mul
}
185 { 0xE0100000, t_norm
}, /* ANDS Rd,Rd,Rs */
186 { 0xE0300000, t_norm
}, /* EORS Rd,Rd,Rs */
187 { 0xE1B00010, t_shift
}, /* MOVS Rd,Rd,LSL Rs */
188 { 0xE1B00030, t_shift
}, /* MOVS Rd,Rd,LSR Rs */
189 { 0xE1B00050, t_shift
}, /* MOVS Rd,Rd,ASR Rs */
190 { 0xE0B00000, t_norm
}, /* ADCS Rd,Rd,Rs */
191 { 0xE0D00000, t_norm
}, /* SBCS Rd,Rd,Rs */
192 { 0xE1B00070, t_shift
}, /* MOVS Rd,Rd,ROR Rs */
193 { 0xE1100000, t_norm
}, /* TST Rd,Rs */
194 { 0xE2700000, t_neg
}, /* RSBS Rd,Rs,#0 */
195 { 0xE1500000, t_norm
}, /* CMP Rd,Rs */
196 { 0xE1700000, t_norm
}, /* CMN Rd,Rs */
197 { 0xE1900000, t_norm
}, /* ORRS Rd,Rd,Rs */
198 { 0xE0100090, t_mul
} , /* MULS Rd,Rd,Rs */
199 { 0xE1D00000, t_norm
}, /* BICS Rd,Rd,Rs */
200 { 0xE1F00000, t_norm
} /* MVNS Rd,Rs */
202 *ainstr
= subset
[(tinstr
& 0x03C0) >> 6].opcode
; /* base */
203 switch (subset
[(tinstr
& 0x03C0) >> 6].otype
)
206 *ainstr
|= ((tinstr
& 0x0007) << 16) /* Rn */
207 | ((tinstr
& 0x0007) << 12) /* Rd */
208 | ((tinstr
& 0x0038) >> 3); /* Rs */
211 *ainstr
|= ((tinstr
& 0x0007) << 12) /* Rd */
212 | ((tinstr
& 0x0007) >> 0) /* Rm */
213 | ((tinstr
& 0x0038) << (8 - 3)); /* Rs */
216 *ainstr
|= ((tinstr
& 0x0007) << 12) /* Rd */
217 | ((tinstr
& 0x0038) << (16 - 3)); /* Rn */
220 *ainstr
|= ((tinstr
& 0x0007) << 16) /* Rd */
221 | ((tinstr
& 0x0007) << 8) /* Rs */
222 | ((tinstr
& 0x0038) >> 3); /* Rm */
229 ARMword Rd
= ((tinstr
& 0x0007) >> 0);
230 ARMword Rs
= ((tinstr
& 0x0038) >> 3);
231 if (tinstr
& (1 << 7))
233 if (tinstr
& (1 << 6))
235 switch ((tinstr
& 0x03C0) >> 6)
237 case 0x1: /* ADD Rd,Rd,Hs */
238 case 0x2: /* ADD Hd,Hd,Rs */
239 case 0x3: /* ADD Hd,Hd,Hs */
240 *ainstr
= 0xE0800000 /* base */
241 | (Rd
<< 16) /* Rn */
242 | (Rd
<< 12) /* Rd */
243 | (Rs
<< 0); /* Rm */
245 case 0x5: /* CMP Rd,Hs */
246 case 0x6: /* CMP Hd,Rs */
247 case 0x7: /* CMP Hd,Hs */
248 *ainstr
= 0xE1500000 /* base */
249 | (Rd
<< 16) /* Rn */
250 | (Rd
<< 12) /* Rd */
251 | (Rs
<< 0); /* Rm */
253 case 0x9: /* MOV Rd,Hs */
254 case 0xA: /* MOV Hd,Rs */
255 case 0xB: /* MOV Hd,Hs */
256 *ainstr
= 0xE1A00000 /* base */
257 | (Rd
<< 16) /* Rn */
258 | (Rd
<< 12) /* Rd */
259 | (Rs
<< 0); /* Rm */
261 case 0xC: /* BX Rs */
262 case 0xD: /* BX Hs */
263 *ainstr
= 0xE12FFF10 /* base */
264 | ((tinstr
& 0x0078) >> 3); /* Rd */
266 case 0xE: /* UNDEFINED */
267 case 0xF: /* UNDEFINED */
271 *ainstr
= 0xE12FFF30 /* base */
272 | ((tinstr
& 0x0078) >> 3); /* Rd */
276 case 0x0: /* UNDEFINED */
277 case 0x4: /* UNDEFINED */
278 case 0x8: /* UNDEFINED */
279 handle_v6_thumb_insn (state
, tinstr
, & valid
);
284 case 9: /* LDR Rd,[PC,#imm8] */
286 *ainstr
= 0xE59F0000 /* base */
287 | ((tinstr
& 0x0700) << (12 - 8)) /* Rd */
288 | ((tinstr
& 0x00FF) << (2 - 0)); /* off8 */
292 /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
293 the following could be merged into a single subset, saving on
294 the following boolean: */
295 if ((tinstr
& (1 << 9)) == 0)
298 ARMword subset
[4] = {
299 0xE7800000, /* STR Rd,[Rb,Ro] */
300 0xE7C00000, /* STRB Rd,[Rb,Ro] */
301 0xE7900000, /* LDR Rd,[Rb,Ro] */
302 0xE7D00000 /* LDRB Rd,[Rb,Ro] */
304 *ainstr
= subset
[(tinstr
& 0x0C00) >> 10] /* base */
305 | ((tinstr
& 0x0007) << (12 - 0)) /* Rd */
306 | ((tinstr
& 0x0038) << (16 - 3)) /* Rb */
307 | ((tinstr
& 0x01C0) >> 6); /* Ro */
312 ARMword subset
[4] = {
313 0xE18000B0, /* STRH Rd,[Rb,Ro] */
314 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */
315 0xE19000B0, /* LDRH Rd,[Rb,Ro] */
316 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */
318 *ainstr
= subset
[(tinstr
& 0x0C00) >> 10] /* base */
319 | ((tinstr
& 0x0007) << (12 - 0)) /* Rd */
320 | ((tinstr
& 0x0038) << (16 - 3)) /* Rb */
321 | ((tinstr
& 0x01C0) >> 6); /* Ro */
324 case 12: /* STR Rd,[Rb,#imm5] */
325 case 13: /* LDR Rd,[Rb,#imm5] */
326 case 14: /* STRB Rd,[Rb,#imm5] */
327 case 15: /* LDRB Rd,[Rb,#imm5] */
330 ARMword subset
[4] = {
331 0xE5800000, /* STR Rd,[Rb,#imm5] */
332 0xE5900000, /* LDR Rd,[Rb,#imm5] */
333 0xE5C00000, /* STRB Rd,[Rb,#imm5] */
334 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
336 /* The offset range defends on whether we are transferring a
337 byte or word value: */
338 *ainstr
= subset
[(tinstr
& 0x1800) >> 11] /* base */
339 | ((tinstr
& 0x0007) << (12 - 0)) /* Rd */
340 | ((tinstr
& 0x0038) << (16 - 3)) /* Rb */
341 | ((tinstr
& 0x07C0) >> (6 - ((tinstr
& (1 << 12)) ? 0 : 2))); /* off5 */
344 case 16: /* STRH Rd,[Rb,#imm5] */
345 case 17: /* LDRH Rd,[Rb,#imm5] */
347 *ainstr
= ((tinstr
& (1 << 11)) /* base */
348 ? 0xE1D000B0 /* LDRH */
349 : 0xE1C000B0) /* STRH */
350 | ((tinstr
& 0x0007) << (12 - 0)) /* Rd */
351 | ((tinstr
& 0x0038) << (16 - 3)) /* Rb */
352 | ((tinstr
& 0x01C0) >> (6 - 1)) /* off5, low nibble */
353 | ((tinstr
& 0x0600) >> (9 - 8)); /* off5, high nibble */
355 case 18: /* STR Rd,[SP,#imm8] */
356 case 19: /* LDR Rd,[SP,#imm8] */
358 *ainstr
= ((tinstr
& (1 << 11)) /* base */
359 ? 0xE59D0000 /* LDR */
360 : 0xE58D0000) /* STR */
361 | ((tinstr
& 0x0700) << (12 - 8)) /* Rd */
362 | ((tinstr
& 0x00FF) << 2); /* off8 */
364 case 20: /* ADD Rd,PC,#imm8 */
365 case 21: /* ADD Rd,SP,#imm8 */
367 if ((tinstr
& (1 << 11)) == 0)
369 /* NOTE: The PC value used here should by word aligned */
370 /* We encode shift-left-by-2 in the rotate immediate field,
371 so no shift of off8 is needed. */
372 *ainstr
= 0xE28F0F00 /* base */
373 | ((tinstr
& 0x0700) << (12 - 8)) /* Rd */
374 | (tinstr
& 0x00FF); /* off8 */
378 /* We encode shift-left-by-2 in the rotate immediate field,
379 so no shift of off8 is needed. */
380 *ainstr
= 0xE28D0F00 /* base */
381 | ((tinstr
& 0x0700) << (12 - 8)) /* Rd */
382 | (tinstr
& 0x00FF); /* off8 */
387 switch (tinstr
& 0x0F00)
391 /* NOTE: The instruction contains a shift left of 2
392 equivalent (implemented as ROR #30): */
393 *ainstr
= ((tinstr
& (1 << 7)) /* base */
394 ? 0xE24DDF00 /* SUB */
395 : 0xE28DDF00) /* ADD */
396 | (tinstr
& 0x007F); /* off7 */
399 /* Format 14 - Push */
400 * ainstr
= 0xE92D0000 | (tinstr
& 0x00FF);
403 /* Format 14 - Push + LR */
404 * ainstr
= 0xE92D4000 | (tinstr
& 0x00FF);
407 /* Format 14 - Pop */
408 * ainstr
= 0xE8BD0000 | (tinstr
& 0x00FF);
411 /* Format 14 - Pop + PC */
412 * ainstr
= 0xE8BD8000 | (tinstr
& 0x00FF);
417 /* This is normally an undefined instruction. The v5t architecture
418 defines this particular pattern as a BKPT instruction, for
419 hardware assisted debugging. We map onto the arm BKPT
421 * ainstr
= 0xE1200070 | ((tinstr
& 0xf0) << 4) | (tinstr
& 0xf);
426 /* Everything else is an undefined instruction. */
427 handle_v6_thumb_insn (state
, tinstr
, & valid
);
434 *ainstr
= ((tinstr
& (1 << 11)) /* base */
435 ? 0xE8B00000 /* LDMIA */
436 : 0xE8A00000) /* STMIA */
437 | ((tinstr
& 0x0700) << (16 - 8)) /* Rb */
438 | (tinstr
& 0x00FF); /* mask8 */
441 case 27: /* Bcc/SWI */
442 if ((tinstr
& 0x0F00) == 0x0F00)
444 /* Format 17 : SWI */
445 *ainstr
= 0xEF000000;
446 /* Breakpoint must be handled specially. */
447 if ((tinstr
& 0x00FF) == 0x18)
448 *ainstr
|= ((tinstr
& 0x00FF) << 16);
449 /* New breakpoint value. See gdb/arm-tdep.c */
450 else if ((tinstr
& 0x00FF) == 0xFE)
451 *ainstr
|= SWI_Breakpoint
;
453 *ainstr
|= (tinstr
& 0x00FF);
455 else if ((tinstr
& 0x0F00) != 0x0E00)
459 /* TODO: Since we are doing a switch here, we could just add
460 the SWI and undefined instruction checks into this
461 switch to same on a couple of conditionals: */
462 switch ((tinstr
& 0x0F00) >> 8)
489 doit
= (CFLAG
&& !ZFLAG
);
492 doit
= (!CFLAG
|| ZFLAG
);
495 doit
= ((!NFLAG
&& !VFLAG
) || (NFLAG
&& VFLAG
));
498 doit
= ((NFLAG
&& !VFLAG
) || (!NFLAG
&& VFLAG
));
501 doit
= ((!NFLAG
&& !VFLAG
&& !ZFLAG
)
502 || (NFLAG
&& VFLAG
&& !ZFLAG
));
505 doit
= ((NFLAG
&& !VFLAG
) || (!NFLAG
&& VFLAG
)) || ZFLAG
;
510 state
->Reg
[15] = (pc
+ 4
511 + (((tinstr
& 0x7F) << 1)
512 | ((tinstr
& (1 << 7)) ? 0xFFFFFF00 : 0)));
518 /* UNDEFINED : cc=1110(AL) uses different format. */
519 handle_v6_thumb_insn (state
, tinstr
, & valid
);
523 state
->Reg
[15] = (pc
+ 4
524 + (((tinstr
& 0x3FF) << 1)
525 | ((tinstr
& (1 << 10)) ? 0xFFFFF800 : 0)));
529 case 29: /* UNDEFINED */
534 handle_v6_thumb_insn (state
, tinstr
, & valid
);
540 /* There is no single ARM instruction equivalent for this
541 instruction. Also, it should only ever be matched with the
542 fmt19 "BL/BLX instruction 1" instruction. However, we do
543 allow the simulation of it on its own, with undefined results
544 if r14 is not suitably initialised. */
546 ARMword tmp
= (pc
+ 2);
548 state
->Reg
[15] = ((state
->Reg
[14] + ((tinstr
& 0x07FF) << 1))
551 state
->Reg
[14] = (tmp
| 1);
558 handle_v6_thumb_insn (state
, tinstr
, & valid
);
561 case 30: /* BL instruction 1 */
563 /* There is no single ARM instruction equivalent for this Thumb
564 instruction. To keep the simulation simple (from the user
565 perspective) we check if the following instruction is the
566 second half of this BL, and if it is we simulate it
568 state
->Reg
[14] = state
->Reg
[15] \
569 + (((tinstr
& 0x07FF) << 12) \
570 | ((tinstr
& (1 << 10)) ? 0xFF800000 : 0));
572 valid
= t_branch
; /* in-case we don't have the 2nd half */
573 tinstr
= next_instr
; /* move the instruction down */
574 pc
+= 2; /* point the pc at the 2nd half */
575 if (((tinstr
& 0xF800) >> 11) != 31)
577 if (((tinstr
& 0xF800) >> 11) == 29)
579 ARMword tmp
= (pc
+ 2);
581 state
->Reg
[15] = ((state
->Reg
[14]
582 + ((tinstr
& 0x07FE) << 1))
585 state
->Reg
[14] = (tmp
| 1);
590 /* Exit, since not correct instruction. */
594 /* else we fall through to process the second half of the BL */
595 pc
+= 2; /* point the pc at the 2nd half */
596 case 31: /* BL instruction 2 */
598 /* There is no single ARM instruction equivalent for this
599 instruction. Also, it should only ever be matched with the
600 fmt19 "BL instruction 1" instruction. However, we do allow
601 the simulation of it on its own, with undefined results if
602 r14 is not suitably initialised. */
606 state
->Reg
[15] = (state
->Reg
[14] + ((tinstr
& 0x07FF) << 1));
607 state
->Reg
[14] = (tmp
| 1);
This page took 0.042707 seconds and 4 git commands to generate.