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 3 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, see <http://www.gnu.org/licenses/>. */
17 /* We can provide simple Thumb simulation by decoding the Thumb
18 instruction into its corresponding ARM instruction, and using the
19 existing ARM simulator. */
21 #ifndef MODET /* required for the Thumb instruction support */
23 #error "MODET needs to be defined for the Thumb world to work"
33 /* Attempt to emulate an ARMv6 instruction.
34 Stores t_branch into PVALUE upon success or t_undefined otherwise. */
37 handle_v6_thumb_insn (ARMul_State * state,
43 * pvalid = t_undefined;
47 switch (tinstr & 0xFFC0)
49 case 0xb660: /* cpsie */
50 case 0xb670: /* cpsid */
51 case 0x4600: /* cpy */
52 case 0xba00: /* rev */
53 case 0xba40: /* rev16 */
54 case 0xbac0: /* revsh */
55 case 0xb650: /* setend */
57 printf ("Unhandled v6 thumb insn: %04x\n", tinstr);
58 * pvalid = t_undefined;
61 case 0xb200: /* sxth */
63 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
66 state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000;
68 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
72 case 0xb240: /* sxtb */
74 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
77 state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00;
79 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
83 case 0xb280: /* uxth */
85 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
87 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
91 case 0xb2c0: /* uxtb */
93 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
95 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
99 /* Indicate that the instruction has been processed. */
103 /* Decode a 16bit Thumb instruction. The instruction is in the low
104 16-bits of the tinstr field, with the following Thumb instruction
105 held in the high 16-bits. Passing in two Thumb instructions allows
106 easier simulation of the special dual BL instruction. */
109 ARMul_ThumbDecode (ARMul_State * state,
114 tdstate valid = t_decoded; /* default assumes a valid instruction */
117 if (state->bigendSig)
119 next_instr = tinstr & 0xFFFF;
124 next_instr = tinstr >> 16;
129 fprintf (stderr, "pc: %x, Thumb instr: %x", pc & ~1, tinstr);
131 #if 1 /* debugging to catch non updates */
132 *ainstr = 0xDEADC0DE;
135 switch ((tinstr & 0xF800) >> 11)
141 *ainstr = 0xE1B00000 /* base opcode */
142 | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */
143 | ((tinstr & 0x07C0) << (7 - 6)) /* imm5 */
144 | ((tinstr & 0x0038) >> 3) /* Rs */
145 | ((tinstr & 0x0007) << 12); /* Rd */
147 case 3: /* ADD/SUB */
150 ARMword subset[4] = {
151 0xE0900000, /* ADDS Rd,Rs,Rn */
152 0xE0500000, /* SUBS Rd,Rs,Rn */
153 0xE2900000, /* ADDS Rd,Rs,#imm3 */
154 0xE2500000 /* SUBS Rd,Rs,#imm3 */
156 /* It is quicker indexing into a table, than performing switch
158 *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */
159 | ((tinstr & 0x01C0) >> 6) /* Rn or imm3 */
160 | ((tinstr & 0x0038) << (16 - 3)) /* Rs */
161 | ((tinstr & 0x0007) << (12 - 0)); /* Rd */
170 ARMword subset[4] = {
171 0xE3B00000, /* MOVS Rd,#imm8 */
172 0xE3500000, /* CMP Rd,#imm8 */
173 0xE2900000, /* ADDS Rd,Rd,#imm8 */
174 0xE2500000, /* SUBS Rd,Rd,#imm8 */
176 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */
177 | ((tinstr & 0x00FF) >> 0) /* imm8 */
178 | ((tinstr & 0x0700) << (16 - 8)) /* Rn */
179 | ((tinstr & 0x0700) << (12 - 8)); /* Rd */
182 case 8: /* Arithmetic and high register transfers */
183 /* TODO: Since the subsets for both Format 4 and Format 5
184 instructions are made up of different ARM encodings, we could
185 save the following conditional, and just have one large
187 if ((tinstr & (1 << 10)) == 0)
194 { t_norm, t_shift, t_neg, t_mul }
199 { 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */
200 { 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */
201 { 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */
202 { 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */
203 { 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */
204 { 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */
205 { 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */
206 { 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */
207 { 0xE1100000, t_norm}, /* TST Rd,Rs */
208 { 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */
209 { 0xE1500000, t_norm}, /* CMP Rd,Rs */
210 { 0xE1700000, t_norm}, /* CMN Rd,Rs */
211 { 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */
212 { 0xE0100090, t_mul} , /* MULS Rd,Rd,Rs */
213 { 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */
214 { 0xE1F00000, t_norm} /* MVNS Rd,Rs */
216 *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
217 switch (subset[(tinstr & 0x03C0) >> 6].otype)
220 *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
221 | ((tinstr & 0x0007) << 12) /* Rd */
222 | ((tinstr & 0x0038) >> 3); /* Rs */
225 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
226 | ((tinstr & 0x0007) >> 0) /* Rm */
227 | ((tinstr & 0x0038) << (8 - 3)); /* Rs */
230 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
231 | ((tinstr & 0x0038) << (16 - 3)); /* Rn */
234 *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
235 | ((tinstr & 0x0007) << 8) /* Rs */
236 | ((tinstr & 0x0038) >> 3); /* Rm */
243 ARMword Rd = ((tinstr & 0x0007) >> 0);
244 ARMword Rs = ((tinstr & 0x0038) >> 3);
245 if (tinstr & (1 << 7))
247 if (tinstr & (1 << 6))
249 switch ((tinstr & 0x03C0) >> 6)
251 case 0x1: /* ADD Rd,Rd,Hs */
252 case 0x2: /* ADD Hd,Hd,Rs */
253 case 0x3: /* ADD Hd,Hd,Hs */
254 *ainstr = 0xE0800000 /* base */
255 | (Rd << 16) /* Rn */
256 | (Rd << 12) /* Rd */
257 | (Rs << 0); /* Rm */
259 case 0x5: /* CMP Rd,Hs */
260 case 0x6: /* CMP Hd,Rs */
261 case 0x7: /* CMP Hd,Hs */
262 *ainstr = 0xE1500000 /* base */
263 | (Rd << 16) /* Rn */
264 | (Rd << 12) /* Rd */
265 | (Rs << 0); /* Rm */
267 case 0x9: /* MOV Rd,Hs */
268 case 0xA: /* MOV Hd,Rs */
269 case 0xB: /* MOV Hd,Hs */
270 *ainstr = 0xE1A00000 /* base */
271 | (Rd << 16) /* Rn */
272 | (Rd << 12) /* Rd */
273 | (Rs << 0); /* Rm */
275 case 0xC: /* BX Rs */
276 case 0xD: /* BX Hs */
277 *ainstr = 0xE12FFF10 /* base */
278 | ((tinstr & 0x0078) >> 3); /* Rd */
280 case 0xE: /* UNDEFINED */
281 case 0xF: /* UNDEFINED */
285 *ainstr = 0xE12FFF30 /* base */
286 | ((tinstr & 0x0078) >> 3); /* Rd */
290 case 0x0: /* UNDEFINED */
291 case 0x4: /* UNDEFINED */
292 case 0x8: /* UNDEFINED */
293 handle_v6_thumb_insn (state, tinstr, & valid);
298 case 9: /* LDR Rd,[PC,#imm8] */
300 *ainstr = 0xE59F0000 /* base */
301 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
302 | ((tinstr & 0x00FF) << (2 - 0)); /* off8 */
306 /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
307 the following could be merged into a single subset, saving on
308 the following boolean: */
309 if ((tinstr & (1 << 9)) == 0)
312 ARMword subset[4] = {
313 0xE7800000, /* STR Rd,[Rb,Ro] */
314 0xE7C00000, /* STRB Rd,[Rb,Ro] */
315 0xE7900000, /* LDR Rd,[Rb,Ro] */
316 0xE7D00000 /* LDRB 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 */
326 ARMword subset[4] = {
327 0xE18000B0, /* STRH Rd,[Rb,Ro] */
328 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */
329 0xE19000B0, /* LDRH Rd,[Rb,Ro] */
330 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */
332 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
333 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
334 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
335 | ((tinstr & 0x01C0) >> 6); /* Ro */
338 case 12: /* STR Rd,[Rb,#imm5] */
339 case 13: /* LDR Rd,[Rb,#imm5] */
340 case 14: /* STRB Rd,[Rb,#imm5] */
341 case 15: /* LDRB Rd,[Rb,#imm5] */
344 ARMword subset[4] = {
345 0xE5800000, /* STR Rd,[Rb,#imm5] */
346 0xE5900000, /* LDR Rd,[Rb,#imm5] */
347 0xE5C00000, /* STRB Rd,[Rb,#imm5] */
348 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
350 /* The offset range defends on whether we are transferring a
351 byte or word value: */
352 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */
353 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
354 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
355 | ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */
358 case 16: /* STRH Rd,[Rb,#imm5] */
359 case 17: /* LDRH Rd,[Rb,#imm5] */
361 *ainstr = ((tinstr & (1 << 11)) /* base */
362 ? 0xE1D000B0 /* LDRH */
363 : 0xE1C000B0) /* STRH */
364 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
365 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
366 | ((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */
367 | ((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */
369 case 18: /* STR Rd,[SP,#imm8] */
370 case 19: /* LDR Rd,[SP,#imm8] */
372 *ainstr = ((tinstr & (1 << 11)) /* base */
373 ? 0xE59D0000 /* LDR */
374 : 0xE58D0000) /* STR */
375 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
376 | ((tinstr & 0x00FF) << 2); /* off8 */
378 case 20: /* ADD Rd,PC,#imm8 */
379 case 21: /* ADD Rd,SP,#imm8 */
381 if ((tinstr & (1 << 11)) == 0)
383 /* NOTE: The PC value used here should by word aligned */
384 /* We encode shift-left-by-2 in the rotate immediate field,
385 so no shift of off8 is needed. */
386 *ainstr = 0xE28F0F00 /* base */
387 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
388 | (tinstr & 0x00FF); /* off8 */
392 /* We encode shift-left-by-2 in the rotate immediate field,
393 so no shift of off8 is needed. */
394 *ainstr = 0xE28D0F00 /* base */
395 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
396 | (tinstr & 0x00FF); /* off8 */
401 switch (tinstr & 0x0F00)
405 /* NOTE: The instruction contains a shift left of 2
406 equivalent (implemented as ROR #30): */
407 *ainstr = ((tinstr & (1 << 7)) /* base */
408 ? 0xE24DDF00 /* SUB */
409 : 0xE28DDF00) /* ADD */
410 | (tinstr & 0x007F); /* off7 */
413 /* Format 14 - Push */
414 * ainstr = 0xE92D0000 | (tinstr & 0x00FF);
417 /* Format 14 - Push + LR */
418 * ainstr = 0xE92D4000 | (tinstr & 0x00FF);
421 /* Format 14 - Pop */
422 * ainstr = 0xE8BD0000 | (tinstr & 0x00FF);
425 /* Format 14 - Pop + PC */
426 * ainstr = 0xE8BD8000 | (tinstr & 0x00FF);
431 /* This is normally an undefined instruction. The v5t architecture
432 defines this particular pattern as a BKPT instruction, for
433 hardware assisted debugging. We map onto the arm BKPT
435 * ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
440 /* Everything else is an undefined instruction. */
441 handle_v6_thumb_insn (state, tinstr, & valid);
448 *ainstr = ((tinstr & (1 << 11)) /* base */
449 ? 0xE8B00000 /* LDMIA */
450 : 0xE8A00000) /* STMIA */
451 | ((tinstr & 0x0700) << (16 - 8)) /* Rb */
452 | (tinstr & 0x00FF); /* mask8 */
455 case 27: /* Bcc/SWI */
456 if ((tinstr & 0x0F00) == 0x0F00)
458 /* Format 17 : SWI */
459 *ainstr = 0xEF000000;
460 /* Breakpoint must be handled specially. */
461 if ((tinstr & 0x00FF) == 0x18)
462 *ainstr |= ((tinstr & 0x00FF) << 16);
463 /* New breakpoint value. See gdb/arm-tdep.c */
464 else if ((tinstr & 0x00FF) == 0xFE)
465 *ainstr |= SWI_Breakpoint;
467 *ainstr |= (tinstr & 0x00FF);
469 else if ((tinstr & 0x0F00) != 0x0E00)
473 /* TODO: Since we are doing a switch here, we could just add
474 the SWI and undefined instruction checks into this
475 switch to same on a couple of conditionals: */
476 switch ((tinstr & 0x0F00) >> 8)
503 doit = (CFLAG && !ZFLAG);
506 doit = (!CFLAG || ZFLAG);
509 doit = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
512 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
515 doit = ((!NFLAG && !VFLAG && !ZFLAG)
516 || (NFLAG && VFLAG && !ZFLAG));
519 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
524 state->Reg[15] = (pc + 4
525 + (((tinstr & 0x7F) << 1)
526 | ((tinstr & (1 << 7)) ? 0xFFFFFF00 : 0)));
532 /* UNDEFINED : cc=1110(AL) uses different format. */
533 handle_v6_thumb_insn (state, tinstr, & valid);
537 state->Reg[15] = (pc + 4
538 + (((tinstr & 0x3FF) << 1)
539 | ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0)));
543 case 29: /* UNDEFINED */
548 handle_v6_thumb_insn (state, tinstr, & valid);
554 /* There is no single ARM instruction equivalent for this
555 instruction. Also, it should only ever be matched with the
556 fmt19 "BL/BLX instruction 1" instruction. However, we do
557 allow the simulation of it on its own, with undefined results
558 if r14 is not suitably initialised. */
560 ARMword tmp = (pc + 2);
562 state->Reg[15] = ((state->Reg[14] + ((tinstr & 0x07FF) << 1))
565 state->Reg[14] = (tmp | 1);
569 fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
574 handle_v6_thumb_insn (state, tinstr, & valid);
577 case 30: /* BL instruction 1 */
579 /* There is no single ARM instruction equivalent for this Thumb
580 instruction. To keep the simulation simple (from the user
581 perspective) we check if the following instruction is the
582 second half of this BL, and if it is we simulate it
584 state->Reg[14] = state->Reg[15] \
585 + (((tinstr & 0x07FF) << 12) \
586 | ((tinstr & (1 << 10)) ? 0xFF800000 : 0));
588 valid = t_branch; /* in-case we don't have the 2nd half */
589 tinstr = next_instr; /* move the instruction down */
590 pc += 2; /* point the pc at the 2nd half */
591 if (((tinstr & 0xF800) >> 11) != 31)
593 if (((tinstr & 0xF800) >> 11) == 29)
595 ARMword tmp = (pc + 2);
597 state->Reg[15] = ((state->Reg[14]
598 + ((tinstr & 0x07FE) << 1))
601 state->Reg[14] = (tmp | 1);
606 /* Exit, since not correct instruction. */
610 /* else we fall through to process the second half of the BL */
611 pc += 2; /* point the pc at the 2nd half */
612 case 31: /* BL instruction 2 */
614 /* There is no single ARM instruction equivalent for this
615 instruction. Also, it should only ever be matched with the
616 fmt19 "BL instruction 1" instruction. However, we do allow
617 the simulation of it on its own, with undefined results if
618 r14 is not suitably initialised. */
622 state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
623 state->Reg[14] = (tmp | 1);
630 if (trace && valid != t_decoded)
631 fprintf (stderr, "\n");