Copyright year update in most files of the GDB Project.
[deliverable/binutils-gdb.git] / sim / arm / thumbemu.c
CommitLineData
c906108c
SS
1/* thumbemu.c -- Thumb instruction emulation.
2 Copyright (C) 1996, Cygnus Software Technologies Ltd.
3
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.
8
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.
13
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
380d9419 16 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
c906108c
SS
17
18/* We can provide simple Thumb simulation by decoding the Thumb
19instruction into its corresponding ARM instruction, and using the
20existing ARM simulator. */
21
dfcd3bfb 22#ifndef MODET /* required for the Thumb instruction support */
c906108c
SS
23#if 1
24#error "MODET needs to be defined for the Thumb world to work"
25#else
26#define MODET (1)
27#endif
28#endif
29
30#include "armdefs.h"
31#include "armemu.h"
7a292a7a 32#include "armos.h"
c906108c 33
546aee7a
NC
34/* Attempt to emulate an ARMv6 instruction.
35 Stores t_branch into PVALUE upon success or t_undefined otherwise. */
36
37static void
38handle_v6_thumb_insn (ARMul_State * state,
39 ARMword tinstr,
40 tdstate * pvalid)
41{
42 ARMword Rd;
43 ARMword Rm;
44
45 if (! state->is_v6)
46 {
47 * pvalid = t_undefined;
48 return;
49 }
50
51 switch (tinstr & 0xFFC0)
52 {
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 */
60 default:
61 printf ("Unhandled v6 thumb insn: %04x\n", tinstr);
62 * pvalid = t_undefined;
63 return;
64
65 case 0xb200: /* sxth */
66 Rm = state->Reg [(tinstr & 0x38) >> 3];
67 if (Rm & 0x8000)
68 state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000;
69 else
70 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
71 break;
72 case 0xb240: /* sxtb */
73 Rm = state->Reg [(tinstr & 0x38) >> 3];
74 if (Rm & 0x80)
75 state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00;
76 else
77 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
78 break;
79 case 0xb280: /* uxth */
80 Rm = state->Reg [(tinstr & 0x38) >> 3];
81 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
82 break;
83 case 0xb2c0: /* uxtb */
84 Rm = state->Reg [(tinstr & 0x38) >> 3];
85 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
86 break;
87 }
88 /* Indicate that the instruction has been processed. */
89 * pvalid = t_branch;
90}
91
c906108c
SS
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. */
96
546aee7a
NC
97tdstate
98ARMul_ThumbDecode (ARMul_State * state,
99 ARMword pc,
100 ARMword tinstr,
101 ARMword * ainstr)
c906108c 102{
dfcd3bfb 103 tdstate valid = t_decoded; /* default assumes a valid instruction */
c906108c 104 ARMword next_instr;
dfcd3bfb 105
c906108c
SS
106 if (state->bigendSig)
107 {
108 next_instr = tinstr & 0xFFFF;
109 tinstr >>= 16;
110 }
111 else
112 {
113 next_instr = tinstr >> 16;
114 tinstr &= 0xFFFF;
115 }
dfcd3bfb
JM
116
117#if 1 /* debugging to catch non updates */
c906108c
SS
118 *ainstr = 0xDEADC0DE;
119#endif
120
121 switch ((tinstr & 0xF800) >> 11)
122 {
dfcd3bfb
JM
123 case 0: /* LSL */
124 case 1: /* LSR */
125 case 2: /* ASR */
c906108c 126 /* Format 1 */
dfcd3bfb
JM
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 */
c906108c 132 break;
dfcd3bfb 133 case 3: /* ADD/SUB */
c906108c
SS
134 /* Format 2 */
135 {
dfcd3bfb
JM
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 */
141 };
142 /* It is quicker indexing into a table, than performing switch
143 or conditionals: */
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 */
c906108c
SS
148 }
149 break;
dfcd3bfb
JM
150 case 4: /* MOV */
151 case 5: /* CMP */
152 case 6: /* ADD */
153 case 7: /* SUB */
c906108c
SS
154 /* Format 3 */
155 {
dfcd3bfb
JM
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 */
161 };
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 */
c906108c 166 }
dfcd3bfb
JM
167 break;
168 case 8: /* Arithmetic and high register transfers */
c906108c
SS
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
172 subset. */
173 if ((tinstr & (1 << 10)) == 0)
dfcd3bfb
JM
174 {
175 /* Format 4 */
176 struct
177 {
178 ARMword opcode;
179 enum
180 { t_norm, t_shift, t_neg, t_mul }
181 otype;
182 }
183 subset[16] =
184 {
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 */
201 };
202 *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
203 switch (subset[(tinstr & 0x03C0) >> 6].otype)
204 {
205 case t_norm:
206 *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
207 | ((tinstr & 0x0007) << 12) /* Rd */
208 | ((tinstr & 0x0038) >> 3); /* Rs */
209 break;
210 case t_shift:
211 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
212 | ((tinstr & 0x0007) >> 0) /* Rm */
213 | ((tinstr & 0x0038) << (8 - 3)); /* Rs */
214 break;
215 case t_neg:
216 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
217 | ((tinstr & 0x0038) << (16 - 3)); /* Rn */
218 break;
219 case t_mul:
220 *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
221 | ((tinstr & 0x0007) << 8) /* Rs */
222 | ((tinstr & 0x0038) >> 3); /* Rm */
223 break;
224 }
225 }
c906108c 226 else
dfcd3bfb
JM
227 {
228 /* Format 5 */
229 ARMword Rd = ((tinstr & 0x0007) >> 0);
230 ARMword Rs = ((tinstr & 0x0038) >> 3);
231 if (tinstr & (1 << 7))
232 Rd += 8;
233 if (tinstr & (1 << 6))
234 Rs += 8;
235 switch ((tinstr & 0x03C0) >> 6)
236 {
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 */
244 break;
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 */
252 break;
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 */
260 break;
261 case 0xC: /* BX Rs */
262 case 0xD: /* BX Hs */
263 *ainstr = 0xE12FFF10 /* base */
264 | ((tinstr & 0x0078) >> 3); /* Rd */
265 break;
f1129fb8
NC
266 case 0xE: /* UNDEFINED */
267 case 0xF: /* UNDEFINED */
268 if (state->is_v5)
269 {
270 /* BLX Rs; BLX Hs */
271 *ainstr = 0xE12FFF30 /* base */
272 | ((tinstr & 0x0078) >> 3); /* Rd */
273 break;
274 }
275 /* Drop through. */
dfcd3bfb
JM
276 case 0x0: /* UNDEFINED */
277 case 0x4: /* UNDEFINED */
278 case 0x8: /* UNDEFINED */
546aee7a 279 handle_v6_thumb_insn (state, tinstr, & valid);
dfcd3bfb
JM
280 break;
281 }
282 }
c906108c 283 break;
dfcd3bfb 284 case 9: /* LDR Rd,[PC,#imm8] */
c906108c 285 /* Format 6 */
dfcd3bfb
JM
286 *ainstr = 0xE59F0000 /* base */
287 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
288 | ((tinstr & 0x00FF) << (2 - 0)); /* off8 */
c906108c
SS
289 break;
290 case 10:
291 case 11:
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)
dfcd3bfb
JM
296 {
297 /* Format 7 */
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] */
303 };
304 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
305 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
306 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
307 | ((tinstr & 0x01C0) >> 6); /* Ro */
308 }
c906108c 309 else
dfcd3bfb
JM
310 {
311 /* Format 8 */
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] */
317 };
318 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
319 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
320 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
321 | ((tinstr & 0x01C0) >> 6); /* Ro */
322 }
c906108c 323 break;
dfcd3bfb
JM
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] */
c906108c
SS
328 /* Format 9 */
329 {
dfcd3bfb
JM
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] */
335 };
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 */
c906108c
SS
342 }
343 break;
dfcd3bfb
JM
344 case 16: /* STRH Rd,[Rb,#imm5] */
345 case 17: /* LDRH Rd,[Rb,#imm5] */
c906108c 346 /* Format 10 */
dfcd3bfb
JM
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 */
c906108c 354 break;
dfcd3bfb
JM
355 case 18: /* STR Rd,[SP,#imm8] */
356 case 19: /* LDR Rd,[SP,#imm8] */
c906108c 357 /* Format 11 */
dfcd3bfb
JM
358 *ainstr = ((tinstr & (1 << 11)) /* base */
359 ? 0xE59D0000 /* LDR */
360 : 0xE58D0000) /* STR */
361 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
362 | ((tinstr & 0x00FF) << 2); /* off8 */
c906108c 363 break;
dfcd3bfb
JM
364 case 20: /* ADD Rd,PC,#imm8 */
365 case 21: /* ADD Rd,SP,#imm8 */
c906108c
SS
366 /* Format 12 */
367 if ((tinstr & (1 << 11)) == 0)
dfcd3bfb
JM
368 {
369 /* NOTE: The PC value used here should by word aligned */
c906108c
SS
370 /* We encode shift-left-by-2 in the rotate immediate field,
371 so no shift of off8 is needed. */
dfcd3bfb
JM
372 *ainstr = 0xE28F0F00 /* base */
373 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
374 | (tinstr & 0x00FF); /* off8 */
375 }
c906108c 376 else
dfcd3bfb 377 {
c906108c
SS
378 /* We encode shift-left-by-2 in the rotate immediate field,
379 so no shift of off8 is needed. */
dfcd3bfb
JM
380 *ainstr = 0xE28D0F00 /* base */
381 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
382 | (tinstr & 0x00FF); /* off8 */
383 }
c906108c
SS
384 break;
385 case 22:
386 case 23:
f1129fb8 387 switch (tinstr & 0x0F00)
dfcd3bfb 388 {
f1129fb8 389 case 0x0000:
dfcd3bfb
JM
390 /* Format 13 */
391 /* NOTE: The instruction contains a shift left of 2
f1129fb8 392 equivalent (implemented as ROR #30): */
dfcd3bfb
JM
393 *ainstr = ((tinstr & (1 << 7)) /* base */
394 ? 0xE24DDF00 /* SUB */
395 : 0xE28DDF00) /* ADD */
396 | (tinstr & 0x007F); /* off7 */
f1129fb8
NC
397 break;
398 case 0x0400:
399 /* Format 14 - Push */
400 * ainstr = 0xE92D0000 | (tinstr & 0x00FF);
401 break;
402 case 0x0500:
403 /* Format 14 - Push + LR */
404 * ainstr = 0xE92D4000 | (tinstr & 0x00FF);
405 break;
406 case 0x0c00:
407 /* Format 14 - Pop */
408 * ainstr = 0xE8BD0000 | (tinstr & 0x00FF);
409 break;
410 case 0x0d00:
411 /* Format 14 - Pop + PC */
412 * ainstr = 0xE8BD8000 | (tinstr & 0x00FF);
413 break;
414 case 0x0e00:
415 if (state->is_v5)
416 {
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
420 instruction. */
421 * ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
422 break;
423 }
424 /* Drop through. */
425 default:
426 /* Everything else is an undefined instruction. */
546aee7a 427 handle_v6_thumb_insn (state, tinstr, & valid);
f1129fb8 428 break;
dfcd3bfb 429 }
c906108c 430 break;
dfcd3bfb
JM
431 case 24: /* STMIA */
432 case 25: /* LDMIA */
c906108c 433 /* Format 15 */
dfcd3bfb
JM
434 *ainstr = ((tinstr & (1 << 11)) /* base */
435 ? 0xE8B00000 /* LDMIA */
436 : 0xE8A00000) /* STMIA */
437 | ((tinstr & 0x0700) << (16 - 8)) /* Rb */
438 | (tinstr & 0x00FF); /* mask8 */
c906108c 439 break;
dfcd3bfb
JM
440 case 26: /* Bcc */
441 case 27: /* Bcc/SWI */
c906108c 442 if ((tinstr & 0x0F00) == 0x0F00)
dfcd3bfb
JM
443 {
444 /* Format 17 : SWI */
445 *ainstr = 0xEF000000;
c906108c
SS
446 /* Breakpoint must be handled specially. */
447 if ((tinstr & 0x00FF) == 0x18)
448 *ainstr |= ((tinstr & 0x00FF) << 16);
7a292a7a
SS
449 /* New breakpoint value. See gdb/arm-tdep.c */
450 else if ((tinstr & 0x00FF) == 0xFE)
dfcd3bfb 451 *ainstr |= SWI_Breakpoint;
c906108c
SS
452 else
453 *ainstr |= (tinstr & 0x00FF);
dfcd3bfb 454 }
c906108c 455 else if ((tinstr & 0x0F00) != 0x0E00)
dfcd3bfb
JM
456 {
457 /* Format 16 */
458 int doit = FALSE;
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)
463 {
464 case EQ:
465 doit = ZFLAG;
466 break;
467 case NE:
468 doit = !ZFLAG;
469 break;
470 case VS:
471 doit = VFLAG;
472 break;
473 case VC:
474 doit = !VFLAG;
475 break;
476 case MI:
477 doit = NFLAG;
478 break;
479 case PL:
480 doit = !NFLAG;
481 break;
482 case CS:
483 doit = CFLAG;
484 break;
485 case CC:
486 doit = !CFLAG;
487 break;
488 case HI:
489 doit = (CFLAG && !ZFLAG);
490 break;
491 case LS:
492 doit = (!CFLAG || ZFLAG);
493 break;
494 case GE:
495 doit = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
496 break;
497 case LT:
498 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
499 break;
500 case GT:
501 doit = ((!NFLAG && !VFLAG && !ZFLAG)
502 || (NFLAG && VFLAG && !ZFLAG));
503 break;
504 case LE:
505 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
506 break;
507 }
508 if (doit)
509 {
510 state->Reg[15] = (pc + 4
511 + (((tinstr & 0x7F) << 1)
512 | ((tinstr & (1 << 7)) ? 0xFFFFFF00 : 0)));
513 FLUSHPIPE;
514 }
515 valid = t_branch;
516 }
546aee7a
NC
517 else
518 /* UNDEFINED : cc=1110(AL) uses different format. */
519 handle_v6_thumb_insn (state, tinstr, & valid);
c906108c 520 break;
dfcd3bfb 521 case 28: /* B */
c906108c 522 /* Format 18 */
dfcd3bfb
JM
523 state->Reg[15] = (pc + 4
524 + (((tinstr & 0x3FF) << 1)
525 | ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0)));
c906108c
SS
526 FLUSHPIPE;
527 valid = t_branch;
528 break;
dfcd3bfb 529 case 29: /* UNDEFINED */
f1129fb8
NC
530 if (state->is_v5)
531 {
532 if (tinstr & 1)
533 {
546aee7a 534 handle_v6_thumb_insn (state, tinstr, & valid);
f1129fb8
NC
535 break;
536 }
537 /* Drop through. */
538
f1129fb8
NC
539 /* Format 19 */
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. */
545 {
546 ARMword tmp = (pc + 2);
7378e198 547
f1129fb8
NC
548 state->Reg[15] = ((state->Reg[14] + ((tinstr & 0x07FF) << 1))
549 & 0xFFFFFFFC);
550 CLEART;
551 state->Reg[14] = (tmp | 1);
552 valid = t_branch;
553 FLUSHPIPE;
554 break;
555 }
556 }
546aee7a
NC
557
558 handle_v6_thumb_insn (state, tinstr, & valid);
c906108c 559 break;
546aee7a 560
dfcd3bfb 561 case 30: /* BL instruction 1 */
c906108c
SS
562 /* Format 19 */
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
dfcd3bfb 567 immediately. */
c906108c 568 state->Reg[14] = state->Reg[15] \
7378e198
NC
569 + (((tinstr & 0x07FF) << 12) \
570 | ((tinstr & (1 << 10)) ? 0xFF800000 : 0));
571
dfcd3bfb
JM
572 valid = t_branch; /* in-case we don't have the 2nd half */
573 tinstr = next_instr; /* move the instruction down */
4f3c3dbb 574 pc += 2; /* point the pc at the 2nd half */
c906108c 575 if (((tinstr & 0xF800) >> 11) != 31)
f1129fb8
NC
576 {
577 if (((tinstr & 0xF800) >> 11) == 29)
578 {
4f3c3dbb
NC
579 ARMword tmp = (pc + 2);
580
4f3c3dbb 581 state->Reg[15] = ((state->Reg[14]
2984e114 582 + ((tinstr & 0x07FE) << 1))
4f3c3dbb
NC
583 & 0xFFFFFFFC);
584 CLEART;
585 state->Reg[14] = (tmp | 1);
586 valid = t_branch;
587 FLUSHPIPE;
f1129fb8 588 }
4f3c3dbb
NC
589 else
590 /* Exit, since not correct instruction. */
591 pc -= 2;
592 break;
f1129fb8 593 }
c906108c 594 /* else we fall through to process the second half of the BL */
2984e114 595 pc += 2; /* point the pc at the 2nd half */
dfcd3bfb 596 case 31: /* BL instruction 2 */
c906108c
SS
597 /* Format 19 */
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
dfcd3bfb 602 r14 is not suitably initialised. */
c906108c 603 {
7378e198
NC
604 ARMword tmp = pc;
605
dfcd3bfb
JM
606 state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
607 state->Reg[14] = (tmp | 1);
608 valid = t_branch;
609 FLUSHPIPE;
c906108c
SS
610 }
611 break;
612 }
613
614 return valid;
615}
This page took 0.545275 seconds and 4 git commands to generate.