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 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1399 instruction
->type
= ARM_ADD
;
1403 instruction
->info
.data_proc
.Rd
= Rd
;
1404 instruction
->info
.data_proc
.Rn
= Rn
;
1405 instruction
->info
.data_proc
.S
= 1;
1409 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1410 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1411 snprintf(instruction
->text
, 128,
1412 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1413 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1417 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1418 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1419 snprintf(instruction
->text
, 128,
1420 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1421 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1427 int evaluate_shift_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1429 uint8_t Rd
= (opcode
>> 0) & 0x7;
1430 uint8_t Rm
= (opcode
>> 3) & 0x7;
1431 uint8_t imm
= (opcode
>> 6) & 0x1f;
1432 uint8_t opc
= (opcode
>> 11) & 0x3;
1433 char *mnemonic
= NULL
;
1438 instruction
->type
= ARM_MOV
;
1440 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1443 instruction
->type
= ARM_MOV
;
1445 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1448 instruction
->type
= ARM_MOV
;
1450 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1454 if ((imm
== 0) && (opc
!= 0))
1457 instruction
->info
.data_proc
.Rd
= Rd
;
1458 instruction
->info
.data_proc
.Rn
= -1;
1459 instruction
->info
.data_proc
.S
= 1;
1461 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1462 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1463 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1465 snprintf(instruction
->text
, 128,
1466 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1467 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1472 int evaluate_data_proc_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1474 uint8_t imm
= opcode
& 0xff;
1475 uint8_t Rd
= (opcode
>> 8) & 0x7;
1476 uint32_t opc
= (opcode
>> 11) & 0x3;
1477 char *mnemonic
= NULL
;
1479 instruction
->info
.data_proc
.Rd
= Rd
;
1480 instruction
->info
.data_proc
.Rn
= Rd
;
1481 instruction
->info
.data_proc
.S
= 1;
1482 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1483 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1488 instruction
->type
= ARM_MOV
;
1490 instruction
->info
.data_proc
.Rn
= -1;
1493 instruction
->type
= ARM_CMP
;
1495 instruction
->info
.data_proc
.Rd
= -1;
1498 instruction
->type
= ARM_ADD
;
1502 instruction
->type
= ARM_SUB
;
1507 snprintf(instruction
->text
, 128,
1508 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1509 address
, opcode
, mnemonic
, Rd
, imm
);
1514 int evaluate_data_proc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1516 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1517 char *mnemonic
= NULL
;
1520 high_reg
= (opcode
& 0x0400) >> 10;
1521 op
= (opcode
& 0x03C0) >> 6;
1523 Rd
= (opcode
& 0x0007);
1524 Rm
= (opcode
& 0x0038) >> 3;
1525 H1
= (opcode
& 0x0080) >> 7;
1526 H2
= (opcode
& 0x0040) >> 6;
1528 instruction
->info
.data_proc
.Rd
= Rd
;
1529 instruction
->info
.data_proc
.Rn
= Rd
;
1530 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1531 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1532 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1543 instruction
->type
= ARM_ADD
;
1547 instruction
->type
= ARM_CMP
;
1551 instruction
->type
= ARM_MOV
;
1557 if ((opcode
& 0x7) == 0x0)
1559 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1562 instruction
->type
= ARM_BLX
;
1563 snprintf(instruction
->text
, 128,
1565 " 0x%4.4x \tBLX\tr%i",
1566 address
, opcode
, Rm
);
1570 instruction
->type
= ARM_BX
;
1571 snprintf(instruction
->text
, 128,
1573 " 0x%4.4x \tBX\tr%i",
1574 address
, opcode
, Rm
);
1579 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1580 snprintf(instruction
->text
, 128,
1583 "UNDEFINED INSTRUCTION",
1595 instruction
->type
= ARM_AND
;
1599 instruction
->type
= ARM_EOR
;
1603 instruction
->type
= ARM_MOV
;
1605 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1606 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1607 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1608 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1611 instruction
->type
= ARM_MOV
;
1613 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1614 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1615 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1616 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1619 instruction
->type
= ARM_MOV
;
1621 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1622 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1623 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1624 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1627 instruction
->type
= ARM_ADC
;
1631 instruction
->type
= ARM_SBC
;
1635 instruction
->type
= ARM_MOV
;
1637 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1638 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1639 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1640 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1643 instruction
->type
= ARM_TST
;
1647 instruction
->type
= ARM_RSB
;
1649 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1650 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1651 instruction
->info
.data_proc
.Rn
= Rm
;
1654 instruction
->type
= ARM_CMP
;
1658 instruction
->type
= ARM_CMN
;
1662 instruction
->type
= ARM_ORR
;
1666 instruction
->type
= ARM_MUL
;
1670 instruction
->type
= ARM_BIC
;
1674 instruction
->type
= ARM_MVN
;
1681 snprintf(instruction
->text
, 128,
1682 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
1684 address
, opcode
, mnemonic
, Rd
, Rm
);
1686 snprintf(instruction
->text
, 128,
1687 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
1688 address
, opcode
, mnemonic
, Rd
, Rm
);
1693 /* PC-relative data addressing is word-aligned even with Thumb */
1694 static inline uint32_t thumb_alignpc4(uint32_t addr
)
1696 return (addr
+ 4) & ~3;
1699 int evaluate_load_literal_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1702 uint8_t Rd
= (opcode
>> 8) & 0x7;
1704 instruction
->type
= ARM_LDR
;
1705 immediate
= opcode
& 0x000000ff;
1708 instruction
->info
.load_store
.Rd
= Rd
;
1709 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
1710 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1711 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1712 instruction
->info
.load_store
.offset
.offset
= immediate
;
1714 snprintf(instruction
->text
, 128,
1715 "0x%8.8" PRIx32
" 0x%4.4x \t"
1716 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
1717 address
, opcode
, Rd
, immediate
,
1718 thumb_alignpc4(address
) + immediate
);
1723 int evaluate_load_store_reg_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1725 uint8_t Rd
= (opcode
>> 0) & 0x7;
1726 uint8_t Rn
= (opcode
>> 3) & 0x7;
1727 uint8_t Rm
= (opcode
>> 6) & 0x7;
1728 uint8_t opc
= (opcode
>> 9) & 0x7;
1729 char *mnemonic
= NULL
;
1734 instruction
->type
= ARM_STR
;
1738 instruction
->type
= ARM_STRH
;
1742 instruction
->type
= ARM_STRB
;
1746 instruction
->type
= ARM_LDRSB
;
1750 instruction
->type
= ARM_LDR
;
1754 instruction
->type
= ARM_LDRH
;
1758 instruction
->type
= ARM_LDRB
;
1762 instruction
->type
= ARM_LDRSH
;
1767 snprintf(instruction
->text
, 128,
1768 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
1769 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
1771 instruction
->info
.load_store
.Rd
= Rd
;
1772 instruction
->info
.load_store
.Rn
= Rn
;
1773 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1774 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
1775 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1780 int evaluate_load_store_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1782 uint32_t offset
= (opcode
>> 6) & 0x1f;
1783 uint8_t Rd
= (opcode
>> 0) & 0x7;
1784 uint8_t Rn
= (opcode
>> 3) & 0x7;
1785 uint32_t L
= opcode
& (1 << 11);
1786 uint32_t B
= opcode
& (1 << 12);
1793 instruction
->type
= ARM_LDR
;
1798 instruction
->type
= ARM_STR
;
1802 if ((opcode
&0xF000) == 0x8000)
1813 snprintf(instruction
->text
, 128,
1814 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
1815 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
1817 instruction
->info
.load_store
.Rd
= Rd
;
1818 instruction
->info
.load_store
.Rn
= Rn
;
1819 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1820 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1821 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
1826 int evaluate_load_store_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1828 uint32_t offset
= opcode
& 0xff;
1829 uint8_t Rd
= (opcode
>> 8) & 0x7;
1830 uint32_t L
= opcode
& (1 << 11);
1835 instruction
->type
= ARM_LDR
;
1840 instruction
->type
= ARM_STR
;
1844 snprintf(instruction
->text
, 128,
1845 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
1846 address
, opcode
, mnemonic
, Rd
, offset
*4);
1848 instruction
->info
.load_store
.Rd
= Rd
;
1849 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
1850 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1851 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1852 instruction
->info
.load_store
.offset
.offset
= offset
*4;
1857 int evaluate_add_sp_pc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1859 uint32_t imm
= opcode
& 0xff;
1860 uint8_t Rd
= (opcode
>> 8) & 0x7;
1862 uint32_t SP
= opcode
& (1 << 11);
1865 instruction
->type
= ARM_ADD
;
1878 snprintf(instruction
->text
, 128,
1879 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
1880 address
, opcode
, Rd
, reg_name
, imm
* 4);
1882 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1883 instruction
->info
.data_proc
.Rd
= Rd
;
1884 instruction
->info
.data_proc
.Rn
= Rn
;
1885 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1890 int evaluate_adjust_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1892 uint32_t imm
= opcode
& 0x7f;
1893 uint8_t opc
= opcode
& (1 << 7);
1899 instruction
->type
= ARM_SUB
;
1904 instruction
->type
= ARM_ADD
;
1908 snprintf(instruction
->text
, 128,
1909 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
1910 address
, opcode
, mnemonic
, imm
*4);
1912 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1913 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
1914 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
1915 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1920 int evaluate_breakpoint_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1922 uint32_t imm
= opcode
& 0xff;
1924 instruction
->type
= ARM_BKPT
;
1926 snprintf(instruction
->text
, 128,
1927 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
1928 address
, opcode
, imm
);
1933 int evaluate_load_store_multiple_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1935 uint32_t reg_list
= opcode
& 0xff;
1936 uint32_t L
= opcode
& (1 << 11);
1937 uint32_t R
= opcode
& (1 << 8);
1938 uint8_t Rn
= (opcode
>> 8) & 7;
1939 uint8_t addr_mode
= 0 /* IA */;
1943 char ptr_name
[7] = "";
1946 if ((opcode
& 0xf000) == 0xc000)
1947 { /* generic load/store multiple */
1952 instruction
->type
= ARM_LDM
;
1954 if (opcode
& (1 << Rn
))
1959 instruction
->type
= ARM_STM
;
1962 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
1969 instruction
->type
= ARM_LDM
;
1972 reg_list
|= (1 << 15) /*PC*/;
1976 instruction
->type
= ARM_STM
;
1978 addr_mode
= 3; /*DB*/
1980 reg_list
|= (1 << 14) /*LR*/;
1984 reg_names_p
= reg_names
;
1985 for (i
= 0; i
<= 15; i
++)
1987 if (reg_list
& (1 << i
))
1988 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
1990 if (reg_names_p
> reg_names
)
1991 reg_names_p
[-2] = '\0';
1992 else /* invalid op : no registers */
1993 reg_names
[0] = '\0';
1995 snprintf(instruction
->text
, 128,
1996 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
1997 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
1999 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2000 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2001 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2006 int evaluate_cond_branch_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2008 uint32_t offset
= opcode
& 0xff;
2009 uint8_t cond
= (opcode
>> 8) & 0xf;
2010 uint32_t target_address
;
2014 instruction
->type
= ARM_SWI
;
2015 snprintf(instruction
->text
, 128,
2016 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2017 address
, opcode
, offset
);
2020 else if (cond
== 0xe)
2022 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2023 snprintf(instruction
->text
, 128,
2024 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2029 /* sign extend 8-bit offset */
2030 if (offset
& 0x00000080)
2031 offset
= 0xffffff00 | offset
;
2033 target_address
= address
+ 4 + (offset
<< 1);
2035 snprintf(instruction
->text
, 128,
2036 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2038 arm_condition_strings
[cond
], target_address
);
2040 instruction
->type
= ARM_B
;
2041 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2042 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2047 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2048 arm_instruction_t
*instruction
)
2052 /* added in Thumb2 */
2053 offset
= (opcode
>> 3) & 0x1f;
2054 offset
|= (opcode
& 0x0200) >> 4;
2056 snprintf(instruction
->text
, 128,
2057 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2059 (opcode
& 0x0800) ? "N" : "",
2060 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2065 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2066 arm_instruction_t
*instruction
)
2068 /* added in ARMv6 */
2069 snprintf(instruction
->text
, 128,
2070 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2072 (opcode
& 0x0080) ? 'U' : 'S',
2073 (opcode
& 0x0040) ? 'B' : 'H',
2074 opcode
& 0x7, (opcode
>> 3) & 0x7);
2079 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2080 arm_instruction_t
*instruction
)
2082 /* added in ARMv6 */
2083 if ((opcode
& 0x0ff0) == 0x0650)
2084 snprintf(instruction
->text
, 128,
2085 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2087 (opcode
& 0x80) ? "BE" : "LE");
2088 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2089 snprintf(instruction
->text
, 128,
2090 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2092 (opcode
& 0x0010) ? 'D' : 'E',
2093 (opcode
& 0x0004) ? "A" : "",
2094 (opcode
& 0x0002) ? "I" : "",
2095 (opcode
& 0x0001) ? "F" : "");
2100 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2101 arm_instruction_t
*instruction
)
2105 /* added in ARMv6 */
2106 switch ((opcode
>> 6) & 3) {
2117 snprintf(instruction
->text
, 128,
2118 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2119 address
, opcode
, suffix
,
2120 opcode
& 0x7, (opcode
>> 3) & 0x7);
2125 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2126 arm_instruction_t
*instruction
)
2130 switch ((opcode
>> 4) & 0x0f) {
2147 hint
= "HINT (UNRECOGNIZED)";
2151 snprintf(instruction
->text
, 128,
2152 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2153 address
, opcode
, hint
);
2158 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2159 arm_instruction_t
*instruction
)
2161 unsigned cond
= (opcode
>> 4) & 0x0f;
2162 char *x
= "", *y
= "", *z
= "";
2165 z
= (opcode
& 0x02) ? "T" : "E";
2167 y
= (opcode
& 0x04) ? "T" : "E";
2169 x
= (opcode
& 0x08) ? "T" : "E";
2171 snprintf(instruction
->text
, 128,
2172 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2174 x
, y
, z
, arm_condition_strings
[cond
]);
2176 /* NOTE: strictly speaking, the next 1-4 instructions should
2177 * now be displayed with the relevant conditional suffix...
2183 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2185 /* clear fields, to avoid confusion */
2186 memset(instruction
, 0, sizeof(arm_instruction_t
));
2187 instruction
->opcode
= opcode
;
2188 instruction
->instruction_size
= 2;
2190 if ((opcode
& 0xe000) == 0x0000)
2192 /* add/substract register or immediate */
2193 if ((opcode
& 0x1800) == 0x1800)
2194 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2195 /* shift by immediate */
2197 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2200 /* Add/substract/compare/move immediate */
2201 if ((opcode
& 0xe000) == 0x2000)
2203 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2206 /* Data processing instructions */
2207 if ((opcode
& 0xf800) == 0x4000)
2209 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2212 /* Load from literal pool */
2213 if ((opcode
& 0xf800) == 0x4800)
2215 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2218 /* Load/Store register offset */
2219 if ((opcode
& 0xf000) == 0x5000)
2221 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2224 /* Load/Store immediate offset */
2225 if (((opcode
& 0xe000) == 0x6000)
2226 ||((opcode
& 0xf000) == 0x8000))
2228 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2231 /* Load/Store from/to stack */
2232 if ((opcode
& 0xf000) == 0x9000)
2234 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2238 if ((opcode
& 0xf000) == 0xa000)
2240 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2244 if ((opcode
& 0xf000) == 0xb000)
2246 switch ((opcode
>> 8) & 0x0f) {
2248 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2253 return evaluate_cb_thumb(opcode
, address
, instruction
);
2255 return evaluate_extend_thumb(opcode
, address
, instruction
);
2260 return evaluate_load_store_multiple_thumb(opcode
, address
,
2263 return evaluate_cps_thumb(opcode
, address
, instruction
);
2265 if ((opcode
& 0x00c0) == 0x0080)
2267 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2269 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2271 if (opcode
& 0x000f)
2272 return evaluate_ifthen_thumb(opcode
, address
,
2275 return evaluate_hint_thumb(opcode
, address
,
2279 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2280 snprintf(instruction
->text
, 128,
2281 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2286 /* Load/Store multiple */
2287 if ((opcode
& 0xf000) == 0xc000)
2289 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2292 /* Conditional branch + SWI */
2293 if ((opcode
& 0xf000) == 0xd000)
2295 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2298 if ((opcode
& 0xe000) == 0xe000)
2300 /* Undefined instructions */
2301 if ((opcode
& 0xf801) == 0xe801)
2303 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2304 snprintf(instruction
->text
, 128,
2305 "0x%8.8" PRIx32
" 0x%8.8x\t"
2306 "UNDEFINED INSTRUCTION",
2311 { /* Branch to offset */
2312 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2316 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2320 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2321 arm_instruction_t
*instruction
, char *cp
)
2324 unsigned b21
= 1 << 21;
2325 unsigned b22
= 1 << 22;
2327 /* instead of combining two smaller 16-bit branch instructions,
2328 * Thumb2 uses only one larger 32-bit instruction.
2330 offset
= opcode
& 0x7ff;
2331 offset
|= (opcode
& 0x03ff0000) >> 5;
2332 if (opcode
& (1 << 26)) {
2333 offset
|= 0xff << 23;
2334 if ((opcode
& (1 << 11)) == 0)
2336 if ((opcode
& (1 << 13)) == 0)
2339 if (opcode
& (1 << 11))
2341 if (opcode
& (1 << 13))
2349 address
+= offset
<< 1;
2351 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2352 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2353 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2354 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2355 (opcode
& (1 << 14)) ? "BL" : "B.W",
2361 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2362 arm_instruction_t
*instruction
, char *cp
)
2365 unsigned b17
= 1 << 17;
2366 unsigned b18
= 1 << 18;
2367 unsigned cond
= (opcode
>> 22) & 0x0f;
2369 offset
= opcode
& 0x7ff;
2370 offset
|= (opcode
& 0x003f0000) >> 5;
2371 if (opcode
& (1 << 26)) {
2372 offset
|= 0xffff << 19;
2373 if ((opcode
& (1 << 11)) == 0)
2375 if ((opcode
& (1 << 13)) == 0)
2378 if (opcode
& (1 << 11))
2380 if (opcode
& (1 << 13))
2387 address
+= offset
<< 1;
2389 instruction
->type
= ARM_B
;
2390 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2391 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2392 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2393 arm_condition_strings
[cond
],
2399 static const char *special_name(int number
)
2401 char *special
= "(RESERVED)";
2432 special
= "primask";
2435 special
= "basepri";
2438 special
= "basepri_max";
2441 special
= "faultmask";
2444 special
= "control";
2450 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2451 arm_instruction_t
*instruction
, char *cp
)
2453 const char *mnemonic
;
2455 if (opcode
& 0x0700) {
2456 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2457 strcpy(cp
, "UNDEFINED");
2461 if (opcode
& 0x00f0) {
2462 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2466 switch (opcode
& 0x0f) {
2471 mnemonic
= "YIELD.W";
2483 mnemonic
= "HINT.W (UNRECOGNIZED)";
2486 strcpy(cp
, mnemonic
);
2490 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2491 arm_instruction_t
*instruction
, char *cp
)
2493 const char *mnemonic
;
2495 switch ((opcode
>> 4) & 0x0f) {
2509 return ERROR_INVALID_ARGUMENTS
;
2511 strcpy(cp
, mnemonic
);
2515 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2516 arm_instruction_t
*instruction
, char *cp
)
2518 /* permanently undefined */
2519 if ((opcode
& 0x07f07000) == 0x07f02000) {
2520 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2521 strcpy(cp
, "UNDEFINED");
2525 switch ((opcode
>> 12) & 0x5) {
2528 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2532 if (((opcode
>> 23) & 0x07) != 0x07)
2533 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2534 if (opcode
& (1 << 26))
2539 switch ((opcode
>> 20) & 0x7f) {
2542 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2543 (int) (opcode
>> 16) & 0x0f);
2546 return t2ev_hint(opcode
, address
, instruction
, cp
);
2548 return t2ev_misc(opcode
, address
, instruction
, cp
);
2551 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
2552 special_name(opcode
& 0xff));
2557 return ERROR_INVALID_ARGUMENTS
;
2560 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
2561 arm_instruction_t
*instruction
, char *cp
)
2563 char *mnemonic
= NULL
;
2564 int rn
= (opcode
>> 16) & 0xf;
2565 int rd
= (opcode
>> 8) & 0xf;
2566 unsigned immed
= opcode
& 0xff;
2572 /* ARMv7-M: A5.3.2 Modified immediate constants */
2573 func
= (opcode
>> 11) & 0x0e;
2576 if (opcode
& (1 << 26))
2579 /* "Modified" immediates */
2580 switch (func
>> 1) {
2587 immed
+= immed
<< 16;
2590 immed
+= immed
<< 8;
2591 immed
+= immed
<< 16;
2595 immed
= ror(immed
, func
);
2598 if (opcode
& (1 << 20))
2601 switch ((opcode
>> 21) & 0xf) {
2604 instruction
->type
= ARM_TST
;
2610 instruction
->type
= ARM_AND
;
2615 instruction
->type
= ARM_BIC
;
2620 instruction
->type
= ARM_MOV
;
2625 instruction
->type
= ARM_ORR
;
2631 instruction
->type
= ARM_MVN
;
2635 // instruction->type = ARM_ORN;
2641 instruction
->type
= ARM_TEQ
;
2647 instruction
->type
= ARM_EOR
;
2653 instruction
->type
= ARM_CMN
;
2659 instruction
->type
= ARM_ADD
;
2665 instruction
->type
= ARM_ADC
;
2670 instruction
->type
= ARM_SBC
;
2675 instruction
->type
= ARM_CMP
;
2681 instruction
->type
= ARM_SUB
;
2687 instruction
->type
= ARM_RSB
;
2692 return ERROR_INVALID_ARGUMENTS
;
2696 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
2697 mnemonic
, suffix2
,rd
, immed
, immed
);
2699 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
2700 mnemonic
, suffix
, suffix2
,
2701 rd
, rn
, immed
, immed
);
2706 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
2707 arm_instruction_t
*instruction
, char *cp
)
2709 char *mnemonic
= NULL
;
2710 int rn
= (opcode
>> 16) & 0xf;
2711 int rd
= (opcode
>> 8) & 0xf;
2714 bool is_signed
= false;
2716 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
2717 if (opcode
& (1 << 26))
2720 switch ((opcode
>> 20) & 0x1f) {
2729 immed
|= (opcode
>> 4) & 0xf000;
2730 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
2738 /* move constant to top 16 bits of register */
2739 immed
|= (opcode
>> 4) & 0xf000;
2740 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
2747 /* signed/unsigned saturated add */
2748 immed
= (opcode
>> 6) & 0x03;
2749 immed
|= (opcode
>> 10) & 0x1c;
2750 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
2751 is_signed
? "S" : "U",
2752 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
2753 (opcode
& (1 << 21)) ? "ASR" : "LSL",
2754 immed
? immed
: 32);
2760 /* signed/unsigned bitfield extract */
2761 immed
= (opcode
>> 6) & 0x03;
2762 immed
|= (opcode
>> 10) & 0x1c;
2763 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
2764 is_signed
? "S" : "U",
2766 (int) (opcode
& 0x1f) + 1);
2769 immed
= (opcode
>> 6) & 0x03;
2770 immed
|= (opcode
>> 10) & 0x1c;
2771 if (rn
== 0xf) /* bitfield clear */
2772 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
2774 (int) (opcode
& 0x1f) + 1 - immed
);
2775 else /* bitfield insert */
2776 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
2778 (int) (opcode
& 0x1f) + 1 - immed
);
2781 return ERROR_INVALID_ARGUMENTS
;
2784 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
2785 rd
, rn
, immed
, immed
);
2789 address
= thumb_alignpc4(address
);
2794 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
2795 * not hiding the pc-relative stuff will sometimes be useful.
2797 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
2801 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
2802 arm_instruction_t
*instruction
, char *cp
)
2804 unsigned op
= (opcode
>> 20) & 0xf;
2810 unsigned rn
= (opcode
>> 16) & 0x0f;
2811 unsigned rt
= (opcode
>> 12) & 0x0f;
2814 return ERROR_INVALID_ARGUMENTS
;
2816 if (opcode
& 0x0800)
2851 return ERROR_INVALID_ARGUMENTS
;
2854 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
2855 size
, rt
, rn
, (int) opcode
& 0x0f,
2856 (int) (opcode
>> 4) & 0x03);
2860 immed
= opcode
& 0x0fff;
2861 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
2862 size
, rt
, rn
, immed
, immed
);
2866 immed
= opcode
& 0x00ff;
2868 switch (opcode
& 0x700) {
2874 return ERROR_INVALID_ARGUMENTS
;
2877 /* two indexed modes will write back rn */
2878 if (opcode
& 0x100) {
2879 if (opcode
& 0x400) /* pre-indexed */
2881 else { /* post-indexed */
2887 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
2888 size
, suffix
, rt
, rn
, p1
,
2889 (opcode
& 0x200) ? "" : "-",
2894 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
2895 arm_instruction_t
*instruction
, char *cp
)
2897 int ra
= (opcode
>> 12) & 0xf;
2899 switch (opcode
& 0x007000f0) {
2902 sprintf(cp
, "MUL\tr%d, r%d, r%d",
2903 (int) (opcode
>> 8) & 0xf,
2904 (int) (opcode
>> 16) & 0xf,
2905 (int) (opcode
>> 0) & 0xf);
2907 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
2908 (int) (opcode
>> 8) & 0xf,
2909 (int) (opcode
>> 16) & 0xf,
2910 (int) (opcode
>> 0) & 0xf, ra
);
2913 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
2914 (int) (opcode
>> 8) & 0xf,
2915 (int) (opcode
>> 16) & 0xf,
2916 (int) (opcode
>> 0) & 0xf, ra
);
2919 return ERROR_INVALID_ARGUMENTS
;
2924 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
2925 arm_instruction_t
*instruction
, char *cp
)
2927 int op
= (opcode
>> 4) & 0xf;
2928 char *infix
= "MUL";
2930 op
+= (opcode
>> 16) & 0x70;
2938 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
2939 (op
& 0x20) ? 'U' : 'S',
2941 (int) (opcode
>> 12) & 0xf,
2942 (int) (opcode
>> 8) & 0xf,
2943 (int) (opcode
>> 16) & 0xf,
2944 (int) (opcode
>> 0) & 0xf);
2948 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
2949 (op
& 0x20) ? 'U' : 'S',
2950 (int) (opcode
>> 8) & 0xf,
2951 (int) (opcode
>> 16) & 0xf,
2952 (int) (opcode
>> 0) & 0xf);
2955 return ERROR_INVALID_ARGUMENTS
;
2961 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
2962 arm_instruction_t
*instruction
, char *cp
)
2964 int rn
= (opcode
>> 16) & 0xf;
2965 int op
= (opcode
>> 22) & 0x6;
2966 int t
= (opcode
>> 21) & 1;
2967 unsigned registers
= opcode
& 0xffff;
2969 if (opcode
& (1 << 20))
2974 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
2978 sprintf(cp
, "POP.W\t");
2980 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
2984 sprintf(cp
, "PUSH.W\t");
2986 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
2989 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
2992 return ERROR_INVALID_ARGUMENTS
;
2997 for (t
= 0; registers
; t
++, registers
>>= 1) {
2998 if ((registers
& 1) == 0)
3001 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3010 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3011 arm_instruction_t
*instruction
, char *cp
)
3013 int op
= (opcode
>> 21) & 0xf;
3014 int rd
= (opcode
>> 8) & 0xf;
3015 int rn
= (opcode
>> 16) & 0xf;
3016 int type
= (opcode
>> 4) & 0x3;
3017 int immed
= (opcode
>> 6) & 0x3;
3021 immed
|= (opcode
>> 10) & 0x1c;
3022 if (opcode
& (1 << 20))
3028 if (!(opcode
& (1 << 20)))
3029 return ERROR_INVALID_ARGUMENTS
;
3030 instruction
->type
= ARM_TST
;
3035 instruction
->type
= ARM_AND
;
3039 instruction
->type
= ARM_BIC
;
3044 instruction
->type
= ARM_MOV
;
3048 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3050 (int) (opcode
& 0xf));
3063 sprintf(cp
, "RRX%s\tr%d, r%d",
3065 (int) (opcode
& 0xf));
3073 instruction
->type
= ARM_ORR
;
3079 instruction
->type
= ARM_MVN
;
3084 // instruction->type = ARM_ORN;
3090 if (!(opcode
& (1 << 20)))
3091 return ERROR_INVALID_ARGUMENTS
;
3092 instruction
->type
= ARM_TEQ
;
3097 instruction
->type
= ARM_EOR
;
3102 if (!(opcode
& (1 << 20)))
3103 return ERROR_INVALID_ARGUMENTS
;
3104 instruction
->type
= ARM_CMN
;
3109 instruction
->type
= ARM_ADD
;
3113 instruction
->type
= ARM_ADC
;
3117 instruction
->type
= ARM_SBC
;
3122 if (!(opcode
& (1 << 21)))
3123 return ERROR_INVALID_ARGUMENTS
;
3124 instruction
->type
= ARM_CMP
;
3129 instruction
->type
= ARM_SUB
;
3133 instruction
->type
= ARM_RSB
;
3137 return ERROR_INVALID_ARGUMENTS
;
3140 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3141 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3164 strcpy(cp
, ", RRX");
3170 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3174 sprintf(cp
, "%s%s.W\tr%d, r%d",
3175 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3179 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3180 mnemonic
, suffix
, rd
,
3181 (int) (opcode
& 0xf), immed
? immed
: 32);
3185 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3186 arm_instruction_t
*instruction
, char *cp
)
3191 if (((opcode
>> 4) & 0xf) == 0) {
3192 switch ((opcode
>> 21) & 0x7) {
3206 return ERROR_INVALID_ARGUMENTS
;
3209 instruction
->type
= ARM_MOV
;
3210 if (opcode
& (1 << 20))
3212 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3214 (int) (opcode
>> 8) & 0xf,
3215 (int) (opcode
>> 16) & 0xf,
3216 (int) (opcode
>> 0) & 0xf);
3218 } else if (opcode
& (1 << 7)) {
3219 switch ((opcode
>> 20) & 0xf) {
3224 switch ((opcode
>> 4) & 0x3) {
3226 suffix
= ", ROR #8";
3229 suffix
= ", ROR #16";
3232 suffix
= ", ROR #24";
3235 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3236 (opcode
& (1 << 24)) ? 'U' : 'S',
3237 (opcode
& (1 << 26)) ? 'B' : 'H',
3238 (int) (opcode
>> 8) & 0xf,
3239 (int) (opcode
>> 0) & 0xf,
3246 if (opcode
& (1 << 6))
3247 return ERROR_INVALID_ARGUMENTS
;
3248 if (((opcode
>> 12) & 0xf) != 0xf)
3249 return ERROR_INVALID_ARGUMENTS
;
3250 if (!(opcode
& (1 << 20)))
3251 return ERROR_INVALID_ARGUMENTS
;
3253 switch (((opcode
>> 19) & 0x04)
3254 | ((opcode
>> 4) & 0x3)) {
3259 mnemonic
= "REV16.W";
3265 mnemonic
= "REVSH.W";
3271 return ERROR_INVALID_ARGUMENTS
;
3273 sprintf(cp
, "%s\tr%d, r%d",
3275 (int) (opcode
>> 8) & 0xf,
3276 (int) (opcode
>> 0) & 0xf);
3279 return ERROR_INVALID_ARGUMENTS
;
3286 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3287 arm_instruction_t
*instruction
, char *cp
)
3289 int rn
= (opcode
>> 16) & 0xf;
3292 instruction
->type
= ARM_LDR
;
3295 immed
= opcode
& 0x0fff;
3296 if ((opcode
& (1 << 23)) == 0)
3298 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3299 (int) (opcode
>> 12) & 0xf,
3300 thumb_alignpc4(address
) + immed
);
3304 if (opcode
& (1 << 23)) {
3305 immed
= opcode
& 0x0fff;
3306 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3307 (int) (opcode
>> 12) & 0xf,
3312 if (!(opcode
& (0x3f << 6))) {
3313 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3314 (int) (opcode
>> 12) & 0xf,
3316 (int) (opcode
>> 0) & 0xf,
3317 (int) (opcode
>> 4) & 0x3);
3322 if (((opcode
>> 8) & 0xf) == 0xe) {
3323 immed
= opcode
& 0x00ff;
3325 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3326 (int) (opcode
>> 12) & 0xf,
3331 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3332 char *p1
= "]", *p2
= "";
3334 if (!(opcode
& 0x0500))
3335 return ERROR_INVALID_ARGUMENTS
;
3337 immed
= opcode
& 0x00ff;
3339 /* two indexed modes will write back rn */
3340 if (opcode
& 0x100) {
3341 if (opcode
& 0x400) /* pre-indexed */
3343 else { /* post-indexed */
3349 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3350 (int) (opcode
>> 12) & 0xf,
3352 (opcode
& 0x200) ? "" : "-",
3357 return ERROR_INVALID_ARGUMENTS
;
3360 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3361 arm_instruction_t
*instruction
, char *cp
)
3363 int rn
= (opcode
>> 16) & 0xf;
3364 int rt
= (opcode
>> 12) & 0xf;
3365 int op2
= (opcode
>> 6) & 0x3f;
3367 char *p1
= "", *p2
= "]";
3370 switch ((opcode
>> 23) & 0x3) {
3372 if ((rn
& rt
) == 0xf) {
3374 immed
= opcode
& 0xfff;
3375 address
= thumb_alignpc4(address
);
3376 if (opcode
& (1 << 23))
3380 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
3384 if (rn
== 0x0f && rt
!= 0x0f) {
3386 immed
= opcode
& 0xfff;
3387 address
= thumb_alignpc4(address
);
3388 if (opcode
& (1 << 23))
3392 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
3398 if ((op2
& 0x3c) == 0x38) {
3399 immed
= opcode
& 0xff;
3400 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3401 rt
, rn
, immed
, immed
);
3404 if ((op2
& 0x3c) == 0x30) {
3406 immed
= opcode
& 0xff;
3409 p1
= (opcode
& (1 << 21)) ? "W" : "";
3410 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3411 p1
, rn
, immed
, immed
);
3416 immed
= opcode
& 0xff;
3417 if (!(opcode
& 0x200))
3420 /* two indexed modes will write back rn */
3421 if (opcode
& 0x100) {
3422 if (opcode
& 0x400) /* pre-indexed */
3424 else { /* post-indexed */
3430 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3431 mnemonic
, rt
, rn
, p1
,
3435 if ((op2
& 0x24) == 0x24) {
3437 goto ldrxb_immediate_t3
;
3440 int rm
= opcode
& 0xf;
3443 sprintf(cp
, "PLD\t");
3445 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
3446 immed
= (opcode
>> 4) & 0x3;
3448 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3453 if ((rn
& rt
) == 0xf)
3456 immed
= opcode
& 0xfff;
3457 goto preload_immediate
;
3461 mnemonic
= "LDRB.W";
3462 immed
= opcode
& 0xfff;
3463 goto ldrxb_immediate_t2
;
3465 if ((rn
& rt
) == 0xf) {
3466 immed
= opcode
& 0xfff;
3467 address
= thumb_alignpc4(address
);
3468 if (opcode
& (1 << 23))
3472 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
3475 if (rn
== 0xf && rt
!= 0xf) {
3477 immed
= opcode
& 0xfff;
3478 address
= thumb_alignpc4(address
);
3479 if (opcode
& (1 << 23))
3483 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
3488 if ((op2
& 0x3c) == 0x38) {
3489 immed
= opcode
& 0xff;
3490 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
3491 rt
, rn
, immed
, immed
);
3494 if ((op2
& 0x3c) == 0x30) {
3496 immed
= opcode
& 0xff;
3497 immed
= -immed
; // pli
3498 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
3503 goto ldrxb_immediate_t3
;
3505 if ((op2
& 0x24) == 0x24) {
3507 goto ldrxb_immediate_t3
;
3510 int rm
= opcode
& 0xf;
3513 sprintf(cp
, "PLI\t");
3515 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
3516 immed
= (opcode
>> 4) & 0x3;
3518 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3524 immed
= opcode
& 0xfff;
3525 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3" PRIx32
,
3531 immed
= opcode
& 0xfff;
3533 goto ldrxb_immediate_t2
;
3536 return ERROR_INVALID_ARGUMENTS
;
3539 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
3540 arm_instruction_t
*instruction
, char *cp
)
3542 int rn
= (opcode
>> 16) & 0xf;
3543 int rt
= (opcode
>> 12) & 0xf;
3544 int op2
= (opcode
>> 6) & 0x3f;
3549 sprintf(cp
, "HINT (UNALLOCATED)");
3553 if (opcode
& (1 << 24))
3556 if ((opcode
& (1 << 23)) == 0) {
3559 immed
= opcode
& 0xfff;
3560 address
= thumb_alignpc4(address
);
3561 if (opcode
& (1 << 23))
3565 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
3570 int rm
= opcode
& 0xf;
3572 immed
= (opcode
>> 4) & 0x3;
3573 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
3574 sign
, rt
, rn
, rm
, immed
);
3577 if ((op2
& 0x3c) == 0x38) {
3578 immed
= opcode
& 0xff;
3579 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
3580 sign
, rt
, rn
, immed
, immed
);
3583 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
3584 char *p1
= "", *p2
= "]";
3586 immed
= opcode
& 0xff;
3587 if (!(opcode
& 0x200))
3590 /* two indexed modes will write back rn */
3591 if (opcode
& 0x100) {
3592 if (opcode
& 0x400) /* pre-indexed */
3594 else { /* post-indexed */
3599 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3600 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
3607 immed
= opcode
& 0xfff;
3608 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
3609 sign
, *sign
? "" : ".W",
3610 rt
, rn
, immed
, immed
);
3614 return ERROR_INVALID_ARGUMENTS
;
3618 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
3619 * always set. That means eventual arm_simulate_step() support for Thumb2
3620 * will need work in this area.
3622 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
3629 /* clear low bit ... it's set on function pointers */
3632 /* clear fields, to avoid confusion */
3633 memset(instruction
, 0, sizeof(arm_instruction_t
));
3635 /* read first halfword, see if this is the only one */
3636 retval
= target_read_u16(target
, address
, &op
);
3637 if (retval
!= ERROR_OK
)
3640 switch (op
& 0xf800) {
3644 /* 32-bit instructions */
3645 instruction
->instruction_size
= 4;
3647 retval
= target_read_u16(target
, address
+ 2, &op
);
3648 if (retval
!= ERROR_OK
)
3651 instruction
->opcode
= opcode
;
3654 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
3655 return thumb_evaluate_opcode(op
, address
, instruction
);
3658 snprintf(instruction
->text
, 128,
3659 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
3661 cp
= strchr(instruction
->text
, 0);
3662 retval
= ERROR_FAIL
;
3664 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
3665 if ((opcode
& 0x1a008000) == 0x10000000)
3666 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
3668 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
3669 else if ((opcode
& 0x1a008000) == 0x12000000)
3670 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
3672 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
3673 else if ((opcode
& 0x18008000) == 0x10008000)
3674 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
3676 /* ARMv7-M: A5.3.5 Load/store multiple */
3677 else if ((opcode
& 0x1e400000) == 0x08000000)
3678 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
3680 /* ARMv7-M: A5.3.7 Load word */
3681 else if ((opcode
& 0x1f700000) == 0x18500000)
3682 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
3684 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
3685 else if ((opcode
& 0x1e700000) == 0x18300000)
3686 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
3688 /* ARMv7-M: A5.3.9 Load byte, memory hints */
3689 else if ((opcode
& 0x1e700000) == 0x18100000)
3690 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
3692 /* ARMv7-M: A5.3.10 Store single data item */
3693 else if ((opcode
& 0x1f100000) == 0x18000000)
3694 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
3696 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
3697 else if ((opcode
& 0x1e000000) == 0x0a000000)
3698 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
3700 /* ARMv7-M: A5.3.12 Data processing (register)
3701 * and A5.3.13 Miscellaneous operations
3703 else if ((opcode
& 0x1f000000) == 0x1a000000)
3704 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
3706 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
3707 else if ((opcode
& 0x1f800000) == 0x1b000000)
3708 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
3710 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
3711 else if ((opcode
& 0x1f800000) == 0x1b800000)
3712 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
3714 /* FIXME decode more 32-bit instructions */
3716 if (retval
== ERROR_OK
)
3719 if (retval
== ERROR_INVALID_ARGUMENTS
) {
3720 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3721 strcpy(cp
, "UNDEFINED OPCODE");
3725 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
3728 strcpy(cp
, "(32-bit Thumb2 ...)");
3732 int arm_access_size(arm_instruction_t
*instruction
)
3734 if ((instruction
->type
== ARM_LDRB
)
3735 || (instruction
->type
== ARM_LDRBT
)
3736 || (instruction
->type
== ARM_LDRSB
)
3737 || (instruction
->type
== ARM_STRB
)
3738 || (instruction
->type
== ARM_STRBT
))
3742 else if ((instruction
->type
== ARM_LDRH
)
3743 || (instruction
->type
== ARM_LDRSH
)
3744 || (instruction
->type
== ARM_STRH
))
3748 else if ((instruction
->type
== ARM_LDR
)
3749 || (instruction
->type
== ARM_LDRT
)
3750 || (instruction
->type
== ARM_STR
)
3751 || (instruction
->type
== ARM_STRT
))
3755 else if ((instruction
->type
== ARM_LDRD
)
3756 || (instruction
->type
== ARM_STRD
))
3762 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)