Remove COMPRESS_DEBUG_ZLIB
[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 7 (at your option) any later version.
8d052926 8
c906108c
SS
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.
8d052926 13
c906108c 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{
546aee7a
NC
41 if (! state->is_v6)
42 {
43 * pvalid = t_undefined;
44 return;
45 }
46
47 switch (tinstr & 0xFFC0)
48 {
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 */
8d052926 56 default:
546aee7a
NC
57 printf ("Unhandled v6 thumb insn: %04x\n", tinstr);
58 * pvalid = t_undefined;
59 return;
60
61 case 0xb200: /* sxth */
8d052926
NC
62 {
63 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
64
65 if (Rm & 0x8000)
66 state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000;
67 else
68 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
69 break;
70 }
71
546aee7a 72 case 0xb240: /* sxtb */
8d052926
NC
73 {
74 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
75
76 if (Rm & 0x80)
77 state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00;
78 else
79 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
80 break;
81 }
82
546aee7a 83 case 0xb280: /* uxth */
8d052926
NC
84 {
85 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
86
87 state->Reg [(tinstr & 0x7)] = Rm & 0xffff;
88 break;
89 }
90
546aee7a 91 case 0xb2c0: /* uxtb */
8d052926
NC
92 {
93 ARMword Rm = state->Reg [(tinstr & 0x38) >> 3];
94
95 state->Reg [(tinstr & 0x7)] = Rm & 0xff;
96 break;
97 }
546aee7a
NC
98 }
99 /* Indicate that the instruction has been processed. */
100 * pvalid = t_branch;
101}
102
c906108c
SS
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. */
107
546aee7a
NC
108tdstate
109ARMul_ThumbDecode (ARMul_State * state,
110 ARMword pc,
111 ARMword tinstr,
112 ARMword * ainstr)
c906108c 113{
dfcd3bfb 114 tdstate valid = t_decoded; /* default assumes a valid instruction */
c906108c 115 ARMword next_instr;
dfcd3bfb 116
c906108c
SS
117 if (state->bigendSig)
118 {
119 next_instr = tinstr & 0xFFFF;
120 tinstr >>= 16;
121 }
122 else
123 {
124 next_instr = tinstr >> 16;
125 tinstr &= 0xFFFF;
126 }
dfcd3bfb 127
8d052926
NC
128 if (trace)
129 fprintf (stderr, "pc: %x, Thumb instr: %x", pc & ~1, tinstr);
130
dfcd3bfb 131#if 1 /* debugging to catch non updates */
c906108c
SS
132 *ainstr = 0xDEADC0DE;
133#endif
134
135 switch ((tinstr & 0xF800) >> 11)
136 {
dfcd3bfb
JM
137 case 0: /* LSL */
138 case 1: /* LSR */
139 case 2: /* ASR */
c906108c 140 /* Format 1 */
dfcd3bfb
JM
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 */
c906108c 146 break;
dfcd3bfb 147 case 3: /* ADD/SUB */
c906108c
SS
148 /* Format 2 */
149 {
dfcd3bfb
JM
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 */
155 };
156 /* It is quicker indexing into a table, than performing switch
157 or conditionals: */
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 */
c906108c
SS
162 }
163 break;
dfcd3bfb
JM
164 case 4: /* MOV */
165 case 5: /* CMP */
166 case 6: /* ADD */
167 case 7: /* SUB */
c906108c
SS
168 /* Format 3 */
169 {
dfcd3bfb
JM
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 */
175 };
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 */
c906108c 180 }
dfcd3bfb
JM
181 break;
182 case 8: /* Arithmetic and high register transfers */
c906108c
SS
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
186 subset. */
187 if ((tinstr & (1 << 10)) == 0)
dfcd3bfb
JM
188 {
189 /* Format 4 */
190 struct
191 {
192 ARMword opcode;
193 enum
194 { t_norm, t_shift, t_neg, t_mul }
195 otype;
196 }
197 subset[16] =
198 {
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 */
215 };
216 *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
217 switch (subset[(tinstr & 0x03C0) >> 6].otype)
218 {
219 case t_norm:
220 *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
221 | ((tinstr & 0x0007) << 12) /* Rd */
222 | ((tinstr & 0x0038) >> 3); /* Rs */
223 break;
224 case t_shift:
225 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
226 | ((tinstr & 0x0007) >> 0) /* Rm */
227 | ((tinstr & 0x0038) << (8 - 3)); /* Rs */
228 break;
229 case t_neg:
230 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
231 | ((tinstr & 0x0038) << (16 - 3)); /* Rn */
232 break;
233 case t_mul:
234 *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
235 | ((tinstr & 0x0007) << 8) /* Rs */
236 | ((tinstr & 0x0038) >> 3); /* Rm */
237 break;
238 }
239 }
c906108c 240 else
dfcd3bfb
JM
241 {
242 /* Format 5 */
243 ARMword Rd = ((tinstr & 0x0007) >> 0);
244 ARMword Rs = ((tinstr & 0x0038) >> 3);
245 if (tinstr & (1 << 7))
246 Rd += 8;
247 if (tinstr & (1 << 6))
248 Rs += 8;
249 switch ((tinstr & 0x03C0) >> 6)
250 {
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 */
258 break;
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 */
266 break;
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 */
274 break;
275 case 0xC: /* BX Rs */
276 case 0xD: /* BX Hs */
277 *ainstr = 0xE12FFF10 /* base */
278 | ((tinstr & 0x0078) >> 3); /* Rd */
279 break;
f1129fb8
NC
280 case 0xE: /* UNDEFINED */
281 case 0xF: /* UNDEFINED */
282 if (state->is_v5)
283 {
284 /* BLX Rs; BLX Hs */
285 *ainstr = 0xE12FFF30 /* base */
286 | ((tinstr & 0x0078) >> 3); /* Rd */
287 break;
288 }
289 /* Drop through. */
dfcd3bfb
JM
290 case 0x0: /* UNDEFINED */
291 case 0x4: /* UNDEFINED */
292 case 0x8: /* UNDEFINED */
546aee7a 293 handle_v6_thumb_insn (state, tinstr, & valid);
dfcd3bfb
JM
294 break;
295 }
296 }
c906108c 297 break;
dfcd3bfb 298 case 9: /* LDR Rd,[PC,#imm8] */
c906108c 299 /* Format 6 */
dfcd3bfb
JM
300 *ainstr = 0xE59F0000 /* base */
301 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
302 | ((tinstr & 0x00FF) << (2 - 0)); /* off8 */
c906108c
SS
303 break;
304 case 10:
305 case 11:
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)
dfcd3bfb
JM
310 {
311 /* Format 7 */
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] */
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 else
dfcd3bfb
JM
324 {
325 /* Format 8 */
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] */
331 };
332 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
333 | ((tinstr & 0x0007) << (12 - 0)) /* Rd */
334 | ((tinstr & 0x0038) << (16 - 3)) /* Rb */
335 | ((tinstr & 0x01C0) >> 6); /* Ro */
336 }
c906108c 337 break;
dfcd3bfb
JM
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] */
c906108c
SS
342 /* Format 9 */
343 {
dfcd3bfb
JM
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] */
349 };
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 */
c906108c
SS
356 }
357 break;
dfcd3bfb
JM
358 case 16: /* STRH Rd,[Rb,#imm5] */
359 case 17: /* LDRH Rd,[Rb,#imm5] */
c906108c 360 /* Format 10 */
dfcd3bfb
JM
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 */
c906108c 368 break;
dfcd3bfb
JM
369 case 18: /* STR Rd,[SP,#imm8] */
370 case 19: /* LDR Rd,[SP,#imm8] */
c906108c 371 /* Format 11 */
dfcd3bfb
JM
372 *ainstr = ((tinstr & (1 << 11)) /* base */
373 ? 0xE59D0000 /* LDR */
374 : 0xE58D0000) /* STR */
375 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
376 | ((tinstr & 0x00FF) << 2); /* off8 */
c906108c 377 break;
dfcd3bfb
JM
378 case 20: /* ADD Rd,PC,#imm8 */
379 case 21: /* ADD Rd,SP,#imm8 */
c906108c
SS
380 /* Format 12 */
381 if ((tinstr & (1 << 11)) == 0)
dfcd3bfb
JM
382 {
383 /* NOTE: The PC value used here should by word aligned */
c906108c
SS
384 /* We encode shift-left-by-2 in the rotate immediate field,
385 so no shift of off8 is needed. */
dfcd3bfb
JM
386 *ainstr = 0xE28F0F00 /* base */
387 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
388 | (tinstr & 0x00FF); /* off8 */
389 }
c906108c 390 else
dfcd3bfb 391 {
c906108c
SS
392 /* We encode shift-left-by-2 in the rotate immediate field,
393 so no shift of off8 is needed. */
dfcd3bfb
JM
394 *ainstr = 0xE28D0F00 /* base */
395 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
396 | (tinstr & 0x00FF); /* off8 */
397 }
c906108c
SS
398 break;
399 case 22:
400 case 23:
f1129fb8 401 switch (tinstr & 0x0F00)
dfcd3bfb 402 {
f1129fb8 403 case 0x0000:
dfcd3bfb
JM
404 /* Format 13 */
405 /* NOTE: The instruction contains a shift left of 2
f1129fb8 406 equivalent (implemented as ROR #30): */
dfcd3bfb
JM
407 *ainstr = ((tinstr & (1 << 7)) /* base */
408 ? 0xE24DDF00 /* SUB */
409 : 0xE28DDF00) /* ADD */
410 | (tinstr & 0x007F); /* off7 */
f1129fb8
NC
411 break;
412 case 0x0400:
413 /* Format 14 - Push */
414 * ainstr = 0xE92D0000 | (tinstr & 0x00FF);
415 break;
416 case 0x0500:
417 /* Format 14 - Push + LR */
418 * ainstr = 0xE92D4000 | (tinstr & 0x00FF);
419 break;
420 case 0x0c00:
421 /* Format 14 - Pop */
422 * ainstr = 0xE8BD0000 | (tinstr & 0x00FF);
423 break;
424 case 0x0d00:
425 /* Format 14 - Pop + PC */
426 * ainstr = 0xE8BD8000 | (tinstr & 0x00FF);
427 break;
428 case 0x0e00:
429 if (state->is_v5)
430 {
8d052926 431 /* This is normally an undefined instruction. The v5t architecture
f1129fb8
NC
432 defines this particular pattern as a BKPT instruction, for
433 hardware assisted debugging. We map onto the arm BKPT
434 instruction. */
435 * ainstr = 0xE1200070 | ((tinstr & 0xf0) << 4) | (tinstr & 0xf);
436 break;
437 }
438 /* Drop through. */
439 default:
440 /* Everything else is an undefined instruction. */
546aee7a 441 handle_v6_thumb_insn (state, tinstr, & valid);
f1129fb8 442 break;
dfcd3bfb 443 }
c906108c 444 break;
dfcd3bfb
JM
445 case 24: /* STMIA */
446 case 25: /* LDMIA */
c906108c 447 /* Format 15 */
dfcd3bfb
JM
448 *ainstr = ((tinstr & (1 << 11)) /* base */
449 ? 0xE8B00000 /* LDMIA */
450 : 0xE8A00000) /* STMIA */
451 | ((tinstr & 0x0700) << (16 - 8)) /* Rb */
452 | (tinstr & 0x00FF); /* mask8 */
c906108c 453 break;
dfcd3bfb
JM
454 case 26: /* Bcc */
455 case 27: /* Bcc/SWI */
c906108c 456 if ((tinstr & 0x0F00) == 0x0F00)
dfcd3bfb
JM
457 {
458 /* Format 17 : SWI */
459 *ainstr = 0xEF000000;
c906108c
SS
460 /* Breakpoint must be handled specially. */
461 if ((tinstr & 0x00FF) == 0x18)
462 *ainstr |= ((tinstr & 0x00FF) << 16);
7a292a7a
SS
463 /* New breakpoint value. See gdb/arm-tdep.c */
464 else if ((tinstr & 0x00FF) == 0xFE)
dfcd3bfb 465 *ainstr |= SWI_Breakpoint;
c906108c
SS
466 else
467 *ainstr |= (tinstr & 0x00FF);
dfcd3bfb 468 }
c906108c 469 else if ((tinstr & 0x0F00) != 0x0E00)
dfcd3bfb
JM
470 {
471 /* Format 16 */
472 int doit = FALSE;
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)
477 {
478 case EQ:
479 doit = ZFLAG;
480 break;
481 case NE:
482 doit = !ZFLAG;
483 break;
484 case VS:
485 doit = VFLAG;
486 break;
487 case VC:
488 doit = !VFLAG;
489 break;
490 case MI:
491 doit = NFLAG;
492 break;
493 case PL:
494 doit = !NFLAG;
495 break;
496 case CS:
497 doit = CFLAG;
498 break;
499 case CC:
500 doit = !CFLAG;
501 break;
502 case HI:
503 doit = (CFLAG && !ZFLAG);
504 break;
505 case LS:
506 doit = (!CFLAG || ZFLAG);
507 break;
508 case GE:
509 doit = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
510 break;
511 case LT:
512 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
513 break;
514 case GT:
515 doit = ((!NFLAG && !VFLAG && !ZFLAG)
516 || (NFLAG && VFLAG && !ZFLAG));
517 break;
518 case LE:
519 doit = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
520 break;
521 }
522 if (doit)
523 {
524 state->Reg[15] = (pc + 4
525 + (((tinstr & 0x7F) << 1)
526 | ((tinstr & (1 << 7)) ? 0xFFFFFF00 : 0)));
527 FLUSHPIPE;
528 }
529 valid = t_branch;
530 }
546aee7a
NC
531 else
532 /* UNDEFINED : cc=1110(AL) uses different format. */
533 handle_v6_thumb_insn (state, tinstr, & valid);
c906108c 534 break;
dfcd3bfb 535 case 28: /* B */
c906108c 536 /* Format 18 */
dfcd3bfb
JM
537 state->Reg[15] = (pc + 4
538 + (((tinstr & 0x3FF) << 1)
539 | ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0)));
c906108c
SS
540 FLUSHPIPE;
541 valid = t_branch;
542 break;
dfcd3bfb 543 case 29: /* UNDEFINED */
f1129fb8
NC
544 if (state->is_v5)
545 {
546 if (tinstr & 1)
547 {
546aee7a 548 handle_v6_thumb_insn (state, tinstr, & valid);
f1129fb8
NC
549 break;
550 }
551 /* Drop through. */
552
f1129fb8
NC
553 /* Format 19 */
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. */
559 {
560 ARMword tmp = (pc + 2);
7378e198 561
f1129fb8
NC
562 state->Reg[15] = ((state->Reg[14] + ((tinstr & 0x07FF) << 1))
563 & 0xFFFFFFFC);
564 CLEART;
565 state->Reg[14] = (tmp | 1);
566 valid = t_branch;
567 FLUSHPIPE;
8d052926
NC
568 if (trace_funcs)
569 fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
f1129fb8
NC
570 break;
571 }
572 }
546aee7a
NC
573
574 handle_v6_thumb_insn (state, tinstr, & valid);
c906108c 575 break;
546aee7a 576
dfcd3bfb 577 case 30: /* BL instruction 1 */
c906108c
SS
578 /* Format 19 */
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
dfcd3bfb 583 immediately. */
c906108c 584 state->Reg[14] = state->Reg[15] \
7378e198
NC
585 + (((tinstr & 0x07FF) << 12) \
586 | ((tinstr & (1 << 10)) ? 0xFF800000 : 0));
587
dfcd3bfb
JM
588 valid = t_branch; /* in-case we don't have the 2nd half */
589 tinstr = next_instr; /* move the instruction down */
4f3c3dbb 590 pc += 2; /* point the pc at the 2nd half */
c906108c 591 if (((tinstr & 0xF800) >> 11) != 31)
f1129fb8
NC
592 {
593 if (((tinstr & 0xF800) >> 11) == 29)
594 {
4f3c3dbb
NC
595 ARMword tmp = (pc + 2);
596
4f3c3dbb 597 state->Reg[15] = ((state->Reg[14]
2984e114 598 + ((tinstr & 0x07FE) << 1))
4f3c3dbb
NC
599 & 0xFFFFFFFC);
600 CLEART;
601 state->Reg[14] = (tmp | 1);
602 valid = t_branch;
603 FLUSHPIPE;
f1129fb8 604 }
4f3c3dbb
NC
605 else
606 /* Exit, since not correct instruction. */
607 pc -= 2;
608 break;
f1129fb8 609 }
c906108c 610 /* else we fall through to process the second half of the BL */
2984e114 611 pc += 2; /* point the pc at the 2nd half */
dfcd3bfb 612 case 31: /* BL instruction 2 */
c906108c
SS
613 /* Format 19 */
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
dfcd3bfb 618 r14 is not suitably initialised. */
c906108c 619 {
7378e198
NC
620 ARMword tmp = pc;
621
dfcd3bfb
JM
622 state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
623 state->Reg[14] = (tmp | 1);
624 valid = t_branch;
625 FLUSHPIPE;
c906108c
SS
626 }
627 break;
628 }
629
8d052926
NC
630 if (trace && valid != t_decoded)
631 fprintf (stderr, "\n");
632
c906108c
SS
633 return valid;
634}
This page took 1.278052 seconds and 4 git commands to generate.