Prevent writes to R15 via LDR or LDM from changing the ARM/Thumb state in pre-v5...
[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
3fd725ef 6 the Free Software Foundation; either version 3 of the License, or
c906108c
SS
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
51b318de 15 along with this program; if not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
16
17/* We can provide simple Thumb simulation by decoding the Thumb
18instruction into its corresponding ARM instruction, and using the
19existing ARM simulator. */
20
dfcd3bfb 21#ifndef MODET /* required for the Thumb instruction support */
c906108c
SS
22#if 1
23#error "MODET needs to be defined for the Thumb world to work"
24#else
25#define MODET (1)
26#endif
27#endif
28
29#include "armdefs.h"
30#include "armemu.h"
7a292a7a 31#include "armos.h"
c906108c 32
546aee7a
NC
33/* Attempt to emulate an ARMv6 instruction.
34 Stores t_branch into PVALUE upon success or t_undefined otherwise. */
35
36static void
37handle_v6_thumb_insn (ARMul_State * state,
38 ARMword tinstr,
39 tdstate * pvalid)
40{
41 ARMword Rd;
42 ARMword Rm;
43
44 if (! state->is_v6)
45 {
46 * pvalid = t_undefined;
47 return;
48 }
49
50 switch (tinstr & 0xFFC0)
51 {
52 case 0xb660: /* cpsie */
53 case 0xb670: /* cpsid */
54 case 0x4600: /* cpy */
55 case 0xba00: /* rev */
56 case 0xba40: /* rev16 */
57 case 0xbac0: /* revsh */
58 case 0xb650: /* setend */
59 default:
60 printf ("Unhandled v6 thumb insn: %04x\n", tinstr);
61 * pvalid = t_undefined;
62 return;
63
64 case 0xb200: /* sxth */
65 Rm = state->Reg [(tinstr & 0x38) >> 3];
66 if (Rm & 0x8000)
67 state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000;
68 else
69 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
70 break;
71 case 0xb240: /* sxtb */
72 Rm = state->Reg [(tinstr & 0x38) >> 3];
73 if (Rm & 0x80)
74 state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00;
75 else
76 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
77 break;
78 case 0xb280: /* uxth */
79 Rm = state->Reg [(tinstr & 0x38) >> 3];
80 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
81 break;
82 case 0xb2c0: /* uxtb */
83 Rm = state->Reg [(tinstr & 0x38) >> 3];
84 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
85 break;
86 }
87 /* Indicate that the instruction has been processed. */
88 * pvalid = t_branch;
89}
90
c906108c
SS
91/* Decode a 16bit Thumb instruction. The instruction is in the low
92 16-bits of the tinstr field, with the following Thumb instruction
93 held in the high 16-bits. Passing in two Thumb instructions allows
94 easier simulation of the special dual BL instruction. */
95
546aee7a
NC
96tdstate
97ARMul_ThumbDecode (ARMul_State * state,
98 ARMword pc,
99 ARMword tinstr,
100 ARMword * ainstr)
c906108c 101{
dfcd3bfb 102 tdstate valid = t_decoded; /* default assumes a valid instruction */
c906108c 103 ARMword next_instr;
dfcd3bfb 104
c906108c
SS
105 if (state->bigendSig)
106 {
107 next_instr = tinstr & 0xFFFF;
108 tinstr >>= 16;
109 }
110 else
111 {
112 next_instr = tinstr >> 16;
113 tinstr &= 0xFFFF;
114 }
dfcd3bfb
JM
115
116#if 1 /* debugging to catch non updates */
c906108c
SS
117 *ainstr = 0xDEADC0DE;
118#endif
119
120 switch ((tinstr & 0xF800) >> 11)
121 {
dfcd3bfb
JM
122 case 0: /* LSL */
123 case 1: /* LSR */
124 case 2: /* ASR */
c906108c 125 /* Format 1 */
dfcd3bfb
JM
126 *ainstr = 0xE1B00000 /* base opcode */
127 | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */
128 | ((tinstr & 0x07C0) << (7 - 6)) /* imm5 */
129 | ((tinstr & 0x0038) >> 3) /* Rs */
130 | ((tinstr & 0x0007) << 12); /* Rd */
c906108c 131 break;
dfcd3bfb 132 case 3: /* ADD/SUB */
c906108c
SS
133 /* Format 2 */
134 {
dfcd3bfb
JM
135 ARMword subset[4] = {
136 0xE0900000, /* ADDS Rd,Rs,Rn */
137 0xE0500000, /* SUBS Rd,Rs,Rn */
138 0xE2900000, /* ADDS Rd,Rs,#imm3 */
139 0xE2500000 /* SUBS Rd,Rs,#imm3 */
140 };
141 /* It is quicker indexing into a table, than performing switch
142 or conditionals: */
143 *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */
144 | ((tinstr & 0x01C0) >> 6) /* Rn or imm3 */
145 | ((tinstr & 0x0038) << (16 - 3)) /* Rs */
146 | ((tinstr & 0x0007) << (12 - 0)); /* Rd */
c906108c
SS
147 }
148 break;
dfcd3bfb
JM
149 case 4: /* MOV */
150 case 5: /* CMP */
151 case 6: /* ADD */
152 case 7: /* SUB */
c906108c
SS
153 /* Format 3 */
154 {
dfcd3bfb
JM
155 ARMword subset[4] = {
156 0xE3B00000, /* MOVS Rd,#imm8 */
157 0xE3500000, /* CMP Rd,#imm8 */
158 0xE2900000, /* ADDS Rd,Rd,#imm8 */
159 0xE2500000, /* SUBS Rd,Rd,#imm8 */
160 };
161 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */
162 | ((tinstr & 0x00FF) >> 0) /* imm8 */
163 | ((tinstr & 0x0700) << (16 - 8)) /* Rn */
164 | ((tinstr & 0x0700) << (12 - 8)); /* Rd */
c906108c 165 }
dfcd3bfb
JM
166 break;
167 case 8: /* Arithmetic and high register transfers */
c906108c
SS
168 /* TODO: Since the subsets for both Format 4 and Format 5
169 instructions are made up of different ARM encodings, we could
170 save the following conditional, and just have one large
171 subset. */
172 if ((tinstr & (1 << 10)) == 0)
dfcd3bfb
JM
173 {
174 /* Format 4 */
175 struct
176 {
177 ARMword opcode;
178 enum
179 { t_norm, t_shift, t_neg, t_mul }
180 otype;
181 }
182 subset[16] =
183 {
184 { 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */
185 { 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */
186 { 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */
187 { 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */
188 { 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */
189 { 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */
190 { 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */
191 { 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */
192 { 0xE1100000, t_norm}, /* TST Rd,Rs */
193 { 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */
194 { 0xE1500000, t_norm}, /* CMP Rd,Rs */
195 { 0xE1700000, t_norm}, /* CMN Rd,Rs */
196 { 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */
197 { 0xE0100090, t_mul} , /* MULS Rd,Rd,Rs */
198 { 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */
199 { 0xE1F00000, t_norm} /* MVNS Rd,Rs */
200 };
201 *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
202 switch (subset[(tinstr & 0x03C0) >> 6].otype)
203 {
204 case t_norm:
205 *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
206 | ((tinstr & 0x0007) << 12) /* Rd */
207 | ((tinstr & 0x0038) >> 3); /* Rs */
208 break;
209 case t_shift:
210 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
211 | ((tinstr & 0x0007) >> 0) /* Rm */
212 | ((tinstr & 0x0038) << (8 - 3)); /* Rs */
213 break;
214 case t_neg:
215 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
216 | ((tinstr & 0x0038) << (16 - 3)); /* Rn */
217 break;
218 case t_mul:
219 *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
220 | ((tinstr & 0x0007) << 8) /* Rs */
221 | ((tinstr & 0x0038) >> 3); /* Rm */
222 break;
223 }
224 }
c906108c 225 else
dfcd3bfb
JM
226 {
227 /* Format 5 */
228 ARMword Rd = ((tinstr & 0x0007) >> 0);
229 ARMword Rs = ((tinstr & 0x0038) >> 3);
230 if (tinstr & (1 << 7))
231 Rd += 8;
232 if (tinstr & (1 << 6))
233 Rs += 8;
234 switch ((tinstr & 0x03C0) >> 6)
235 {
236 case 0x1: /* ADD Rd,Rd,Hs */
237 case 0x2: /* ADD Hd,Hd,Rs */
238 case 0x3: /* ADD Hd,Hd,Hs */
239 *ainstr = 0xE0800000 /* base */
240 | (Rd << 16) /* Rn */
241 | (Rd << 12) /* Rd */
242 | (Rs << 0); /* Rm */
243 break;
244 case 0x5: /* CMP Rd,Hs */
245 case 0x6: /* CMP Hd,Rs */
246 case 0x7: /* CMP Hd,Hs */
247 *ainstr = 0xE1500000 /* base */
248 | (Rd << 16) /* Rn */
249 | (Rd << 12) /* Rd */
250 | (Rs << 0); /* Rm */
251 break;
252 case 0x9: /* MOV Rd,Hs */
253 case 0xA: /* MOV Hd,Rs */
254 case 0xB: /* MOV Hd,Hs */
255 *ainstr = 0xE1A00000 /* base */
256 | (Rd << 16) /* Rn */
257 | (Rd << 12) /* Rd */
258 | (Rs << 0); /* Rm */
259 break;
260 case 0xC: /* BX Rs */
261 case 0xD: /* BX Hs */
262 *ainstr = 0xE12FFF10 /* base */
263 | ((tinstr & 0x0078) >> 3); /* Rd */
264 break;
f1129fb8
NC
265 case 0xE: /* UNDEFINED */
266 case 0xF: /* UNDEFINED */
267 if (state->is_v5)
268 {
269 /* BLX Rs; BLX Hs */
270 *ainstr = 0xE12FFF30 /* base */
271 | ((tinstr & 0x0078) >> 3); /* Rd */
272 break;
273 }
274 /* Drop through. */
dfcd3bfb
JM
275 case 0x0: /* UNDEFINED */
276 case 0x4: /* UNDEFINED */
277 case 0x8: /* UNDEFINED */
546aee7a 278 handle_v6_thumb_insn (state, tinstr, & valid);
dfcd3bfb
JM
279 break;
280 }
281 }
c906108c 282 break;
dfcd3bfb 283 case 9: /* LDR Rd,[PC,#imm8] */
c906108c 284 /* Format 6 */
dfcd3bfb
JM
285 *ainstr = 0xE59F0000 /* base */
286 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
287 | ((tinstr & 0x00FF) << (2 - 0)); /* off8 */
c906108c
SS
288 break;
289 case 10:
290 case 11:
291 /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
292 the following could be merged into a single subset, saving on
293 the following boolean: */
294 if ((tinstr & (1 << 9)) == 0)
dfcd3bfb
JM
295 {
296 /* Format 7 */
297 ARMword subset[4] = {
298 0xE7800000, /* STR Rd,[Rb,Ro] */
299 0xE7C00000, /* STRB Rd,[Rb,Ro] */
300 0xE7900000, /* LDR Rd,[Rb,Ro] */
301 0xE7D00000 /* LDRB Rd,[Rb,Ro] */
302 };
303 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
304 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
305 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
306 | ((tinstr & 0x01C0) >> 6); /* Ro */
307 }
c906108c 308 else
dfcd3bfb
JM
309 {
310 /* Format 8 */
311 ARMword subset[4] = {
312 0xE18000B0, /* STRH Rd,[Rb,Ro] */
313 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */
314 0xE19000B0, /* LDRH Rd,[Rb,Ro] */
315 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */
316 };
317 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
318 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
319 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
320 | ((tinstr & 0x01C0) >> 6); /* Ro */
321 }
c906108c 322 break;
dfcd3bfb
JM
323 case 12: /* STR Rd,[Rb,#imm5] */
324 case 13: /* LDR Rd,[Rb,#imm5] */
325 case 14: /* STRB Rd,[Rb,#imm5] */
326 case 15: /* LDRB Rd,[Rb,#imm5] */
c906108c
SS
327 /* Format 9 */
328 {
dfcd3bfb
JM
329 ARMword subset[4] = {
330 0xE5800000, /* STR Rd,[Rb,#imm5] */
331 0xE5900000, /* LDR Rd,[Rb,#imm5] */
332 0xE5C00000, /* STRB Rd,[Rb,#imm5] */
333 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
334 };
335 /* The offset range defends on whether we are transferring a
336 byte or word value: */
337 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */
338 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
339 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
340 | ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */
c906108c
SS
341 }
342 break;
dfcd3bfb
JM
343 case 16: /* STRH Rd,[Rb,#imm5] */
344 case 17: /* LDRH Rd,[Rb,#imm5] */
c906108c 345 /* Format 10 */
dfcd3bfb
JM
346 *ainstr = ((tinstr & (1 << 11)) /* base */
347 ? 0xE1D000B0 /* LDRH */
348 : 0xE1C000B0) /* STRH */
349 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
350 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
351 | ((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */
352 | ((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */
c906108c 353 break;
dfcd3bfb
JM
354 case 18: /* STR Rd,[SP,#imm8] */
355 case 19: /* LDR Rd,[SP,#imm8] */
c906108c 356 /* Format 11 */
dfcd3bfb
JM
357 *ainstr = ((tinstr & (1 << 11)) /* base */
358 ? 0xE59D0000 /* LDR */
359 : 0xE58D0000) /* STR */
360 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
361 | ((tinstr & 0x00FF) << 2); /* off8 */
c906108c 362 break;
dfcd3bfb
JM
363 case 20: /* ADD Rd,PC,#imm8 */
364 case 21: /* ADD Rd,SP,#imm8 */
c906108c
SS
365 /* Format 12 */
366 if ((tinstr & (1 << 11)) == 0)
dfcd3bfb
JM
367 {
368 /* NOTE: The PC value used here should by word aligned */
c906108c
SS
369 /* We encode shift-left-by-2 in the rotate immediate field,
370 so no shift of off8 is needed. */
dfcd3bfb
JM
371 *ainstr = 0xE28F0F00 /* base */
372 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
373 | (tinstr & 0x00FF); /* off8 */
374 }
c906108c 375 else
dfcd3bfb 376 {
c906108c
SS
377 /* We encode shift-left-by-2 in the rotate immediate field,
378 so no shift of off8 is needed. */
dfcd3bfb
JM
379 *ainstr = 0xE28D0F00 /* base */
380 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
381 | (tinstr & 0x00FF); /* off8 */
382 }
c906108c
SS
383 break;
384 case 22:
385 case 23:
f1129fb8 386 switch (tinstr & 0x0F00)
dfcd3bfb 387 {
f1129fb8 388 case 0x0000:
dfcd3bfb
JM
389 /* Format 13 */
390 /* NOTE: The instruction contains a shift left of 2
f1129fb8 391 equivalent (implemented as ROR #30): */
dfcd3bfb
JM
392 *ainstr = ((tinstr & (1 << 7)) /* base */
393 ? 0xE24DDF00 /* SUB */
394 : 0xE28DDF00) /* ADD */
395 | (tinstr & 0x007F); /* off7 */
f1129fb8
NC
396 break;
397 case 0x0400:
398 /* Format 14 - Push */
399 * ainstr = 0xE92D0000 | (tinstr & 0x00FF);
400 break;
401 case 0x0500:
402 /* Format 14 - Push + LR */
403 * ainstr = 0xE92D4000 | (tinstr & 0x00FF);
404 break;
405 case 0x0c00:
406 /* Format 14 - Pop */
407 * ainstr = 0xE8BD0000 | (tinstr & 0x00FF);
408 break;
409 case 0x0d00:
410 /* Format 14 - Pop + PC */
411 * ainstr = 0xE8BD8000 | (tinstr & 0x00FF);
412 break;
413 case 0x0e00:
414 if (state->is_v5)
415 {
416 /* This is normally an undefined instruction. The v5t architecture
417 defines this particular pattern as a BKPT instruction, for
418 hardware assisted debugging. We map onto the arm BKPT
419 instruction. */
420 * ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
421 break;
422 }
423 /* Drop through. */
424 default:
425 /* Everything else is an undefined instruction. */
546aee7a 426 handle_v6_thumb_insn (state, tinstr, & valid);
f1129fb8 427 break;
dfcd3bfb 428 }
c906108c 429 break;
dfcd3bfb
JM
430 case 24: /* STMIA */
431 case 25: /* LDMIA */
c906108c 432 /* Format 15 */
dfcd3bfb
JM
433 *ainstr = ((tinstr & (1 << 11)) /* base */
434 ? 0xE8B00000 /* LDMIA */
435 : 0xE8A00000) /* STMIA */
436 | ((tinstr & 0x0700) << (16 - 8)) /* Rb */
437 | (tinstr & 0x00FF); /* mask8 */
c906108c 438 break;
dfcd3bfb
JM
439 case 26: /* Bcc */
440 case 27: /* Bcc/SWI */
c906108c 441 if ((tinstr & 0x0F00) == 0x0F00)
dfcd3bfb
JM
442 {
443 /* Format 17 : SWI */
444 *ainstr = 0xEF000000;
c906108c
SS
445 /* Breakpoint must be handled specially. */
446 if ((tinstr & 0x00FF) == 0x18)
447 *ainstr |= ((tinstr & 0x00FF) << 16);
7a292a7a
SS
448 /* New breakpoint value. See gdb/arm-tdep.c */
449 else if ((tinstr & 0x00FF) == 0xFE)
dfcd3bfb 450 *ainstr |= SWI_Breakpoint;
c906108c
SS
451 else
452 *ainstr |= (tinstr & 0x00FF);
dfcd3bfb 453 }
c906108c 454 else if ((tinstr & 0x0F00) != 0x0E00)
dfcd3bfb
JM
455 {
456 /* Format 16 */
457 int doit = FALSE;
458 /* TODO: Since we are doing a switch here, we could just add
459 the SWI and undefined instruction checks into this
460 switch to same on a couple of conditionals: */
461 switch ((tinstr & 0x0F00) >> 8)
462 {
463 case EQ:
464 doit = ZFLAG;
465 break;
466 case NE:
467 doit = !ZFLAG;
468 break;
469 case VS:
470 doit = VFLAG;
471 break;
472 case VC:
473 doit = !VFLAG;
474 break;
475 case MI:
476 doit = NFLAG;
477 break;
478 case PL:
479 doit = !NFLAG;
480 break;
481 case CS:
482 doit = CFLAG;
483 break;
484 case CC:
485 doit = !CFLAG;
486 break;
487 case HI:
488 doit = (CFLAG && !ZFLAG);
489 break;
490 case LS:
491 doit = (!CFLAG || ZFLAG);
492 break;
493 case GE:
494 doit = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
495 break;
496 case LT:
497 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
498 break;
499 case GT:
500 doit = ((!NFLAG && !VFLAG && !ZFLAG)
501 || (NFLAG && VFLAG && !ZFLAG));
502 break;
503 case LE:
504 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
505 break;
506 }
507 if (doit)
508 {
509 state->Reg[15] = (pc + 4
510 + (((tinstr & 0x7F) << 1)
511 | ((tinstr & (1 << 7)) ? 0xFFFFFF00 : 0)));
512 FLUSHPIPE;
513 }
514 valid = t_branch;
515 }
546aee7a
NC
516 else
517 /* UNDEFINED : cc=1110(AL) uses different format. */
518 handle_v6_thumb_insn (state, tinstr, & valid);
c906108c 519 break;
dfcd3bfb 520 case 28: /* B */
c906108c 521 /* Format 18 */
dfcd3bfb
JM
522 state->Reg[15] = (pc + 4
523 + (((tinstr & 0x3FF) << 1)
524 | ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0)));
c906108c
SS
525 FLUSHPIPE;
526 valid = t_branch;
527 break;
dfcd3bfb 528 case 29: /* UNDEFINED */
f1129fb8
NC
529 if (state->is_v5)
530 {
531 if (tinstr & 1)
532 {
546aee7a 533 handle_v6_thumb_insn (state, tinstr, & valid);
f1129fb8
NC
534 break;
535 }
536 /* Drop through. */
537
f1129fb8
NC
538 /* Format 19 */
539 /* There is no single ARM instruction equivalent for this
540 instruction. Also, it should only ever be matched with the
541 fmt19 "BL/BLX instruction 1" instruction. However, we do
542 allow the simulation of it on its own, with undefined results
543 if r14 is not suitably initialised. */
544 {
545 ARMword tmp = (pc + 2);
7378e198 546
f1129fb8
NC
547 state->Reg[15] = ((state->Reg[14] + ((tinstr & 0x07FF) << 1))
548 & 0xFFFFFFFC);
549 CLEART;
550 state->Reg[14] = (tmp | 1);
551 valid = t_branch;
552 FLUSHPIPE;
553 break;
554 }
555 }
546aee7a
NC
556
557 handle_v6_thumb_insn (state, tinstr, & valid);
c906108c 558 break;
546aee7a 559
dfcd3bfb 560 case 30: /* BL instruction 1 */
c906108c
SS
561 /* Format 19 */
562 /* There is no single ARM instruction equivalent for this Thumb
563 instruction. To keep the simulation simple (from the user
564 perspective) we check if the following instruction is the
565 second half of this BL, and if it is we simulate it
dfcd3bfb 566 immediately. */
c906108c 567 state->Reg[14] = state->Reg[15] \
7378e198
NC
568 + (((tinstr & 0x07FF) << 12) \
569 | ((tinstr & (1 << 10)) ? 0xFF800000 : 0));
570
dfcd3bfb
JM
571 valid = t_branch; /* in-case we don't have the 2nd half */
572 tinstr = next_instr; /* move the instruction down */
4f3c3dbb 573 pc += 2; /* point the pc at the 2nd half */
c906108c 574 if (((tinstr & 0xF800) >> 11) != 31)
f1129fb8
NC
575 {
576 if (((tinstr & 0xF800) >> 11) == 29)
577 {
4f3c3dbb
NC
578 ARMword tmp = (pc + 2);
579
4f3c3dbb 580 state->Reg[15] = ((state->Reg[14]
2984e114 581 + ((tinstr & 0x07FE) << 1))
4f3c3dbb
NC
582 & 0xFFFFFFFC);
583 CLEART;
584 state->Reg[14] = (tmp | 1);
585 valid = t_branch;
586 FLUSHPIPE;
f1129fb8 587 }
4f3c3dbb
NC
588 else
589 /* Exit, since not correct instruction. */
590 pc -= 2;
591 break;
f1129fb8 592 }
c906108c 593 /* else we fall through to process the second half of the BL */
2984e114 594 pc += 2; /* point the pc at the 2nd half */
dfcd3bfb 595 case 31: /* BL instruction 2 */
c906108c
SS
596 /* Format 19 */
597 /* There is no single ARM instruction equivalent for this
598 instruction. Also, it should only ever be matched with the
599 fmt19 "BL instruction 1" instruction. However, we do allow
600 the simulation of it on its own, with undefined results if
dfcd3bfb 601 r14 is not suitably initialised. */
c906108c 602 {
7378e198
NC
603 ARMword tmp = pc;
604
dfcd3bfb
JM
605 state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
606 state->Reg[14] = (tmp | 1);
607 valid = t_branch;
608 FLUSHPIPE;
c906108c
SS
609 }
610 break;
611 }
612
613 return valid;
614}
This page took 0.65751 seconds and 4 git commands to generate.