1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
27 #include "arm_disassembler.h"
31 /* textual represenation of the condition field */
32 /* ALways (default) is ommitted (empty string) */
33 char *arm_condition_strings
[] =
35 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
38 /* make up for C's missing ROR */
39 uint32_t ror(uint32_t value
, int places
)
41 return (value
>> places
) | (value
<< (32 - places
));
44 int evaluate_pld(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
47 if ((opcode
& 0x0d70f0000) == 0x0550f000)
49 instruction
->type
= ARM_PLD
;
51 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
57 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
61 LOG_ERROR("should never reach this point");
65 int evaluate_swi(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
67 instruction
->type
= ARM_SWI
;
69 snprintf(instruction
->text
, 128,
70 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
71 address
, opcode
, (opcode
& 0xffffff));
76 int evaluate_blx_imm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
80 uint32_t target_address
;
82 instruction
->type
= ARM_BLX
;
83 immediate
= opcode
& 0x00ffffff;
85 /* sign extend 24-bit immediate */
86 if (immediate
& 0x00800000)
87 offset
= 0xff000000 | immediate
;
91 /* shift two bits left */
94 /* odd/event halfword */
95 if (opcode
& 0x01000000)
98 target_address
= address
+ 8 + offset
;
100 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
102 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
103 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
108 int evaluate_b_bl(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
113 uint32_t target_address
;
115 immediate
= opcode
& 0x00ffffff;
116 L
= (opcode
& 0x01000000) >> 24;
118 /* sign extend 24-bit immediate */
119 if (immediate
& 0x00800000)
120 offset
= 0xff000000 | immediate
;
124 /* shift two bits left */
127 target_address
= address
+ 8 + offset
;
130 instruction
->type
= ARM_BL
;
132 instruction
->type
= ARM_B
;
134 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
135 (L
) ? "L" : "", COND(opcode
), target_address
);
137 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
138 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
143 /* Coprocessor load/store and double register transfers */
144 /* both normal and extended instruction space (condition field b1111) */
145 int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
147 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
150 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
152 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
155 cp_opcode
= (opcode
& 0xf0) >> 4;
156 Rd
= (opcode
& 0xf000) >> 12;
157 Rn
= (opcode
& 0xf0000) >> 16;
158 CRm
= (opcode
& 0xf);
161 if ((opcode
& 0x0ff00000) == 0x0c400000)
163 instruction
->type
= ARM_MCRR
;
168 if ((opcode
& 0x0ff00000) == 0x0c500000)
170 instruction
->type
= ARM_MRRC
;
174 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
175 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
177 else /* LDC or STC */
179 uint8_t CRd
, Rn
, offset
;
182 char addressing_mode
[32];
184 CRd
= (opcode
& 0xf000) >> 12;
185 Rn
= (opcode
& 0xf0000) >> 16;
186 offset
= (opcode
& 0xff);
189 if (opcode
& 0x00100000)
191 instruction
->type
= ARM_LDC
;
196 instruction
->type
= ARM_STC
;
200 U
= (opcode
& 0x00800000) >> 23;
201 N
= (opcode
& 0x00400000) >> 22;
203 /* addressing modes */
204 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
205 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
206 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
207 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
208 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
209 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
210 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
211 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
213 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
214 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
216 cp_num
, CRd
, addressing_mode
);
222 /* Coprocessor data processing instructions */
223 /* Coprocessor register transfer instructions */
224 /* both normal and extended instruction space (condition field b1111) */
225 int evaluate_cdp_mcr_mrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
229 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
231 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
232 cp_num
= (opcode
& 0xf00) >> 8;
233 CRd_Rd
= (opcode
& 0xf000) >> 12;
234 CRn
= (opcode
& 0xf0000) >> 16;
235 CRm
= (opcode
& 0xf);
236 opcode_2
= (opcode
& 0xe0) >> 5;
239 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
241 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
243 instruction
->type
= ARM_MRC
;
246 else /* bit 20 not set -> MCR */
248 instruction
->type
= ARM_MCR
;
252 opcode_1
= (opcode
& 0x00e00000) >> 21;
254 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
255 address
, opcode
, mnemonic
, cond
,
256 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
258 else /* bit 4 not set -> CDP */
260 instruction
->type
= ARM_CDP
;
263 opcode_1
= (opcode
& 0x00f00000) >> 20;
265 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
266 address
, opcode
, mnemonic
, cond
,
267 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
273 /* Load/store instructions */
274 int evaluate_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
276 uint8_t I
, P
, U
, B
, W
, L
;
278 char *operation
; /* "LDR" or "STR" */
279 char *suffix
; /* "", "B", "T", "BT" */
283 I
= (opcode
& 0x02000000) >> 25;
284 P
= (opcode
& 0x01000000) >> 24;
285 U
= (opcode
& 0x00800000) >> 23;
286 B
= (opcode
& 0x00400000) >> 22;
287 W
= (opcode
& 0x00200000) >> 21;
288 L
= (opcode
& 0x00100000) >> 20;
290 /* target register */
291 Rd
= (opcode
& 0xf000) >> 12;
294 Rn
= (opcode
& 0xf0000) >> 16;
296 instruction
->info
.load_store
.Rd
= Rd
;
297 instruction
->info
.load_store
.Rn
= Rn
;
298 instruction
->info
.load_store
.U
= U
;
300 /* determine operation */
306 /* determine instruction type and suffix */
309 if ((P
== 0) && (W
== 1))
312 instruction
->type
= ARM_LDRBT
;
314 instruction
->type
= ARM_STRBT
;
320 instruction
->type
= ARM_LDRB
;
322 instruction
->type
= ARM_STRB
;
328 if ((P
== 0) && (W
== 1))
331 instruction
->type
= ARM_LDRT
;
333 instruction
->type
= ARM_STRT
;
339 instruction
->type
= ARM_LDR
;
341 instruction
->type
= ARM_STR
;
346 if (!I
) /* #+-<offset_12> */
348 uint32_t offset_12
= (opcode
& 0xfff);
350 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
352 snprintf(offset
, 32, "%s", "");
354 instruction
->info
.load_store
.offset_mode
= 0;
355 instruction
->info
.load_store
.offset
.offset
= offset_12
;
357 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
359 uint8_t shift_imm
, shift
;
362 shift_imm
= (opcode
& 0xf80) >> 7;
363 shift
= (opcode
& 0x60) >> 5;
366 /* LSR encodes a shift by 32 bit as 0x0 */
367 if ((shift
== 0x1) && (shift_imm
== 0x0))
370 /* ASR encodes a shift by 32 bit as 0x0 */
371 if ((shift
== 0x2) && (shift_imm
== 0x0))
374 /* ROR by 32 bit is actually a RRX */
375 if ((shift
== 0x3) && (shift_imm
== 0x0))
378 instruction
->info
.load_store
.offset_mode
= 1;
379 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
380 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
381 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
383 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
385 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
387 else /* +-<Rm>, <Shift>, #<shift_imm> */
392 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
395 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
398 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
401 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
404 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
412 if (W
== 0) /* offset */
414 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
415 address
, opcode
, operation
, COND(opcode
), suffix
,
418 instruction
->info
.load_store
.index_mode
= 0;
420 else /* pre-indexed */
422 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
423 address
, opcode
, operation
, COND(opcode
), suffix
,
426 instruction
->info
.load_store
.index_mode
= 1;
429 else /* post-indexed */
431 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
432 address
, opcode
, operation
, COND(opcode
), suffix
,
435 instruction
->info
.load_store
.index_mode
= 2;
441 /* Miscellaneous load/store instructions */
442 int evaluate_misc_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
444 uint8_t P
, U
, I
, W
, L
, S
, H
;
446 char *operation
; /* "LDR" or "STR" */
447 char *suffix
; /* "H", "SB", "SH", "D" */
451 P
= (opcode
& 0x01000000) >> 24;
452 U
= (opcode
& 0x00800000) >> 23;
453 I
= (opcode
& 0x00400000) >> 22;
454 W
= (opcode
& 0x00200000) >> 21;
455 L
= (opcode
& 0x00100000) >> 20;
456 S
= (opcode
& 0x00000040) >> 6;
457 H
= (opcode
& 0x00000020) >> 5;
459 /* target register */
460 Rd
= (opcode
& 0xf000) >> 12;
463 Rn
= (opcode
& 0xf0000) >> 16;
465 instruction
->info
.load_store
.Rd
= Rd
;
466 instruction
->info
.load_store
.Rn
= Rn
;
467 instruction
->info
.load_store
.U
= U
;
469 /* determine instruction type and suffix */
477 instruction
->type
= ARM_LDRSH
;
483 instruction
->type
= ARM_LDRSB
;
487 else /* there are no signed stores, so this is used to encode double-register load/stores */
493 instruction
->type
= ARM_STRD
;
498 instruction
->type
= ARM_LDRD
;
508 instruction
->type
= ARM_LDRH
;
513 instruction
->type
= ARM_STRH
;
517 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
519 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
520 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
522 instruction
->info
.load_store
.offset_mode
= 0;
523 instruction
->info
.load_store
.offset
.offset
= offset_8
;
525 else /* Register offset/index (+-<Rm>) */
529 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
531 instruction
->info
.load_store
.offset_mode
= 1;
532 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
533 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
534 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
539 if (W
== 0) /* offset */
541 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
542 address
, opcode
, operation
, COND(opcode
), suffix
,
545 instruction
->info
.load_store
.index_mode
= 0;
547 else /* pre-indexed */
549 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
550 address
, opcode
, operation
, COND(opcode
), suffix
,
553 instruction
->info
.load_store
.index_mode
= 1;
556 else /* post-indexed */
558 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
559 address
, opcode
, operation
, COND(opcode
), suffix
,
562 instruction
->info
.load_store
.index_mode
= 2;
568 /* Load/store multiples instructions */
569 int evaluate_ldm_stm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
571 uint8_t P
, U
, S
, W
, L
, Rn
;
572 uint32_t register_list
;
573 char *addressing_mode
;
580 P
= (opcode
& 0x01000000) >> 24;
581 U
= (opcode
& 0x00800000) >> 23;
582 S
= (opcode
& 0x00400000) >> 22;
583 W
= (opcode
& 0x00200000) >> 21;
584 L
= (opcode
& 0x00100000) >> 20;
585 register_list
= (opcode
& 0xffff);
586 Rn
= (opcode
& 0xf0000) >> 16;
588 instruction
->info
.load_store_multiple
.Rn
= Rn
;
589 instruction
->info
.load_store_multiple
.register_list
= register_list
;
590 instruction
->info
.load_store_multiple
.S
= S
;
591 instruction
->info
.load_store_multiple
.W
= W
;
595 instruction
->type
= ARM_LDM
;
600 instruction
->type
= ARM_STM
;
608 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
609 addressing_mode
= "IB";
613 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
614 addressing_mode
= "DB";
621 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
622 /* "IA" is the default in UAL syntax */
623 addressing_mode
= "";
627 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
628 addressing_mode
= "DA";
632 reg_list_p
= reg_list
;
633 for (i
= 0; i
<= 15; i
++)
635 if ((register_list
>> i
) & 1)
640 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
644 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
649 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
650 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
651 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
656 /* Multiplies, extra load/stores */
657 int evaluate_mul_and_extra_ld_st(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
659 /* Multiply (accumulate) (long) and Swap/swap byte */
660 if ((opcode
& 0x000000f0) == 0x00000090)
662 /* Multiply (accumulate) */
663 if ((opcode
& 0x0f800000) == 0x00000000)
665 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
667 Rs
= (opcode
& 0xf00) >> 8;
668 Rn
= (opcode
& 0xf000) >> 12;
669 Rd
= (opcode
& 0xf0000) >> 16;
670 S
= (opcode
& 0x00100000) >> 20;
672 /* examine A bit (accumulate) */
673 if (opcode
& 0x00200000)
675 instruction
->type
= ARM_MLA
;
676 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
677 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
681 instruction
->type
= ARM_MUL
;
682 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
683 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
689 /* Multiply (accumulate) long */
690 if ((opcode
& 0x0f800000) == 0x00800000)
692 char* mnemonic
= NULL
;
693 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
695 Rs
= (opcode
& 0xf00) >> 8;
696 RdHi
= (opcode
& 0xf000) >> 12;
697 RdLow
= (opcode
& 0xf0000) >> 16;
698 S
= (opcode
& 0x00100000) >> 20;
700 switch ((opcode
& 0x00600000) >> 21)
703 instruction
->type
= ARM_UMULL
;
707 instruction
->type
= ARM_UMLAL
;
711 instruction
->type
= ARM_SMULL
;
715 instruction
->type
= ARM_SMLAL
;
720 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
721 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
722 RdLow
, RdHi
, Rm
, Rs
);
728 if ((opcode
& 0x0f800000) == 0x01000000)
732 Rd
= (opcode
& 0xf000) >> 12;
733 Rn
= (opcode
& 0xf0000) >> 16;
736 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
738 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
739 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
745 return evaluate_misc_load_store(opcode
, address
, instruction
);
748 int evaluate_mrs_msr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
750 int R
= (opcode
& 0x00400000) >> 22;
751 char *PSR
= (R
) ? "SPSR" : "CPSR";
753 /* Move register to status register (MSR) */
754 if (opcode
& 0x00200000)
756 instruction
->type
= ARM_MSR
;
758 /* immediate variant */
759 if (opcode
& 0x02000000)
761 uint8_t immediate
= (opcode
& 0xff);
762 uint8_t rotate
= (opcode
& 0xf00);
764 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
765 address
, opcode
, COND(opcode
), PSR
,
766 (opcode
& 0x10000) ? "c" : "",
767 (opcode
& 0x20000) ? "x" : "",
768 (opcode
& 0x40000) ? "s" : "",
769 (opcode
& 0x80000) ? "f" : "",
770 ror(immediate
, (rotate
* 2))
773 else /* register variant */
775 uint8_t Rm
= opcode
& 0xf;
776 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
777 address
, opcode
, COND(opcode
), PSR
,
778 (opcode
& 0x10000) ? "c" : "",
779 (opcode
& 0x20000) ? "x" : "",
780 (opcode
& 0x40000) ? "s" : "",
781 (opcode
& 0x80000) ? "f" : "",
787 else /* Move status register to register (MRS) */
791 instruction
->type
= ARM_MRS
;
792 Rd
= (opcode
& 0x0000f000) >> 12;
794 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
795 address
, opcode
, COND(opcode
), Rd
, PSR
);
801 /* Miscellaneous instructions */
802 int evaluate_misc_instr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
805 if ((opcode
& 0x000000f0) == 0x00000000)
807 evaluate_mrs_msr(opcode
, address
, instruction
);
811 if ((opcode
& 0x006000f0) == 0x00200010)
814 instruction
->type
= ARM_BX
;
817 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
818 address
, opcode
, COND(opcode
), Rm
);
820 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
821 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
825 if ((opcode
& 0x006000f0) == 0x00600010)
828 instruction
->type
= ARM_CLZ
;
830 Rd
= (opcode
& 0xf000) >> 12;
832 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
833 address
, opcode
, COND(opcode
), Rd
, Rm
);
837 if ((opcode
& 0x006000f0) == 0x00200030)
840 instruction
->type
= ARM_BLX
;
843 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
844 address
, opcode
, COND(opcode
), Rm
);
846 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
847 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
850 /* Enhanced DSP add/subtracts */
851 if ((opcode
& 0x0000000f0) == 0x00000050)
854 char *mnemonic
= NULL
;
856 Rd
= (opcode
& 0xf000) >> 12;
857 Rn
= (opcode
& 0xf0000) >> 16;
859 switch ((opcode
& 0x00600000) >> 21)
862 instruction
->type
= ARM_QADD
;
866 instruction
->type
= ARM_QSUB
;
870 instruction
->type
= ARM_QDADD
;
874 instruction
->type
= ARM_QDSUB
;
879 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
880 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
883 /* Software breakpoints */
884 if ((opcode
& 0x0000000f0) == 0x00000070)
887 instruction
->type
= ARM_BKPT
;
888 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
890 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
891 address
, opcode
, immediate
);
894 /* Enhanced DSP multiplies */
895 if ((opcode
& 0x000000090) == 0x00000080)
897 int x
= (opcode
& 0x20) >> 5;
898 int y
= (opcode
& 0x40) >> 6;
901 if ((opcode
& 0x00600000) == 0x00000000)
903 uint8_t Rd
, Rm
, Rs
, Rn
;
904 instruction
->type
= ARM_SMLAxy
;
905 Rd
= (opcode
& 0xf0000) >> 16;
907 Rs
= (opcode
& 0xf00) >> 8;
908 Rn
= (opcode
& 0xf000) >> 12;
910 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
911 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
916 if ((opcode
& 0x00600000) == 0x00400000)
918 uint8_t RdLow
, RdHi
, Rm
, Rs
;
919 instruction
->type
= ARM_SMLAxy
;
920 RdHi
= (opcode
& 0xf0000) >> 16;
921 RdLow
= (opcode
& 0xf000) >> 12;
923 Rs
= (opcode
& 0xf00) >> 8;
925 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
926 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
927 RdLow
, RdHi
, Rm
, Rs
);
931 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
933 uint8_t Rd
, Rm
, Rs
, Rn
;
934 instruction
->type
= ARM_SMLAWy
;
935 Rd
= (opcode
& 0xf0000) >> 16;
937 Rs
= (opcode
& 0xf00) >> 8;
938 Rn
= (opcode
& 0xf000) >> 12;
940 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
941 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
946 if ((opcode
& 0x00600000) == 0x00300000)
949 instruction
->type
= ARM_SMULxy
;
950 Rd
= (opcode
& 0xf0000) >> 16;
952 Rs
= (opcode
& 0xf00) >> 8;
954 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
955 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
960 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
963 instruction
->type
= ARM_SMULWy
;
964 Rd
= (opcode
& 0xf0000) >> 16;
966 Rs
= (opcode
& 0xf00) >> 8;
968 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
969 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
977 int evaluate_data_proc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
979 uint8_t I
, op
, S
, Rn
, Rd
;
980 char *mnemonic
= NULL
;
981 char shifter_operand
[32];
983 I
= (opcode
& 0x02000000) >> 25;
984 op
= (opcode
& 0x01e00000) >> 21;
985 S
= (opcode
& 0x00100000) >> 20;
987 Rd
= (opcode
& 0xf000) >> 12;
988 Rn
= (opcode
& 0xf0000) >> 16;
990 instruction
->info
.data_proc
.Rd
= Rd
;
991 instruction
->info
.data_proc
.Rn
= Rn
;
992 instruction
->info
.data_proc
.S
= S
;
997 instruction
->type
= ARM_AND
;
1001 instruction
->type
= ARM_EOR
;
1005 instruction
->type
= ARM_SUB
;
1009 instruction
->type
= ARM_RSB
;
1013 instruction
->type
= ARM_ADD
;
1017 instruction
->type
= ARM_ADC
;
1021 instruction
->type
= ARM_SBC
;
1025 instruction
->type
= ARM_RSC
;
1029 instruction
->type
= ARM_TST
;
1033 instruction
->type
= ARM_TEQ
;
1037 instruction
->type
= ARM_CMP
;
1041 instruction
->type
= ARM_CMN
;
1045 instruction
->type
= ARM_ORR
;
1049 instruction
->type
= ARM_MOV
;
1053 instruction
->type
= ARM_BIC
;
1057 instruction
->type
= ARM_MVN
;
1062 if (I
) /* immediate shifter operand (#<immediate>)*/
1064 uint8_t immed_8
= opcode
& 0xff;
1065 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1068 immediate
= ror(immed_8
, rotate_imm
* 2);
1070 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1072 instruction
->info
.data_proc
.variant
= 0;
1073 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1075 else /* register-based shifter operand */
1078 shift
= (opcode
& 0x60) >> 5;
1079 Rm
= (opcode
& 0xf);
1081 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1084 shift_imm
= (opcode
& 0xf80) >> 7;
1086 instruction
->info
.data_proc
.variant
= 1;
1087 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1088 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1089 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1091 /* LSR encodes a shift by 32 bit as 0x0 */
1092 if ((shift
== 0x1) && (shift_imm
== 0x0))
1095 /* ASR encodes a shift by 32 bit as 0x0 */
1096 if ((shift
== 0x2) && (shift_imm
== 0x0))
1099 /* ROR by 32 bit is actually a RRX */
1100 if ((shift
== 0x3) && (shift_imm
== 0x0))
1103 if ((shift_imm
== 0x0) && (shift
== 0x0))
1105 snprintf(shifter_operand
, 32, "r%i", Rm
);
1109 if (shift
== 0x0) /* LSL */
1111 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1113 else if (shift
== 0x1) /* LSR */
1115 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1117 else if (shift
== 0x2) /* ASR */
1119 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1121 else if (shift
== 0x3) /* ROR */
1123 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1125 else if (shift
== 0x4) /* RRX */
1127 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1131 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1133 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1135 instruction
->info
.data_proc
.variant
= 2;
1136 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1137 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1138 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1140 if (shift
== 0x0) /* LSL */
1142 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1144 else if (shift
== 0x1) /* LSR */
1146 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1148 else if (shift
== 0x2) /* ASR */
1150 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1152 else if (shift
== 0x3) /* ROR */
1154 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1159 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1161 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1162 address
, opcode
, mnemonic
, COND(opcode
),
1163 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1165 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1167 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1168 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1170 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1171 address
, opcode
, mnemonic
, COND(opcode
),
1172 (S
) ? "S" : "", Rd
, shifter_operand
);
1174 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1176 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1177 address
, opcode
, mnemonic
, COND(opcode
),
1178 Rn
, shifter_operand
);
1184 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1186 /* clear fields, to avoid confusion */
1187 memset(instruction
, 0, sizeof(arm_instruction_t
));
1188 instruction
->opcode
= opcode
;
1189 instruction
->instruction_size
= 4;
1191 /* catch opcodes with condition field [31:28] = b1111 */
1192 if ((opcode
& 0xf0000000) == 0xf0000000)
1194 /* Undefined instruction (or ARMv5E cache preload PLD) */
1195 if ((opcode
& 0x08000000) == 0x00000000)
1196 return evaluate_pld(opcode
, address
, instruction
);
1198 /* Undefined instruction */
1199 if ((opcode
& 0x0e000000) == 0x08000000)
1201 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1202 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1206 /* Branch and branch with link and change to Thumb */
1207 if ((opcode
& 0x0e000000) == 0x0a000000)
1208 return evaluate_blx_imm(opcode
, address
, instruction
);
1210 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1211 /* Coprocessor load/store and double register transfers */
1212 if ((opcode
& 0x0e000000) == 0x0c000000)
1213 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1215 /* Coprocessor data processing */
1216 if ((opcode
& 0x0f000100) == 0x0c000000)
1217 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1219 /* Coprocessor register transfers */
1220 if ((opcode
& 0x0f000010) == 0x0c000010)
1221 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1223 /* Undefined instruction */
1224 if ((opcode
& 0x0f000000) == 0x0f000000)
1226 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1227 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1232 /* catch opcodes with [27:25] = b000 */
1233 if ((opcode
& 0x0e000000) == 0x00000000)
1235 /* Multiplies, extra load/stores */
1236 if ((opcode
& 0x00000090) == 0x00000090)
1237 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1239 /* Miscellaneous instructions */
1240 if ((opcode
& 0x0f900000) == 0x01000000)
1241 return evaluate_misc_instr(opcode
, address
, instruction
);
1243 return evaluate_data_proc(opcode
, address
, instruction
);
1246 /* catch opcodes with [27:25] = b001 */
1247 if ((opcode
& 0x0e000000) == 0x02000000)
1249 /* Undefined instruction */
1250 if ((opcode
& 0x0fb00000) == 0x03000000)
1252 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1253 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1257 /* Move immediate to status register */
1258 if ((opcode
& 0x0fb00000) == 0x03200000)
1259 return evaluate_mrs_msr(opcode
, address
, instruction
);
1261 return evaluate_data_proc(opcode
, address
, instruction
);
1265 /* catch opcodes with [27:25] = b010 */
1266 if ((opcode
& 0x0e000000) == 0x04000000)
1268 /* Load/store immediate offset */
1269 return evaluate_load_store(opcode
, address
, instruction
);
1272 /* catch opcodes with [27:25] = b011 */
1273 if ((opcode
& 0x0e000000) == 0x06000000)
1275 /* Undefined instruction */
1276 if ((opcode
& 0x00000010) == 0x00000010)
1278 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1279 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1283 /* Load/store register offset */
1284 return evaluate_load_store(opcode
, address
, instruction
);
1288 /* catch opcodes with [27:25] = b100 */
1289 if ((opcode
& 0x0e000000) == 0x08000000)
1291 /* Load/store multiple */
1292 return evaluate_ldm_stm(opcode
, address
, instruction
);
1295 /* catch opcodes with [27:25] = b101 */
1296 if ((opcode
& 0x0e000000) == 0x0a000000)
1298 /* Branch and branch with link */
1299 return evaluate_b_bl(opcode
, address
, instruction
);
1302 /* catch opcodes with [27:25] = b110 */
1303 if ((opcode
& 0x0e000000) == 0x0a000000)
1305 /* Coprocessor load/store and double register transfers */
1306 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1309 /* catch opcodes with [27:25] = b111 */
1310 if ((opcode
& 0x0e000000) == 0x0e000000)
1312 /* Software interrupt */
1313 if ((opcode
& 0x0f000000) == 0x0f000000)
1314 return evaluate_swi(opcode
, address
, instruction
);
1316 /* Coprocessor data processing */
1317 if ((opcode
& 0x0f000010) == 0x0e000000)
1318 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1320 /* Coprocessor register transfers */
1321 if ((opcode
& 0x0f000010) == 0x0e000010)
1322 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1325 LOG_ERROR("should never reach this point");
1329 int evaluate_b_bl_blx_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1331 uint32_t offset
= opcode
& 0x7ff;
1332 uint32_t opc
= (opcode
>> 11) & 0x3;
1333 uint32_t target_address
;
1334 char *mnemonic
= NULL
;
1336 /* sign extend 11-bit offset */
1337 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1338 offset
= 0xfffff800 | offset
;
1340 target_address
= address
+ 4 + (offset
<< 1);
1344 /* unconditional branch */
1346 instruction
->type
= ARM_B
;
1351 instruction
->type
= ARM_BLX
;
1356 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1357 mnemonic
= "prefix";
1358 target_address
= offset
<< 12;
1362 instruction
->type
= ARM_BL
;
1367 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1368 * these are effectively 32-bit instructions even in Thumb1.
1369 * Might be simplest to always use the Thumb2 decoder.
1372 snprintf(instruction
->text
, 128,
1373 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1374 address
, opcode
, mnemonic
, target_address
);
1376 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1377 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1382 int evaluate_add_sub_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1384 uint8_t Rd
= (opcode
>> 0) & 0x7;
1385 uint8_t Rn
= (opcode
>> 3) & 0x7;
1386 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1387 uint32_t opc
= opcode
& (1 << 9);
1388 uint32_t reg_imm
= opcode
& (1 << 10);
1393 instruction
->type
= ARM_SUB
;
1398 instruction
->type
= ARM_ADD
;
1402 instruction
->info
.data_proc
.Rd
= Rd
;
1403 instruction
->info
.data_proc
.Rn
= Rn
;
1404 instruction
->info
.data_proc
.S
= 1;
1408 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1409 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1410 snprintf(instruction
->text
, 128,
1411 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1412 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1416 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1417 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1418 snprintf(instruction
->text
, 128,
1419 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1420 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1426 int evaluate_shift_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1428 uint8_t Rd
= (opcode
>> 0) & 0x7;
1429 uint8_t Rm
= (opcode
>> 3) & 0x7;
1430 uint8_t imm
= (opcode
>> 6) & 0x1f;
1431 uint8_t opc
= (opcode
>> 11) & 0x3;
1432 char *mnemonic
= NULL
;
1437 instruction
->type
= ARM_MOV
;
1439 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1442 instruction
->type
= ARM_MOV
;
1444 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1447 instruction
->type
= ARM_MOV
;
1449 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1453 if ((imm
== 0) && (opc
!= 0))
1456 instruction
->info
.data_proc
.Rd
= Rd
;
1457 instruction
->info
.data_proc
.Rn
= -1;
1458 instruction
->info
.data_proc
.S
= 1;
1460 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1461 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1462 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1464 snprintf(instruction
->text
, 128,
1465 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1466 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1471 int evaluate_data_proc_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1473 uint8_t imm
= opcode
& 0xff;
1474 uint8_t Rd
= (opcode
>> 8) & 0x7;
1475 uint32_t opc
= (opcode
>> 11) & 0x3;
1476 char *mnemonic
= NULL
;
1478 instruction
->info
.data_proc
.Rd
= Rd
;
1479 instruction
->info
.data_proc
.Rn
= Rd
;
1480 instruction
->info
.data_proc
.S
= 1;
1481 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1482 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1487 instruction
->type
= ARM_MOV
;
1489 instruction
->info
.data_proc
.Rn
= -1;
1492 instruction
->type
= ARM_CMP
;
1494 instruction
->info
.data_proc
.Rd
= -1;
1497 instruction
->type
= ARM_ADD
;
1501 instruction
->type
= ARM_SUB
;
1506 snprintf(instruction
->text
, 128,
1507 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1508 address
, opcode
, mnemonic
, Rd
, imm
);
1513 int evaluate_data_proc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1515 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1516 char *mnemonic
= NULL
;
1519 high_reg
= (opcode
& 0x0400) >> 10;
1520 op
= (opcode
& 0x03C0) >> 6;
1522 Rd
= (opcode
& 0x0007);
1523 Rm
= (opcode
& 0x0038) >> 3;
1524 H1
= (opcode
& 0x0080) >> 7;
1525 H2
= (opcode
& 0x0040) >> 6;
1527 instruction
->info
.data_proc
.Rd
= Rd
;
1528 instruction
->info
.data_proc
.Rn
= Rd
;
1529 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1530 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1531 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1542 instruction
->type
= ARM_ADD
;
1546 instruction
->type
= ARM_CMP
;
1550 instruction
->type
= ARM_MOV
;
1556 if ((opcode
& 0x7) == 0x0)
1558 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1561 instruction
->type
= ARM_BLX
;
1562 snprintf(instruction
->text
, 128,
1564 " 0x%4.4x \tBLX\tr%i",
1565 address
, opcode
, Rm
);
1569 instruction
->type
= ARM_BX
;
1570 snprintf(instruction
->text
, 128,
1572 " 0x%4.4x \tBX\tr%i",
1573 address
, opcode
, Rm
);
1578 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1579 snprintf(instruction
->text
, 128,
1582 "UNDEFINED INSTRUCTION",
1594 instruction
->type
= ARM_AND
;
1598 instruction
->type
= ARM_EOR
;
1602 instruction
->type
= ARM_MOV
;
1604 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1605 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1606 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1607 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1610 instruction
->type
= ARM_MOV
;
1612 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1613 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1614 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1615 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1618 instruction
->type
= ARM_MOV
;
1620 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1621 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1622 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1623 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1626 instruction
->type
= ARM_ADC
;
1630 instruction
->type
= ARM_SBC
;
1634 instruction
->type
= ARM_MOV
;
1636 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1637 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1638 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1639 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1642 instruction
->type
= ARM_TST
;
1646 instruction
->type
= ARM_RSB
;
1648 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1649 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1650 instruction
->info
.data_proc
.Rn
= Rm
;
1653 instruction
->type
= ARM_CMP
;
1657 instruction
->type
= ARM_CMN
;
1661 instruction
->type
= ARM_ORR
;
1665 instruction
->type
= ARM_MUL
;
1669 instruction
->type
= ARM_BIC
;
1673 instruction
->type
= ARM_MVN
;
1680 snprintf(instruction
->text
, 128,
1681 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
1683 address
, opcode
, mnemonic
, Rd
, Rm
);
1685 snprintf(instruction
->text
, 128,
1686 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
1687 address
, opcode
, mnemonic
, Rd
, Rm
);
1692 /* PC-relative data addressing is word-aligned even with Thumb */
1693 static inline uint32_t thumb_alignpc4(uint32_t addr
)
1695 return (addr
+ 4) & ~3;
1698 int evaluate_load_literal_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1701 uint8_t Rd
= (opcode
>> 8) & 0x7;
1703 instruction
->type
= ARM_LDR
;
1704 immediate
= opcode
& 0x000000ff;
1707 instruction
->info
.load_store
.Rd
= Rd
;
1708 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
1709 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1710 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1711 instruction
->info
.load_store
.offset
.offset
= immediate
;
1713 snprintf(instruction
->text
, 128,
1714 "0x%8.8" PRIx32
" 0x%4.4x \t"
1715 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
1716 address
, opcode
, Rd
, immediate
,
1717 thumb_alignpc4(address
) + immediate
);
1722 int evaluate_load_store_reg_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1724 uint8_t Rd
= (opcode
>> 0) & 0x7;
1725 uint8_t Rn
= (opcode
>> 3) & 0x7;
1726 uint8_t Rm
= (opcode
>> 6) & 0x7;
1727 uint8_t opc
= (opcode
>> 9) & 0x7;
1728 char *mnemonic
= NULL
;
1733 instruction
->type
= ARM_STR
;
1737 instruction
->type
= ARM_STRH
;
1741 instruction
->type
= ARM_STRB
;
1745 instruction
->type
= ARM_LDRSB
;
1749 instruction
->type
= ARM_LDR
;
1753 instruction
->type
= ARM_LDRH
;
1757 instruction
->type
= ARM_LDRB
;
1761 instruction
->type
= ARM_LDRSH
;
1766 snprintf(instruction
->text
, 128,
1767 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
1768 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
1770 instruction
->info
.load_store
.Rd
= Rd
;
1771 instruction
->info
.load_store
.Rn
= Rn
;
1772 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1773 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
1774 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1779 int evaluate_load_store_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1781 uint32_t offset
= (opcode
>> 6) & 0x1f;
1782 uint8_t Rd
= (opcode
>> 0) & 0x7;
1783 uint8_t Rn
= (opcode
>> 3) & 0x7;
1784 uint32_t L
= opcode
& (1 << 11);
1785 uint32_t B
= opcode
& (1 << 12);
1792 instruction
->type
= ARM_LDR
;
1797 instruction
->type
= ARM_STR
;
1801 if ((opcode
&0xF000) == 0x8000)
1812 snprintf(instruction
->text
, 128,
1813 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
1814 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
1816 instruction
->info
.load_store
.Rd
= Rd
;
1817 instruction
->info
.load_store
.Rn
= Rn
;
1818 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1819 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1820 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
1825 int evaluate_load_store_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1827 uint32_t offset
= opcode
& 0xff;
1828 uint8_t Rd
= (opcode
>> 8) & 0x7;
1829 uint32_t L
= opcode
& (1 << 11);
1834 instruction
->type
= ARM_LDR
;
1839 instruction
->type
= ARM_STR
;
1843 snprintf(instruction
->text
, 128,
1844 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
1845 address
, opcode
, mnemonic
, Rd
, offset
*4);
1847 instruction
->info
.load_store
.Rd
= Rd
;
1848 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
1849 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1850 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1851 instruction
->info
.load_store
.offset
.offset
= offset
*4;
1856 int evaluate_add_sp_pc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1858 uint32_t imm
= opcode
& 0xff;
1859 uint8_t Rd
= (opcode
>> 8) & 0x7;
1861 uint32_t SP
= opcode
& (1 << 11);
1864 instruction
->type
= ARM_ADD
;
1877 snprintf(instruction
->text
, 128,
1878 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
1879 address
, opcode
, Rd
, reg_name
, imm
* 4);
1881 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1882 instruction
->info
.data_proc
.Rd
= Rd
;
1883 instruction
->info
.data_proc
.Rn
= Rn
;
1884 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1889 int evaluate_adjust_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1891 uint32_t imm
= opcode
& 0x7f;
1892 uint8_t opc
= opcode
& (1 << 7);
1898 instruction
->type
= ARM_SUB
;
1903 instruction
->type
= ARM_ADD
;
1907 snprintf(instruction
->text
, 128,
1908 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
1909 address
, opcode
, mnemonic
, imm
*4);
1911 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1912 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
1913 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
1914 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1919 int evaluate_breakpoint_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1921 uint32_t imm
= opcode
& 0xff;
1923 instruction
->type
= ARM_BKPT
;
1925 snprintf(instruction
->text
, 128,
1926 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
1927 address
, opcode
, imm
);
1932 int evaluate_load_store_multiple_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1934 uint32_t reg_list
= opcode
& 0xff;
1935 uint32_t L
= opcode
& (1 << 11);
1936 uint32_t R
= opcode
& (1 << 8);
1937 uint8_t Rn
= (opcode
>> 8) & 7;
1938 uint8_t addr_mode
= 0 /* IA */;
1942 char ptr_name
[7] = "";
1945 if ((opcode
& 0xf000) == 0xc000)
1946 { /* generic load/store multiple */
1951 instruction
->type
= ARM_LDM
;
1953 if (opcode
& (1 << Rn
))
1958 instruction
->type
= ARM_STM
;
1961 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
1968 instruction
->type
= ARM_LDM
;
1971 reg_list
|= (1 << 15) /*PC*/;
1975 instruction
->type
= ARM_STM
;
1977 addr_mode
= 3; /*DB*/
1979 reg_list
|= (1 << 14) /*LR*/;
1983 reg_names_p
= reg_names
;
1984 for (i
= 0; i
<= 15; i
++)
1986 if (reg_list
& (1 << i
))
1987 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
1989 if (reg_names_p
> reg_names
)
1990 reg_names_p
[-2] = '\0';
1991 else /* invalid op : no registers */
1992 reg_names
[0] = '\0';
1994 snprintf(instruction
->text
, 128,
1995 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
1996 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
1998 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
1999 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2000 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2005 int evaluate_cond_branch_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2007 uint32_t offset
= opcode
& 0xff;
2008 uint8_t cond
= (opcode
>> 8) & 0xf;
2009 uint32_t target_address
;
2013 instruction
->type
= ARM_SWI
;
2014 snprintf(instruction
->text
, 128,
2015 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2016 address
, opcode
, offset
);
2019 else if (cond
== 0xe)
2021 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2022 snprintf(instruction
->text
, 128,
2023 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2028 /* sign extend 8-bit offset */
2029 if (offset
& 0x00000080)
2030 offset
= 0xffffff00 | offset
;
2032 target_address
= address
+ 4 + (offset
<< 1);
2034 snprintf(instruction
->text
, 128,
2035 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2037 arm_condition_strings
[cond
], target_address
);
2039 instruction
->type
= ARM_B
;
2040 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2041 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2046 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2047 arm_instruction_t
*instruction
)
2051 /* added in Thumb2 */
2052 offset
= (opcode
>> 3) & 0x1f;
2053 offset
|= (opcode
& 0x0200) >> 4;
2055 snprintf(instruction
->text
, 128,
2056 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2058 (opcode
& 0x0800) ? "N" : "",
2059 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2064 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2065 arm_instruction_t
*instruction
)
2067 /* added in ARMv6 */
2068 snprintf(instruction
->text
, 128,
2069 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2071 (opcode
& 0x0080) ? 'U' : 'S',
2072 (opcode
& 0x0040) ? 'B' : 'H',
2073 opcode
& 0x7, (opcode
>> 3) & 0x7);
2078 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2079 arm_instruction_t
*instruction
)
2081 /* added in ARMv6 */
2082 if ((opcode
& 0x0ff0) == 0x0650)
2083 snprintf(instruction
->text
, 128,
2084 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2086 (opcode
& 0x80) ? "BE" : "LE");
2087 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2088 snprintf(instruction
->text
, 128,
2089 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2091 (opcode
& 0x0010) ? 'D' : 'E',
2092 (opcode
& 0x0004) ? "A" : "",
2093 (opcode
& 0x0002) ? "I" : "",
2094 (opcode
& 0x0001) ? "F" : "");
2099 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2100 arm_instruction_t
*instruction
)
2104 /* added in ARMv6 */
2105 switch ((opcode
>> 6) & 3) {
2116 snprintf(instruction
->text
, 128,
2117 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2118 address
, opcode
, suffix
,
2119 opcode
& 0x7, (opcode
>> 3) & 0x7);
2124 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2125 arm_instruction_t
*instruction
)
2129 switch ((opcode
>> 4) & 0x0f) {
2146 hint
= "HINT (UNRECOGNIZED)";
2150 snprintf(instruction
->text
, 128,
2151 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2152 address
, opcode
, hint
);
2157 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2158 arm_instruction_t
*instruction
)
2160 unsigned cond
= (opcode
>> 4) & 0x0f;
2161 char *x
= "", *y
= "", *z
= "";
2164 z
= (opcode
& 0x02) ? "T" : "E";
2166 y
= (opcode
& 0x04) ? "T" : "E";
2168 x
= (opcode
& 0x08) ? "T" : "E";
2170 snprintf(instruction
->text
, 128,
2171 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2173 x
, y
, z
, arm_condition_strings
[cond
]);
2175 /* NOTE: strictly speaking, the next 1-4 instructions should
2176 * now be displayed with the relevant conditional suffix...
2182 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2184 /* clear fields, to avoid confusion */
2185 memset(instruction
, 0, sizeof(arm_instruction_t
));
2186 instruction
->opcode
= opcode
;
2187 instruction
->instruction_size
= 2;
2189 if ((opcode
& 0xe000) == 0x0000)
2191 /* add/substract register or immediate */
2192 if ((opcode
& 0x1800) == 0x1800)
2193 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2194 /* shift by immediate */
2196 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2199 /* Add/substract/compare/move immediate */
2200 if ((opcode
& 0xe000) == 0x2000)
2202 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2205 /* Data processing instructions */
2206 if ((opcode
& 0xf800) == 0x4000)
2208 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2211 /* Load from literal pool */
2212 if ((opcode
& 0xf800) == 0x4800)
2214 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2217 /* Load/Store register offset */
2218 if ((opcode
& 0xf000) == 0x5000)
2220 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2223 /* Load/Store immediate offset */
2224 if (((opcode
& 0xe000) == 0x6000)
2225 ||((opcode
& 0xf000) == 0x8000))
2227 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2230 /* Load/Store from/to stack */
2231 if ((opcode
& 0xf000) == 0x9000)
2233 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2237 if ((opcode
& 0xf000) == 0xa000)
2239 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2243 if ((opcode
& 0xf000) == 0xb000)
2245 switch ((opcode
>> 8) & 0x0f) {
2247 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2252 return evaluate_cb_thumb(opcode
, address
, instruction
);
2254 return evaluate_extend_thumb(opcode
, address
, instruction
);
2259 return evaluate_load_store_multiple_thumb(opcode
, address
,
2262 return evaluate_cps_thumb(opcode
, address
, instruction
);
2264 if ((opcode
& 0x00c0) == 0x0080)
2266 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2268 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2270 if (opcode
& 0x000f)
2271 return evaluate_ifthen_thumb(opcode
, address
,
2274 return evaluate_hint_thumb(opcode
, address
,
2278 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2279 snprintf(instruction
->text
, 128,
2280 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2285 /* Load/Store multiple */
2286 if ((opcode
& 0xf000) == 0xc000)
2288 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2291 /* Conditional branch + SWI */
2292 if ((opcode
& 0xf000) == 0xd000)
2294 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2297 if ((opcode
& 0xe000) == 0xe000)
2299 /* Undefined instructions */
2300 if ((opcode
& 0xf801) == 0xe801)
2302 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2303 snprintf(instruction
->text
, 128,
2304 "0x%8.8" PRIx32
" 0x%8.8x\t"
2305 "UNDEFINED INSTRUCTION",
2310 { /* Branch to offset */
2311 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2315 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2319 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2320 arm_instruction_t
*instruction
, char *cp
)
2323 unsigned b21
= 1 << 21;
2324 unsigned b22
= 1 << 22;
2326 /* instead of combining two smaller 16-bit branch instructions,
2327 * Thumb2 uses only one larger 32-bit instruction.
2329 offset
= opcode
& 0x7ff;
2330 offset
|= (opcode
& 0x03ff0000) >> 5;
2331 if (opcode
& (1 << 26)) {
2332 offset
|= 0xff << 23;
2333 if ((opcode
& (1 << 11)) == 0)
2335 if ((opcode
& (1 << 13)) == 0)
2338 if (opcode
& (1 << 11))
2340 if (opcode
& (1 << 13))
2348 address
+= offset
<< 1;
2350 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2351 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2352 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2353 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2354 (opcode
& (1 << 14)) ? "BL" : "B.W",
2360 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2361 arm_instruction_t
*instruction
, char *cp
)
2364 unsigned b17
= 1 << 17;
2365 unsigned b18
= 1 << 18;
2366 unsigned cond
= (opcode
>> 22) & 0x0f;
2368 offset
= opcode
& 0x7ff;
2369 offset
|= (opcode
& 0x003f0000) >> 5;
2370 if (opcode
& (1 << 26)) {
2371 offset
|= 0xffff << 19;
2372 if ((opcode
& (1 << 11)) == 0)
2374 if ((opcode
& (1 << 13)) == 0)
2377 if (opcode
& (1 << 11))
2379 if (opcode
& (1 << 13))
2386 address
+= offset
<< 1;
2388 instruction
->type
= ARM_B
;
2389 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2390 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2391 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2392 arm_condition_strings
[cond
],
2398 static const char *special_name(int number
)
2400 char *special
= "(RESERVED)";
2431 special
= "primask";
2434 special
= "basepri";
2437 special
= "basepri_max";
2440 special
= "faultmask";
2443 special
= "control";
2449 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2450 arm_instruction_t
*instruction
, char *cp
)
2452 const char *mnemonic
;
2454 if (opcode
& 0x0700) {
2455 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2456 strcpy(cp
, "UNDEFINED");
2460 if (opcode
& 0x00f0) {
2461 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2465 switch (opcode
& 0x0f) {
2470 mnemonic
= "YIELD.W";
2482 mnemonic
= "HINT.W (UNRECOGNIZED)";
2485 strcpy(cp
, mnemonic
);
2489 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2490 arm_instruction_t
*instruction
, char *cp
)
2492 const char *mnemonic
;
2494 switch ((opcode
>> 4) & 0x0f) {
2508 return ERROR_INVALID_ARGUMENTS
;
2510 strcpy(cp
, mnemonic
);
2514 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2515 arm_instruction_t
*instruction
, char *cp
)
2517 /* permanently undefined */
2518 if ((opcode
& 0x07f07000) == 0x07f02000) {
2519 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2520 strcpy(cp
, "UNDEFINED");
2524 switch ((opcode
>> 12) & 0x5) {
2527 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2531 if (((opcode
>> 23) & 0x07) != 0x07)
2532 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2533 if (opcode
& (1 << 26))
2538 switch ((opcode
>> 20) & 0x7f) {
2541 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2542 (int) (opcode
>> 16) & 0x0f);
2545 return t2ev_hint(opcode
, address
, instruction
, cp
);
2547 return t2ev_misc(opcode
, address
, instruction
, cp
);
2550 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
2551 special_name(opcode
& 0xff));
2556 return ERROR_INVALID_ARGUMENTS
;
2559 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
2560 arm_instruction_t
*instruction
, char *cp
)
2562 char *mnemonic
= NULL
;
2563 int rn
= (opcode
>> 16) & 0xf;
2564 int rd
= (opcode
>> 8) & 0xf;
2565 unsigned immed
= opcode
& 0xff;
2571 /* ARMv7-M: A5.3.2 Modified immediate constants */
2572 func
= (opcode
>> 11) & 0x0e;
2575 if (opcode
& (1 << 26))
2578 /* "Modified" immediates */
2579 switch (func
>> 1) {
2586 immed
+= immed
<< 16;
2589 immed
+= immed
<< 8;
2590 immed
+= immed
<< 16;
2594 immed
= ror(immed
, func
);
2597 if (opcode
& (1 << 20))
2600 switch ((opcode
>> 21) & 0xf) {
2603 instruction
->type
= ARM_TST
;
2609 instruction
->type
= ARM_AND
;
2614 instruction
->type
= ARM_BIC
;
2619 instruction
->type
= ARM_MOV
;
2624 instruction
->type
= ARM_ORR
;
2630 instruction
->type
= ARM_MVN
;
2634 // instruction->type = ARM_ORN;
2640 instruction
->type
= ARM_TEQ
;
2646 instruction
->type
= ARM_EOR
;
2652 instruction
->type
= ARM_CMN
;
2658 instruction
->type
= ARM_ADD
;
2664 instruction
->type
= ARM_ADC
;
2669 instruction
->type
= ARM_SBC
;
2674 instruction
->type
= ARM_CMP
;
2680 instruction
->type
= ARM_SUB
;
2686 instruction
->type
= ARM_RSB
;
2691 return ERROR_INVALID_ARGUMENTS
;
2695 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
2696 mnemonic
, suffix2
,rd
, immed
, immed
);
2698 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
2699 mnemonic
, suffix
, suffix2
,
2700 rd
, rn
, immed
, immed
);
2705 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
2706 arm_instruction_t
*instruction
, char *cp
)
2708 char *mnemonic
= NULL
;
2709 int rn
= (opcode
>> 16) & 0xf;
2710 int rd
= (opcode
>> 8) & 0xf;
2713 bool is_signed
= false;
2715 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
2716 if (opcode
& (1 << 26))
2719 switch ((opcode
>> 20) & 0x1f) {
2728 immed
|= (opcode
>> 4) & 0xf000;
2729 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
2737 /* move constant to top 16 bits of register */
2738 immed
|= (opcode
>> 4) & 0xf000;
2739 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
2746 /* signed/unsigned saturated add */
2747 immed
= (opcode
>> 6) & 0x03;
2748 immed
|= (opcode
>> 10) & 0x1c;
2749 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
2750 is_signed
? "S" : "U",
2751 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
2752 (opcode
& (1 << 21)) ? "ASR" : "LSL",
2753 immed
? immed
: 32);
2759 /* signed/unsigned bitfield extract */
2760 immed
= (opcode
>> 6) & 0x03;
2761 immed
|= (opcode
>> 10) & 0x1c;
2762 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
2763 is_signed
? "S" : "U",
2765 (int) (opcode
& 0x1f) + 1);
2768 immed
= (opcode
>> 6) & 0x03;
2769 immed
|= (opcode
>> 10) & 0x1c;
2770 if (rn
== 0xf) /* bitfield clear */
2771 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
2773 (int) (opcode
& 0x1f) + 1 - immed
);
2774 else /* bitfield insert */
2775 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
2777 (int) (opcode
& 0x1f) + 1 - immed
);
2780 return ERROR_INVALID_ARGUMENTS
;
2783 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
2784 rd
, rn
, immed
, immed
);
2788 address
= thumb_alignpc4(address
);
2793 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
2794 * not hiding the pc-relative stuff will sometimes be useful.
2796 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
2800 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
2801 arm_instruction_t
*instruction
, char *cp
)
2803 unsigned op
= (opcode
>> 20) & 0xf;
2809 unsigned rn
= (opcode
>> 16) & 0x0f;
2810 unsigned rt
= (opcode
>> 12) & 0x0f;
2813 return ERROR_INVALID_ARGUMENTS
;
2815 if (opcode
& 0x0800)
2850 return ERROR_INVALID_ARGUMENTS
;
2853 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
2854 size
, rt
, rn
, (int) opcode
& 0x0f,
2855 (int) (opcode
>> 4) & 0x03);
2859 immed
= opcode
& 0x0fff;
2860 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
2861 size
, rt
, rn
, immed
, immed
);
2865 immed
= opcode
& 0x00ff;
2867 switch (opcode
& 0x700) {
2873 return ERROR_INVALID_ARGUMENTS
;
2876 /* two indexed modes will write back rn */
2877 if (opcode
& 0x100) {
2878 if (opcode
& 0x400) /* pre-indexed */
2880 else { /* post-indexed */
2886 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
2887 size
, suffix
, rt
, rn
, p1
,
2888 (opcode
& 0x200) ? "" : "-",
2893 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
2894 arm_instruction_t
*instruction
, char *cp
)
2896 int ra
= (opcode
>> 12) & 0xf;
2898 switch (opcode
& 0x007000f0) {
2901 sprintf(cp
, "MUL\tr%d, r%d, r%d",
2902 (int) (opcode
>> 8) & 0xf,
2903 (int) (opcode
>> 16) & 0xf,
2904 (int) (opcode
>> 0) & 0xf);
2906 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
2907 (int) (opcode
>> 8) & 0xf,
2908 (int) (opcode
>> 16) & 0xf,
2909 (int) (opcode
>> 0) & 0xf, ra
);
2912 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
2913 (int) (opcode
>> 8) & 0xf,
2914 (int) (opcode
>> 16) & 0xf,
2915 (int) (opcode
>> 0) & 0xf, ra
);
2918 return ERROR_INVALID_ARGUMENTS
;
2923 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
2924 arm_instruction_t
*instruction
, char *cp
)
2926 int op
= (opcode
>> 4) & 0xf;
2927 char *infix
= "MUL";
2929 op
+= (opcode
>> 16) & 0x70;
2937 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
2938 (op
& 0x20) ? 'U' : 'S',
2940 (int) (opcode
>> 12) & 0xf,
2941 (int) (opcode
>> 8) & 0xf,
2942 (int) (opcode
>> 16) & 0xf,
2943 (int) (opcode
>> 0) & 0xf);
2947 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
2948 (op
& 0x20) ? 'U' : 'S',
2949 (int) (opcode
>> 8) & 0xf,
2950 (int) (opcode
>> 16) & 0xf,
2951 (int) (opcode
>> 0) & 0xf);
2954 return ERROR_INVALID_ARGUMENTS
;
2960 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
2961 arm_instruction_t
*instruction
, char *cp
)
2963 int rn
= (opcode
>> 16) & 0xf;
2964 int op
= (opcode
>> 22) & 0x6;
2965 int t
= (opcode
>> 21) & 1;
2966 unsigned registers
= opcode
& 0xffff;
2968 if (opcode
& (1 << 20))
2973 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
2977 sprintf(cp
, "POP.W\t");
2979 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
2983 sprintf(cp
, "PUSH.W\t");
2985 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
2988 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
2991 return ERROR_INVALID_ARGUMENTS
;
2996 for (t
= 0; registers
; t
++, registers
>>= 1) {
2997 if ((registers
& 1) == 0)
3000 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3009 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3010 arm_instruction_t
*instruction
, char *cp
)
3012 int op
= (opcode
>> 21) & 0xf;
3013 int rd
= (opcode
>> 8) & 0xf;
3014 int rn
= (opcode
>> 16) & 0xf;
3015 int type
= (opcode
>> 4) & 0x3;
3016 int immed
= (opcode
>> 6) & 0x3;
3020 immed
|= (opcode
>> 10) & 0x7;
3021 if (opcode
& (1 << 21))
3027 if (!(opcode
& (1 << 21)))
3028 return ERROR_INVALID_ARGUMENTS
;
3029 instruction
->type
= ARM_TST
;
3033 instruction
->type
= ARM_AND
;
3037 instruction
->type
= ARM_BIC
;
3042 instruction
->type
= ARM_MOV
;
3046 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3048 (int) (opcode
& 0xf));
3061 sprintf(cp
, "RRX%s.W\tr%d, r%d",
3063 (int) (opcode
& 0xf));
3071 instruction
->type
= ARM_ORR
;
3077 instruction
->type
= ARM_MVN
;
3082 // instruction->type = ARM_ORN;
3088 if (!(opcode
& (1 << 21)))
3089 return ERROR_INVALID_ARGUMENTS
;
3090 instruction
->type
= ARM_TEQ
;
3094 instruction
->type
= ARM_EOR
;
3099 if (!(opcode
& (1 << 21)))
3100 return ERROR_INVALID_ARGUMENTS
;
3101 instruction
->type
= ARM_CMN
;
3105 instruction
->type
= ARM_ADD
;
3109 instruction
->type
= ARM_ADC
;
3113 instruction
->type
= ARM_SBC
;
3118 if (!(opcode
& (1 << 21)))
3119 return ERROR_INVALID_ARGUMENTS
;
3120 instruction
->type
= ARM_CMP
;
3124 instruction
->type
= ARM_SUB
;
3128 instruction
->type
= ARM_RSB
;
3132 return ERROR_INVALID_ARGUMENTS
;
3135 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3136 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3161 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3165 sprintf(cp
, "%s%s.W\tr%d, r%d",
3166 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3170 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3171 mnemonic
, suffix
, rd
,
3172 (int) (opcode
& 0xf), immed
? immed
: 32);
3176 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3177 arm_instruction_t
*instruction
, char *cp
)
3182 if (((opcode
>> 4) & 0xf) == 0) {
3183 switch ((opcode
>> 21) & 0x7) {
3197 return ERROR_INVALID_ARGUMENTS
;
3200 instruction
->type
= ARM_MOV
;
3201 if (opcode
& (1 << 20))
3203 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3205 (int) (opcode
>> 8) & 0xf,
3206 (int) (opcode
>> 16) & 0xf,
3207 (int) (opcode
>> 0) & 0xf);
3209 } else if (opcode
& (1 << 7)) {
3210 switch ((opcode
>> 20) & 0xf) {
3215 switch ((opcode
>> 4) & 0x3) {
3217 suffix
= ", ROR #8";
3220 suffix
= ", ROR #16";
3223 suffix
= ", ROR #24";
3226 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3227 (opcode
& (1 << 24)) ? 'U' : 'S',
3228 (opcode
& (1 << 26)) ? 'B' : 'H',
3229 (int) (opcode
>> 8) & 0xf,
3230 (int) (opcode
>> 0) & 0xf,
3237 if (opcode
& (1 << 6))
3238 return ERROR_INVALID_ARGUMENTS
;
3239 if (((opcode
>> 12) & 0xf) != 0xf)
3240 return ERROR_INVALID_ARGUMENTS
;
3241 if (!(opcode
& (1 << 20)))
3242 return ERROR_INVALID_ARGUMENTS
;
3244 switch (((opcode
>> 19) & 0x04)
3245 | ((opcode
>> 4) & 0x3)) {
3250 mnemonic
= "REV16.W";
3256 mnemonic
= "REVSH.W";
3262 return ERROR_INVALID_ARGUMENTS
;
3264 sprintf(cp
, "%s\tr%d, r%d",
3266 (int) (opcode
>> 8) & 0xf,
3267 (int) (opcode
>> 0) & 0xf);
3270 return ERROR_INVALID_ARGUMENTS
;
3277 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3278 arm_instruction_t
*instruction
, char *cp
)
3280 int rn
= (opcode
>> 16) & 0xf;
3283 instruction
->type
= ARM_LDR
;
3286 immed
= opcode
& 0x0fff;
3287 if ((opcode
& (1 << 23)) == 0)
3289 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3290 (int) (opcode
>> 12) & 0xf,
3291 thumb_alignpc4(address
) + immed
);
3295 if (opcode
& (1 << 23)) {
3296 immed
= opcode
& 0x0fff;
3297 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3298 (int) (opcode
>> 12) & 0xf,
3303 if (!(opcode
& (0x3f << 6))) {
3304 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3305 (int) (opcode
>> 12) & 0xf,
3307 (int) (opcode
>> 0) & 0xf,
3308 (int) (opcode
>> 4) & 0x3);
3313 if (((opcode
>> 8) & 0xf) == 0xe) {
3314 immed
= opcode
& 0x00ff;
3316 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3317 (int) (opcode
>> 12) & 0xf,
3322 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3323 char *p1
= "]", *p2
= "";
3325 if (!(opcode
& 0x0500))
3326 return ERROR_INVALID_ARGUMENTS
;
3328 immed
= opcode
& 0x00ff;
3330 /* two indexed modes will write back rn */
3331 if (opcode
& 0x100) {
3332 if (opcode
& 0x400) /* pre-indexed */
3334 else { /* post-indexed */
3340 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3341 (int) (opcode
>> 12) & 0xf,
3343 (opcode
& 0x200) ? "" : "-",
3348 return ERROR_INVALID_ARGUMENTS
;
3351 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3352 arm_instruction_t
*instruction
, char *cp
)
3354 int rn
= (opcode
>> 16) & 0xf;
3355 int rt
= (opcode
>> 12) & 0xf;
3356 int op2
= (opcode
>> 6) & 0x3f;
3358 char *p1
= "", *p2
= "]";
3361 switch ((opcode
>> 23) & 0x3) {
3363 if ((rn
& rt
) == 0xf) {
3365 immed
= opcode
& 0xfff;
3366 address
= thumb_alignpc4(address
);
3367 if (opcode
& (1 << 23))
3371 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
3375 if (rn
== 0x0f && rt
!= 0x0f) {
3377 immed
= opcode
& 0xfff;
3378 address
= thumb_alignpc4(address
);
3379 if (opcode
& (1 << 23))
3383 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
3389 if ((op2
& 0x3c) == 0x38) {
3390 immed
= opcode
& 0xff;
3391 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3392 rt
, rn
, immed
, immed
);
3395 if ((op2
& 0x3c) == 0x30) {
3397 immed
= opcode
& 0xff;
3400 p1
= (opcode
& (1 << 21)) ? "W" : "";
3401 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3402 p1
, rn
, immed
, immed
);
3407 immed
= opcode
& 0xff;
3408 if (!(opcode
& 0x200))
3411 /* two indexed modes will write back rn */
3412 if (opcode
& 0x100) {
3413 if (opcode
& 0x400) /* pre-indexed */
3415 else { /* post-indexed */
3421 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3422 mnemonic
, rt
, rn
, p1
,
3426 if ((op2
& 0x24) == 0x24) {
3428 goto ldrxb_immediate_t3
;
3431 int rm
= opcode
& 0xf;
3434 sprintf(cp
, "PLD\t");
3436 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
3437 immed
= (opcode
>> 4) & 0x3;
3439 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3444 if ((rn
& rt
) == 0xf)
3447 immed
= opcode
& 0xfff;
3448 goto preload_immediate
;
3452 mnemonic
= "LDRB.W";
3453 immed
= opcode
& 0xfff;
3454 goto ldrxb_immediate_t2
;
3456 if ((rn
& rt
) == 0xf) {
3457 immed
= opcode
& 0xfff;
3458 address
= thumb_alignpc4(address
);
3459 if (opcode
& (1 << 23))
3463 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
3466 if (rn
== 0xf && rt
!= 0xf) {
3468 immed
= opcode
& 0xfff;
3469 address
= thumb_alignpc4(address
);
3470 if (opcode
& (1 << 23))
3474 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
3479 if ((op2
& 0x3c) == 0x38) {
3480 immed
= opcode
& 0xff;
3481 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
3482 rt
, rn
, immed
, immed
);
3485 if ((op2
& 0x3c) == 0x30) {
3487 immed
= opcode
& 0xff;
3488 immed
= -immed
; // pli
3489 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
3494 goto ldrxb_immediate_t3
;
3496 if ((op2
& 0x24) == 0x24) {
3498 goto ldrxb_immediate_t3
;
3501 int rm
= opcode
& 0xf;
3504 sprintf(cp
, "PLI\t");
3506 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
3507 immed
= (opcode
>> 4) & 0x3;
3509 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3515 immed
= opcode
& 0xfff;
3516 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3" PRIx32
,
3522 immed
= opcode
& 0xfff;
3524 goto ldrxb_immediate_t2
;
3527 return ERROR_INVALID_ARGUMENTS
;
3530 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
3531 arm_instruction_t
*instruction
, char *cp
)
3533 int rn
= (opcode
>> 16) & 0xf;
3534 int rt
= (opcode
>> 12) & 0xf;
3535 int op2
= (opcode
>> 6) & 0x3f;
3540 sprintf(cp
, "HINT (UNALLOCATED)");
3544 if (opcode
& (1 << 24))
3547 if ((opcode
& (1 << 23)) == 0) {
3550 immed
= opcode
& 0xfff;
3551 address
= thumb_alignpc4(address
);
3552 if (opcode
& (1 << 23))
3556 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
3561 int rm
= opcode
& 0xf;
3563 immed
= (opcode
>> 4) & 0x3;
3564 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
3565 sign
, rt
, rn
, rm
, immed
);
3568 if ((op2
& 0x3c) == 0x38) {
3569 immed
= opcode
& 0xff;
3570 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
3571 sign
, rt
, rn
, immed
, immed
);
3574 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
3575 char *p1
= "", *p2
= "]";
3577 immed
= opcode
& 0xff;
3578 if (!(opcode
& 0x200))
3581 /* two indexed modes will write back rn */
3582 if (opcode
& 0x100) {
3583 if (opcode
& 0x400) /* pre-indexed */
3585 else { /* post-indexed */
3590 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3591 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
3598 immed
= opcode
& 0xfff;
3599 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
3600 sign
, *sign
? "" : ".W",
3601 rt
, rn
, immed
, immed
);
3605 return ERROR_INVALID_ARGUMENTS
;
3609 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
3610 * always set. That means eventual arm_simulate_step() support for Thumb2
3611 * will need work in this area.
3613 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
3620 /* clear low bit ... it's set on function pointers */
3623 /* clear fields, to avoid confusion */
3624 memset(instruction
, 0, sizeof(arm_instruction_t
));
3626 /* read first halfword, see if this is the only one */
3627 retval
= target_read_u16(target
, address
, &op
);
3628 if (retval
!= ERROR_OK
)
3631 switch (op
& 0xf800) {
3635 /* 32-bit instructions */
3636 instruction
->instruction_size
= 4;
3638 retval
= target_read_u16(target
, address
+ 2, &op
);
3639 if (retval
!= ERROR_OK
)
3642 instruction
->opcode
= opcode
;
3645 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
3646 return thumb_evaluate_opcode(op
, address
, instruction
);
3649 snprintf(instruction
->text
, 128,
3650 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
3652 cp
= strchr(instruction
->text
, 0);
3653 retval
= ERROR_FAIL
;
3655 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
3656 if ((opcode
& 0x1a008000) == 0x10000000)
3657 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
3659 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
3660 else if ((opcode
& 0x1a008000) == 0x12000000)
3661 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
3663 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
3664 else if ((opcode
& 0x18008000) == 0x10008000)
3665 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
3667 /* ARMv7-M: A5.3.5 Load/store multiple */
3668 else if ((opcode
& 0x1e400000) == 0x08000000)
3669 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
3671 /* ARMv7-M: A5.3.7 Load word */
3672 else if ((opcode
& 0x1f700000) == 0x18500000)
3673 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
3675 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
3676 else if ((opcode
& 0x1e700000) == 0x18300000)
3677 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
3679 /* ARMv7-M: A5.3.9 Load byte, memory hints */
3680 else if ((opcode
& 0x1e700000) == 0x18100000)
3681 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
3683 /* ARMv7-M: A5.3.10 Store single data item */
3684 else if ((opcode
& 0x1f100000) == 0x18000000)
3685 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
3687 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
3688 else if ((opcode
& 0x1e000000) == 0x0a000000)
3689 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
3691 /* ARMv7-M: A5.3.12 Data processing (register)
3692 * and A5.3.13 Miscellaneous operations
3694 else if ((opcode
& 0x1f000000) == 0x1a000000)
3695 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
3697 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
3698 else if ((opcode
& 0x1f800000) == 0x1b000000)
3699 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
3701 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
3702 else if ((opcode
& 0x1f800000) == 0x1b800000)
3703 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
3705 /* FIXME decode more 32-bit instructions */
3707 if (retval
== ERROR_OK
)
3710 if (retval
== ERROR_INVALID_ARGUMENTS
) {
3711 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3712 strcpy(cp
, "UNDEFINED OPCODE");
3716 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
3719 strcpy(cp
, "(32-bit Thumb2 ...)");
3723 int arm_access_size(arm_instruction_t
*instruction
)
3725 if ((instruction
->type
== ARM_LDRB
)
3726 || (instruction
->type
== ARM_LDRBT
)
3727 || (instruction
->type
== ARM_LDRSB
)
3728 || (instruction
->type
== ARM_STRB
)
3729 || (instruction
->type
== ARM_STRBT
))
3733 else if ((instruction
->type
== ARM_LDRH
)
3734 || (instruction
->type
== ARM_LDRSH
)
3735 || (instruction
->type
== ARM_STRH
))
3739 else if ((instruction
->type
== ARM_LDR
)
3740 || (instruction
->type
== ARM_LDRT
)
3741 || (instruction
->type
== ARM_STR
)
3742 || (instruction
->type
== ARM_STRT
))
3746 else if ((instruction
->type
== ARM_LDRD
)
3747 || (instruction
->type
== ARM_STRD
))
3753 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction
->type
);
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)