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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
21 ***************************************************************************/
28 #include "arm_disassembler.h"
29 #include <helper/log.h>
32 * This disassembler supports two main functions for OpenOCD:
34 * - Various "disassemble" commands. OpenOCD can serve as a
35 * machine-language debugger, without help from GDB.
37 * - Single stepping. Not all ARM cores support hardware single
38 * stepping. To work without that support, the debugger must
39 * be able to decode instructions to find out where to put a
40 * "next instruction" breakpoint.
42 * In addition, interpretation of ETM trace data needs some of the
43 * decoding mechanisms.
45 * At this writing (September 2009) neither function is complete.
48 * * Old-style syntax (not UAL) is generally used
49 * * VFP instructions are not understood (ARMv5 and later)
50 * except as coprocessor 10/11 operations
51 * * Most ARM instructions through ARMv6 are decoded, but some
52 * of the post-ARMv4 opcodes may not be handled yet
53 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
54 * * NEON instructions are not understood (ARMv7-A)
56 * - Thumb/Thumb2 decoding
57 * * UAL syntax should be consistently used
58 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
59 * be handled properly. Accordingly, so should the subset
60 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
62 * * Conditional effects of Thumb2 "IT" (if-then) instructions
63 * are not handled: the affected instructions are not shown
64 * with their now-conditional suffixes.
65 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
66 * handled (minimally for coprocessor access).
67 * * SIMD instructions, and some other Thumb2 instructions
68 * from ARMv7-A, are not understood.
71 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
72 * * Opcodes changed by ThumbEE mode are not handled; these
73 * instructions wrongly decode as LDM and STM.
75 * - Jazelle decoding ... no support whatsoever for Jazelle mode
76 * or decoding. ARM encourages use of the more generic ThumbEE
77 * mode, instead of Jazelle mode, in current chips.
79 * - Single-step/emulation ... spotty support, which is only weakly
80 * tested. Thumb2 is not supported. (Arguably a full simulator
81 * is not needed to support just single stepping. Recognizing
82 * branch vs non-branch instructions suffices, except when the
83 * instruction faults and triggers a synchronous exception which
84 * can be intercepted using other means.)
86 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
87 * ARM v7-R edition" gives the most complete coverage of the various
88 * generations of ARM instructions. At this writing it is publicly
89 * accessible to anyone willing to create an account at the ARM
90 * web site; see http://www.arm.com/documentation/ for information.
92 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
93 * more details relevant to the Thumb2-only processors (such as
94 * the Cortex-M implementations).
97 /* textual represenation of the condition field
98 * ALways (default) is ommitted (empty string) */
99 static const char *arm_condition_strings
[] = {
100 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
103 /* make up for C's missing ROR */
104 static uint32_t ror(uint32_t value
, int places
)
106 return (value
>> places
) | (value
<< (32 - places
));
109 static int evaluate_unknown(uint32_t opcode
,
110 uint32_t address
, struct arm_instruction
*instruction
)
112 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
113 snprintf(instruction
->text
, 128,
114 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
115 "\tUNDEFINED INSTRUCTION", address
, opcode
);
119 static int evaluate_pld(uint32_t opcode
,
120 uint32_t address
, struct arm_instruction
*instruction
)
123 if ((opcode
& 0x0d70f000) == 0x0550f000) {
124 instruction
->type
= ARM_PLD
;
126 snprintf(instruction
->text
,
128 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...",
134 return evaluate_unknown(opcode
, address
, instruction
);
137 static int evaluate_srs(uint32_t opcode
,
138 uint32_t address
, struct arm_instruction
*instruction
)
140 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
141 const char *mode
= "";
143 switch ((opcode
>> 23) & 0x3) {
148 /* "IA" is default */
158 switch (opcode
& 0x0e500000) {
160 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
162 "\tSRS%s\tSP%s, #%d",
165 (unsigned)(opcode
& 0x1f));
168 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
173 (unsigned)((opcode
>> 16) & 0xf), wback
);
176 return evaluate_unknown(opcode
, address
, instruction
);
181 static int evaluate_swi(uint32_t opcode
,
182 uint32_t address
, struct arm_instruction
*instruction
)
184 instruction
->type
= ARM_SWI
;
186 snprintf(instruction
->text
, 128,
187 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
188 address
, opcode
, (opcode
& 0xffffff));
193 static int evaluate_blx_imm(uint32_t opcode
,
194 uint32_t address
, struct arm_instruction
*instruction
)
198 uint32_t target_address
;
200 instruction
->type
= ARM_BLX
;
201 immediate
= opcode
& 0x00ffffff;
203 /* sign extend 24-bit immediate */
204 if (immediate
& 0x00800000)
205 offset
= 0xff000000 | immediate
;
209 /* shift two bits left */
212 /* odd/event halfword */
213 if (opcode
& 0x01000000)
216 target_address
= address
+ 8 + offset
;
218 snprintf(instruction
->text
,
220 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"",
225 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
226 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
231 static int evaluate_b_bl(uint32_t opcode
,
232 uint32_t address
, struct arm_instruction
*instruction
)
237 uint32_t target_address
;
239 immediate
= opcode
& 0x00ffffff;
240 L
= (opcode
& 0x01000000) >> 24;
242 /* sign extend 24-bit immediate */
243 if (immediate
& 0x00800000)
244 offset
= 0xff000000 | immediate
;
248 /* shift two bits left */
251 target_address
= address
+ 8 + offset
;
254 instruction
->type
= ARM_BL
;
256 instruction
->type
= ARM_B
;
258 snprintf(instruction
->text
,
260 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
,
267 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
268 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
273 /* Coprocessor load/store and double register transfers
274 * both normal and extended instruction space (condition field b1111) */
275 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
276 uint32_t address
, struct arm_instruction
*instruction
)
278 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
281 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000)) {
282 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
285 cp_opcode
= (opcode
& 0xf0) >> 4;
286 Rd
= (opcode
& 0xf000) >> 12;
287 Rn
= (opcode
& 0xf0000) >> 16;
288 CRm
= (opcode
& 0xf);
291 if ((opcode
& 0x0ff00000) == 0x0c400000) {
292 instruction
->type
= ARM_MCRR
;
294 } else if ((opcode
& 0x0ff00000) == 0x0c500000) {
296 instruction
->type
= ARM_MRRC
;
299 LOG_ERROR("Unknown instruction");
303 snprintf(instruction
->text
, 128,
304 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
305 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
306 address
, opcode
, mnemonic
,
307 ((opcode
& 0xf0000000) == 0xf0000000)
308 ? "2" : COND(opcode
),
309 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
310 } else {/* LDC or STC */
311 uint8_t CRd
, Rn
, offset
;
314 char addressing_mode
[32];
316 CRd
= (opcode
& 0xf000) >> 12;
317 Rn
= (opcode
& 0xf0000) >> 16;
318 offset
= (opcode
& 0xff) << 2;
321 if (opcode
& 0x00100000) {
322 instruction
->type
= ARM_LDC
;
325 instruction
->type
= ARM_STC
;
329 U
= (opcode
& 0x00800000) >> 23;
331 /* addressing modes */
332 if ((opcode
& 0x01200000) == 0x01000000)/* offset */
333 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
334 Rn
, U
? "" : "-", offset
);
335 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
336 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
337 Rn
, U
? "" : "-", offset
);
338 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
339 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
340 Rn
, U
? "" : "-", offset
);
341 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
342 snprintf(addressing_mode
, 32, "[r%i], {%d}",
345 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
347 "\t%s%s%s p%i, c%i, %s",
348 address
, opcode
, mnemonic
,
349 ((opcode
& 0xf0000000) == 0xf0000000)
350 ? "2" : COND(opcode
),
351 (opcode
& (1 << 22)) ? "L" : "",
352 cp_num
, CRd
, addressing_mode
);
358 /* Coprocessor data processing instructions
359 * Coprocessor register transfer instructions
360 * both normal and extended instruction space (condition field b1111) */
361 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
362 uint32_t address
, struct arm_instruction
*instruction
)
366 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
368 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
369 cp_num
= (opcode
& 0xf00) >> 8;
370 CRd_Rd
= (opcode
& 0xf000) >> 12;
371 CRn
= (opcode
& 0xf0000) >> 16;
372 CRm
= (opcode
& 0xf);
373 opcode_2
= (opcode
& 0xe0) >> 5;
376 if (opcode
& 0x00000010) { /* bit 4 set -> MRC/MCR */
377 if (opcode
& 0x00100000) { /* bit 20 set -> MRC */
378 instruction
->type
= ARM_MRC
;
380 } else {/* bit 20 not set -> MCR */
381 instruction
->type
= ARM_MCR
;
385 opcode_1
= (opcode
& 0x00e00000) >> 21;
387 snprintf(instruction
->text
,
389 "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",
400 } else {/* bit 4 not set -> CDP */
401 instruction
->type
= ARM_CDP
;
404 opcode_1
= (opcode
& 0x00f00000) >> 20;
406 snprintf(instruction
->text
,
408 "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",
424 /* Load/store instructions */
425 static int evaluate_load_store(uint32_t opcode
,
426 uint32_t address
, struct arm_instruction
*instruction
)
428 uint8_t I
, P
, U
, B
, W
, L
;
430 char *operation
;/* "LDR" or "STR" */
431 char *suffix
; /* "", "B", "T", "BT" */
435 I
= (opcode
& 0x02000000) >> 25;
436 P
= (opcode
& 0x01000000) >> 24;
437 U
= (opcode
& 0x00800000) >> 23;
438 B
= (opcode
& 0x00400000) >> 22;
439 W
= (opcode
& 0x00200000) >> 21;
440 L
= (opcode
& 0x00100000) >> 20;
442 /* target register */
443 Rd
= (opcode
& 0xf000) >> 12;
446 Rn
= (opcode
& 0xf0000) >> 16;
448 instruction
->info
.load_store
.Rd
= Rd
;
449 instruction
->info
.load_store
.Rn
= Rn
;
450 instruction
->info
.load_store
.U
= U
;
452 /* determine operation */
458 /* determine instruction type and suffix */
460 if ((P
== 0) && (W
== 1)) {
462 instruction
->type
= ARM_LDRBT
;
464 instruction
->type
= ARM_STRBT
;
468 instruction
->type
= ARM_LDRB
;
470 instruction
->type
= ARM_STRB
;
474 if ((P
== 0) && (W
== 1)) {
476 instruction
->type
= ARM_LDRT
;
478 instruction
->type
= ARM_STRT
;
482 instruction
->type
= ARM_LDR
;
484 instruction
->type
= ARM_STR
;
489 if (!I
) { /* #+-<offset_12> */
490 uint32_t offset_12
= (opcode
& 0xfff);
492 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
494 snprintf(offset
, 32, "%s", "");
496 instruction
->info
.load_store
.offset_mode
= 0;
497 instruction
->info
.load_store
.offset
.offset
= offset_12
;
498 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
499 uint8_t shift_imm
, shift
;
502 shift_imm
= (opcode
& 0xf80) >> 7;
503 shift
= (opcode
& 0x60) >> 5;
506 /* LSR encodes a shift by 32 bit as 0x0 */
507 if ((shift
== 0x1) && (shift_imm
== 0x0))
510 /* ASR encodes a shift by 32 bit as 0x0 */
511 if ((shift
== 0x2) && (shift_imm
== 0x0))
514 /* ROR by 32 bit is actually a RRX */
515 if ((shift
== 0x3) && (shift_imm
== 0x0))
518 instruction
->info
.load_store
.offset_mode
= 1;
519 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
520 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
521 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
523 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
524 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
525 else { /* +-<Rm>, <Shift>, #<shift_imm> */
528 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
531 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
534 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
537 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
540 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
547 if (W
== 0) { /* offset */
548 snprintf(instruction
->text
,
550 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
560 instruction
->info
.load_store
.index_mode
= 0;
561 } else {/* pre-indexed */
562 snprintf(instruction
->text
,
564 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
574 instruction
->info
.load_store
.index_mode
= 1;
576 } else {/* post-indexed */
577 snprintf(instruction
->text
,
579 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
589 instruction
->info
.load_store
.index_mode
= 2;
595 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
597 unsigned rm
= (opcode
>> 0) & 0xf;
598 unsigned rd
= (opcode
>> 12) & 0xf;
599 unsigned rn
= (opcode
>> 16) & 0xf;
602 switch ((opcode
>> 24) & 0x3) {
607 sprintf(cp
, "UNDEFINED");
608 return ARM_UNDEFINED_INSTRUCTION
;
617 switch ((opcode
>> 10) & 0x3) {
633 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
634 (opcode
& (1 << 22)) ? 'U' : 'S',
639 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
640 (opcode
& (1 << 22)) ? 'U' : 'S',
647 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
653 switch ((opcode
>> 20) & 0x7) {
676 switch ((opcode
>> 5) & 0x7) {
705 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
706 (int) (opcode
>> 12) & 0xf,
707 (int) (opcode
>> 16) & 0xf,
708 (int) (opcode
>> 0) & 0xf);
712 /* these opcodes might be used someday */
713 sprintf(cp
, "UNDEFINED");
714 return ARM_UNDEFINED_INSTRUCTION
;
717 /* ARMv6 and later support "media" instructions (includes SIMD) */
718 static int evaluate_media(uint32_t opcode
, uint32_t address
,
719 struct arm_instruction
*instruction
)
721 char *cp
= instruction
->text
;
722 char *mnemonic
= NULL
;
725 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
729 /* parallel add/subtract */
730 if ((opcode
& 0x01800000) == 0x00000000) {
731 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
736 if ((opcode
& 0x01f00020) == 0x00800000) {
738 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
740 if (opcode
& (1 << 6)) {
749 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
751 (int) (opcode
>> 12) & 0xf,
752 (int) (opcode
>> 16) & 0xf,
753 (int) (opcode
>> 0) & 0xf,
759 if ((opcode
& 0x01a00020) == 0x00a00000) {
761 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
763 if (opcode
& (1 << 6)) {
770 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
771 (opcode
& (1 << 22)) ? 'U' : 'S',
773 (int) (opcode
>> 12) & 0xf,
774 (int) (opcode
>> 16) & 0x1f,
775 (int) (opcode
>> 0) & 0xf,
781 if ((opcode
& 0x018000f0) == 0x00800070) {
782 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
787 if ((opcode
& 0x01f00080) == 0x01000000) {
788 unsigned rn
= (opcode
>> 12) & 0xf;
791 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
792 (opcode
& (1 << 6)) ? 'S' : 'A',
793 (opcode
& (1 << 5)) ? "X" : "",
795 (int) (opcode
>> 16) & 0xf,
796 (int) (opcode
>> 0) & 0xf,
797 (int) (opcode
>> 8) & 0xf,
800 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
801 (opcode
& (1 << 6)) ? 'S' : 'A',
802 (opcode
& (1 << 5)) ? "X" : "",
804 (int) (opcode
>> 16) & 0xf,
805 (int) (opcode
>> 0) & 0xf,
806 (int) (opcode
>> 8) & 0xf);
809 if ((opcode
& 0x01f00000) == 0x01400000) {
810 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
811 (opcode
& (1 << 6)) ? 'S' : 'A',
812 (opcode
& (1 << 5)) ? "X" : "",
814 (int) (opcode
>> 12) & 0xf,
815 (int) (opcode
>> 16) & 0xf,
816 (int) (opcode
>> 0) & 0xf,
817 (int) (opcode
>> 8) & 0xf);
820 if ((opcode
& 0x01f00000) == 0x01500000) {
821 unsigned rn
= (opcode
>> 12) & 0xf;
823 switch (opcode
& 0xc0) {
835 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
836 (opcode
& (1 << 6)) ? 'S' : 'A',
837 (opcode
& (1 << 5)) ? "R" : "",
839 (int) (opcode
>> 16) & 0xf,
840 (int) (opcode
>> 0) & 0xf,
841 (int) (opcode
>> 8) & 0xf,
844 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
845 (opcode
& (1 << 5)) ? "R" : "",
847 (int) (opcode
>> 16) & 0xf,
848 (int) (opcode
>> 0) & 0xf,
849 (int) (opcode
>> 8) & 0xf);
853 /* simple matches against the remaining decode bits */
854 switch (opcode
& 0x01f000f0) {
857 /* parallel halfword saturate */
858 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
859 (opcode
& (1 << 22)) ? 'U' : 'S',
861 (int) (opcode
>> 12) & 0xf,
862 (int) (opcode
>> 16) & 0xf,
863 (int) (opcode
>> 0) & 0xf);
876 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
877 (int) (opcode
>> 12) & 0xf,
878 (int) (opcode
>> 16) & 0xf,
879 (int) (opcode
>> 0) & 0xf);
882 /* unsigned sum of absolute differences */
883 if (((opcode
>> 12) & 0xf) == 0xf)
884 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
885 (int) (opcode
>> 16) & 0xf,
886 (int) (opcode
>> 0) & 0xf,
887 (int) (opcode
>> 8) & 0xf);
889 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
890 (int) (opcode
>> 16) & 0xf,
891 (int) (opcode
>> 0) & 0xf,
892 (int) (opcode
>> 8) & 0xf,
893 (int) (opcode
>> 12) & 0xf);
897 unsigned rm
= (opcode
>> 0) & 0xf;
898 unsigned rd
= (opcode
>> 12) & 0xf;
900 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
905 /* these opcodes might be used someday */
906 sprintf(cp
, "UNDEFINED");
910 /* Miscellaneous load/store instructions */
911 static int evaluate_misc_load_store(uint32_t opcode
,
912 uint32_t address
, struct arm_instruction
*instruction
)
914 uint8_t P
, U
, I
, W
, L
, S
, H
;
916 char *operation
;/* "LDR" or "STR" */
917 char *suffix
; /* "H", "SB", "SH", "D" */
921 P
= (opcode
& 0x01000000) >> 24;
922 U
= (opcode
& 0x00800000) >> 23;
923 I
= (opcode
& 0x00400000) >> 22;
924 W
= (opcode
& 0x00200000) >> 21;
925 L
= (opcode
& 0x00100000) >> 20;
926 S
= (opcode
& 0x00000040) >> 6;
927 H
= (opcode
& 0x00000020) >> 5;
929 /* target register */
930 Rd
= (opcode
& 0xf000) >> 12;
933 Rn
= (opcode
& 0xf0000) >> 16;
935 instruction
->info
.load_store
.Rd
= Rd
;
936 instruction
->info
.load_store
.Rn
= Rn
;
937 instruction
->info
.load_store
.U
= U
;
939 /* determine instruction type and suffix */
944 instruction
->type
= ARM_LDRSH
;
948 instruction
->type
= ARM_LDRSB
;
951 } else {/* there are no signed stores, so this is used to encode double-register
956 instruction
->type
= ARM_STRD
;
959 instruction
->type
= ARM_LDRD
;
962 } else {/* unsigned */
966 instruction
->type
= ARM_LDRH
;
969 instruction
->type
= ARM_STRH
;
973 if (I
) {/* Immediate offset/index (#+-<offset_8>)*/
974 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
975 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
977 instruction
->info
.load_store
.offset_mode
= 0;
978 instruction
->info
.load_store
.offset
.offset
= offset_8
;
979 } else {/* Register offset/index (+-<Rm>) */
982 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
984 instruction
->info
.load_store
.offset_mode
= 1;
985 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
986 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
987 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
991 if (W
== 0) { /* offset */
992 snprintf(instruction
->text
,
994 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
1004 instruction
->info
.load_store
.index_mode
= 0;
1005 } else {/* pre-indexed */
1006 snprintf(instruction
->text
,
1008 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1018 instruction
->info
.load_store
.index_mode
= 1;
1020 } else {/* post-indexed */
1021 snprintf(instruction
->text
,
1023 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1033 instruction
->info
.load_store
.index_mode
= 2;
1039 /* Load/store multiples instructions */
1040 static int evaluate_ldm_stm(uint32_t opcode
,
1041 uint32_t address
, struct arm_instruction
*instruction
)
1043 uint8_t P
, U
, S
, W
, L
, Rn
;
1044 uint32_t register_list
;
1045 char *addressing_mode
;
1052 P
= (opcode
& 0x01000000) >> 24;
1053 U
= (opcode
& 0x00800000) >> 23;
1054 S
= (opcode
& 0x00400000) >> 22;
1055 W
= (opcode
& 0x00200000) >> 21;
1056 L
= (opcode
& 0x00100000) >> 20;
1057 register_list
= (opcode
& 0xffff);
1058 Rn
= (opcode
& 0xf0000) >> 16;
1060 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1061 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1062 instruction
->info
.load_store_multiple
.S
= S
;
1063 instruction
->info
.load_store_multiple
.W
= W
;
1066 instruction
->type
= ARM_LDM
;
1069 instruction
->type
= ARM_STM
;
1075 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1076 addressing_mode
= "IB";
1078 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1079 addressing_mode
= "DB";
1083 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1084 /* "IA" is the default in UAL syntax */
1085 addressing_mode
= "";
1087 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1088 addressing_mode
= "DA";
1092 reg_list_p
= reg_list
;
1093 for (i
= 0; i
<= 15; i
++) {
1094 if ((register_list
>> i
) & 1) {
1097 reg_list_p
+= snprintf(reg_list_p
,
1098 (reg_list
+ 69 - reg_list_p
),
1102 reg_list_p
+= snprintf(reg_list_p
,
1103 (reg_list
+ 69 - reg_list_p
),
1109 snprintf(instruction
->text
, 128,
1110 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1111 "\t%s%s%s r%i%s, {%s}%s",
1113 mnemonic
, addressing_mode
, COND(opcode
),
1114 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1119 /* Multiplies, extra load/stores */
1120 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1121 uint32_t address
, struct arm_instruction
*instruction
)
1123 /* Multiply (accumulate) (long) and Swap/swap byte */
1124 if ((opcode
& 0x000000f0) == 0x00000090) {
1125 /* Multiply (accumulate) */
1126 if ((opcode
& 0x0f800000) == 0x00000000) {
1127 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1129 Rs
= (opcode
& 0xf00) >> 8;
1130 Rn
= (opcode
& 0xf000) >> 12;
1131 Rd
= (opcode
& 0xf0000) >> 16;
1132 S
= (opcode
& 0x00100000) >> 20;
1134 /* examine A bit (accumulate) */
1135 if (opcode
& 0x00200000) {
1136 instruction
->type
= ARM_MLA
;
1137 snprintf(instruction
->text
,
1139 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1149 instruction
->type
= ARM_MUL
;
1150 snprintf(instruction
->text
,
1152 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1165 /* Multiply (accumulate) long */
1166 if ((opcode
& 0x0f800000) == 0x00800000) {
1167 char *mnemonic
= NULL
;
1168 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1170 Rs
= (opcode
& 0xf00) >> 8;
1171 RdHi
= (opcode
& 0xf000) >> 12;
1172 RdLow
= (opcode
& 0xf0000) >> 16;
1173 S
= (opcode
& 0x00100000) >> 20;
1175 switch ((opcode
& 0x00600000) >> 21) {
1177 instruction
->type
= ARM_UMULL
;
1181 instruction
->type
= ARM_UMLAL
;
1185 instruction
->type
= ARM_SMULL
;
1189 instruction
->type
= ARM_SMLAL
;
1194 snprintf(instruction
->text
,
1196 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1210 /* Swap/swap byte */
1211 if ((opcode
& 0x0f800000) == 0x01000000) {
1214 Rd
= (opcode
& 0xf000) >> 12;
1215 Rn
= (opcode
& 0xf0000) >> 16;
1217 /* examine B flag */
1218 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1220 snprintf(instruction
->text
,
1222 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1225 (opcode
& 0x00400000) ? "SWPB" : "SWP",
1235 return evaluate_misc_load_store(opcode
, address
, instruction
);
1238 static int evaluate_mrs_msr(uint32_t opcode
,
1239 uint32_t address
, struct arm_instruction
*instruction
)
1241 int R
= (opcode
& 0x00400000) >> 22;
1242 char *PSR
= (R
) ? "SPSR" : "CPSR";
1244 /* Move register to status register (MSR) */
1245 if (opcode
& 0x00200000) {
1246 instruction
->type
= ARM_MSR
;
1248 /* immediate variant */
1249 if (opcode
& 0x02000000) {
1250 uint8_t immediate
= (opcode
& 0xff);
1251 uint8_t rotate
= (opcode
& 0xf00);
1253 snprintf(instruction
->text
,
1255 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1260 (opcode
& 0x10000) ? "c" : "",
1261 (opcode
& 0x20000) ? "x" : "",
1262 (opcode
& 0x40000) ? "s" : "",
1263 (opcode
& 0x80000) ? "f" : "",
1264 ror(immediate
, (rotate
* 2))
1266 } else {/* register variant */
1267 uint8_t Rm
= opcode
& 0xf;
1268 snprintf(instruction
->text
,
1270 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1275 (opcode
& 0x10000) ? "c" : "",
1276 (opcode
& 0x20000) ? "x" : "",
1277 (opcode
& 0x40000) ? "s" : "",
1278 (opcode
& 0x80000) ? "f" : "",
1283 } else {/* Move status register to register (MRS) */
1286 instruction
->type
= ARM_MRS
;
1287 Rd
= (opcode
& 0x0000f000) >> 12;
1289 snprintf(instruction
->text
,
1291 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1302 /* Miscellaneous instructions */
1303 static int evaluate_misc_instr(uint32_t opcode
,
1304 uint32_t address
, struct arm_instruction
*instruction
)
1307 if ((opcode
& 0x000000f0) == 0x00000000)
1308 evaluate_mrs_msr(opcode
, address
, instruction
);
1311 if ((opcode
& 0x006000f0) == 0x00200010) {
1313 instruction
->type
= ARM_BX
;
1316 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1317 address
, opcode
, COND(opcode
), Rm
);
1319 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1320 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1323 /* BXJ - "Jazelle" support (ARMv5-J) */
1324 if ((opcode
& 0x006000f0) == 0x00200020) {
1326 instruction
->type
= ARM_BX
;
1329 snprintf(instruction
->text
, 128,
1330 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1331 address
, opcode
, COND(opcode
), Rm
);
1333 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1334 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1338 if ((opcode
& 0x006000f0) == 0x00600010) {
1340 instruction
->type
= ARM_CLZ
;
1342 Rd
= (opcode
& 0xf000) >> 12;
1344 snprintf(instruction
->text
,
1346 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1355 if ((opcode
& 0x006000f0) == 0x00200030) {
1357 instruction
->type
= ARM_BLX
;
1360 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1361 address
, opcode
, COND(opcode
), Rm
);
1363 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1364 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1367 /* Enhanced DSP add/subtracts */
1368 if ((opcode
& 0x0000000f0) == 0x00000050) {
1370 char *mnemonic
= NULL
;
1372 Rd
= (opcode
& 0xf000) >> 12;
1373 Rn
= (opcode
& 0xf0000) >> 16;
1375 switch ((opcode
& 0x00600000) >> 21) {
1377 instruction
->type
= ARM_QADD
;
1381 instruction
->type
= ARM_QSUB
;
1385 instruction
->type
= ARM_QDADD
;
1389 instruction
->type
= ARM_QDSUB
;
1394 snprintf(instruction
->text
,
1396 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1406 /* Software breakpoints */
1407 if ((opcode
& 0x0000000f0) == 0x00000070) {
1409 instruction
->type
= ARM_BKPT
;
1410 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1412 snprintf(instruction
->text
,
1414 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1420 /* Enhanced DSP multiplies */
1421 if ((opcode
& 0x000000090) == 0x00000080) {
1422 int x
= (opcode
& 0x20) >> 5;
1423 int y
= (opcode
& 0x40) >> 6;
1426 if ((opcode
& 0x00600000) == 0x00000000) {
1427 uint8_t Rd
, Rm
, Rs
, Rn
;
1428 instruction
->type
= ARM_SMLAxy
;
1429 Rd
= (opcode
& 0xf0000) >> 16;
1430 Rm
= (opcode
& 0xf);
1431 Rs
= (opcode
& 0xf00) >> 8;
1432 Rn
= (opcode
& 0xf000) >> 12;
1434 snprintf(instruction
->text
,
1436 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1449 if ((opcode
& 0x00600000) == 0x00400000) {
1450 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1451 instruction
->type
= ARM_SMLAxy
;
1452 RdHi
= (opcode
& 0xf0000) >> 16;
1453 RdLow
= (opcode
& 0xf000) >> 12;
1454 Rm
= (opcode
& 0xf);
1455 Rs
= (opcode
& 0xf00) >> 8;
1457 snprintf(instruction
->text
,
1459 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1472 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0)) {
1473 uint8_t Rd
, Rm
, Rs
, Rn
;
1474 instruction
->type
= ARM_SMLAWy
;
1475 Rd
= (opcode
& 0xf0000) >> 16;
1476 Rm
= (opcode
& 0xf);
1477 Rs
= (opcode
& 0xf00) >> 8;
1478 Rn
= (opcode
& 0xf000) >> 12;
1480 snprintf(instruction
->text
,
1482 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1494 if ((opcode
& 0x00600000) == 0x00300000) {
1496 instruction
->type
= ARM_SMULxy
;
1497 Rd
= (opcode
& 0xf0000) >> 16;
1498 Rm
= (opcode
& 0xf);
1499 Rs
= (opcode
& 0xf00) >> 8;
1501 snprintf(instruction
->text
,
1503 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1515 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1)) {
1517 instruction
->type
= ARM_SMULWy
;
1518 Rd
= (opcode
& 0xf0000) >> 16;
1519 Rm
= (opcode
& 0xf);
1520 Rs
= (opcode
& 0xf00) >> 8;
1522 snprintf(instruction
->text
,
1524 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1538 static int evaluate_data_proc(uint32_t opcode
,
1539 uint32_t address
, struct arm_instruction
*instruction
)
1541 uint8_t I
, op
, S
, Rn
, Rd
;
1542 char *mnemonic
= NULL
;
1543 char shifter_operand
[32];
1545 I
= (opcode
& 0x02000000) >> 25;
1546 op
= (opcode
& 0x01e00000) >> 21;
1547 S
= (opcode
& 0x00100000) >> 20;
1549 Rd
= (opcode
& 0xf000) >> 12;
1550 Rn
= (opcode
& 0xf0000) >> 16;
1552 instruction
->info
.data_proc
.Rd
= Rd
;
1553 instruction
->info
.data_proc
.Rn
= Rn
;
1554 instruction
->info
.data_proc
.S
= S
;
1558 instruction
->type
= ARM_AND
;
1562 instruction
->type
= ARM_EOR
;
1566 instruction
->type
= ARM_SUB
;
1570 instruction
->type
= ARM_RSB
;
1574 instruction
->type
= ARM_ADD
;
1578 instruction
->type
= ARM_ADC
;
1582 instruction
->type
= ARM_SBC
;
1586 instruction
->type
= ARM_RSC
;
1590 instruction
->type
= ARM_TST
;
1594 instruction
->type
= ARM_TEQ
;
1598 instruction
->type
= ARM_CMP
;
1602 instruction
->type
= ARM_CMN
;
1606 instruction
->type
= ARM_ORR
;
1610 instruction
->type
= ARM_MOV
;
1614 instruction
->type
= ARM_BIC
;
1618 instruction
->type
= ARM_MVN
;
1623 if (I
) {/* immediate shifter operand (#<immediate>)*/
1624 uint8_t immed_8
= opcode
& 0xff;
1625 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1628 immediate
= ror(immed_8
, rotate_imm
* 2);
1630 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1632 instruction
->info
.data_proc
.variant
= 0;
1633 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1634 } else {/* register-based shifter operand */
1636 shift
= (opcode
& 0x60) >> 5;
1637 Rm
= (opcode
& 0xf);
1639 if ((opcode
& 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1640 *#<shift_immediate>") */
1642 shift_imm
= (opcode
& 0xf80) >> 7;
1644 instruction
->info
.data_proc
.variant
= 1;
1645 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1646 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
=
1648 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1650 /* LSR encodes a shift by 32 bit as 0x0 */
1651 if ((shift
== 0x1) && (shift_imm
== 0x0))
1654 /* ASR encodes a shift by 32 bit as 0x0 */
1655 if ((shift
== 0x2) && (shift_imm
== 0x0))
1658 /* ROR by 32 bit is actually a RRX */
1659 if ((shift
== 0x3) && (shift_imm
== 0x0))
1662 if ((shift_imm
== 0x0) && (shift
== 0x0))
1663 snprintf(shifter_operand
, 32, "r%i", Rm
);
1665 if (shift
== 0x0) /* LSL */
1666 snprintf(shifter_operand
,
1671 else if (shift
== 0x1) /* LSR */
1672 snprintf(shifter_operand
,
1677 else if (shift
== 0x2) /* ASR */
1678 snprintf(shifter_operand
,
1683 else if (shift
== 0x3) /* ROR */
1684 snprintf(shifter_operand
,
1689 else if (shift
== 0x4) /* RRX */
1690 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1692 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1693 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1695 instruction
->info
.data_proc
.variant
= 2;
1696 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1697 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1698 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1700 if (shift
== 0x0) /* LSL */
1701 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1702 else if (shift
== 0x1) /* LSR */
1703 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1704 else if (shift
== 0x2) /* ASR */
1705 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1706 else if (shift
== 0x3) /* ROR */
1707 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1711 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1712 *<shifter_operand> */
1713 snprintf(instruction
->text
,
1715 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1724 } else if ((op
== 0xd) || (op
== 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1725 *<shifter_operand> */
1726 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1727 snprintf(instruction
->text
,
1729 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",
1733 snprintf(instruction
->text
,
1735 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1743 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1744 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1745 address
, opcode
, mnemonic
, COND(opcode
),
1746 Rn
, shifter_operand
);
1752 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1753 struct arm_instruction
*instruction
)
1755 /* clear fields, to avoid confusion */
1756 memset(instruction
, 0, sizeof(struct arm_instruction
));
1757 instruction
->opcode
= opcode
;
1758 instruction
->instruction_size
= 4;
1760 /* catch opcodes with condition field [31:28] = b1111 */
1761 if ((opcode
& 0xf0000000) == 0xf0000000) {
1762 /* Undefined instruction (or ARMv5E cache preload PLD) */
1763 if ((opcode
& 0x08000000) == 0x00000000)
1764 return evaluate_pld(opcode
, address
, instruction
);
1766 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1767 if ((opcode
& 0x0e000000) == 0x08000000)
1768 return evaluate_srs(opcode
, address
, instruction
);
1770 /* Branch and branch with link and change to Thumb */
1771 if ((opcode
& 0x0e000000) == 0x0a000000)
1772 return evaluate_blx_imm(opcode
, address
, instruction
);
1774 /* Extended coprocessor opcode space (ARMv5 and higher)
1775 * Coprocessor load/store and double register transfers */
1776 if ((opcode
& 0x0e000000) == 0x0c000000)
1777 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1779 /* Coprocessor data processing */
1780 if ((opcode
& 0x0f000100) == 0x0c000000)
1781 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1783 /* Coprocessor register transfers */
1784 if ((opcode
& 0x0f000010) == 0x0c000010)
1785 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1787 /* Undefined instruction */
1788 if ((opcode
& 0x0f000000) == 0x0f000000) {
1789 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1790 snprintf(instruction
->text
,
1792 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1799 /* catch opcodes with [27:25] = b000 */
1800 if ((opcode
& 0x0e000000) == 0x00000000) {
1801 /* Multiplies, extra load/stores */
1802 if ((opcode
& 0x00000090) == 0x00000090)
1803 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1805 /* Miscellaneous instructions */
1806 if ((opcode
& 0x0f900000) == 0x01000000)
1807 return evaluate_misc_instr(opcode
, address
, instruction
);
1809 return evaluate_data_proc(opcode
, address
, instruction
);
1812 /* catch opcodes with [27:25] = b001 */
1813 if ((opcode
& 0x0e000000) == 0x02000000) {
1814 /* Undefined instruction */
1815 if ((opcode
& 0x0fb00000) == 0x03000000) {
1816 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1817 snprintf(instruction
->text
,
1819 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1825 /* Move immediate to status register */
1826 if ((opcode
& 0x0fb00000) == 0x03200000)
1827 return evaluate_mrs_msr(opcode
, address
, instruction
);
1829 return evaluate_data_proc(opcode
, address
, instruction
);
1833 /* catch opcodes with [27:25] = b010 */
1834 if ((opcode
& 0x0e000000) == 0x04000000) {
1835 /* Load/store immediate offset */
1836 return evaluate_load_store(opcode
, address
, instruction
);
1839 /* catch opcodes with [27:25] = b011 */
1840 if ((opcode
& 0x0e000000) == 0x06000000) {
1841 /* Load/store register offset */
1842 if ((opcode
& 0x00000010) == 0x00000000)
1843 return evaluate_load_store(opcode
, address
, instruction
);
1845 /* Architecturally Undefined instruction
1846 * ... don't expect these to ever be used
1848 if ((opcode
& 0x07f000f0) == 0x07f000f0) {
1849 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1850 snprintf(instruction
->text
, 128,
1851 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1856 /* "media" instructions */
1857 return evaluate_media(opcode
, address
, instruction
);
1860 /* catch opcodes with [27:25] = b100 */
1861 if ((opcode
& 0x0e000000) == 0x08000000) {
1862 /* Load/store multiple */
1863 return evaluate_ldm_stm(opcode
, address
, instruction
);
1866 /* catch opcodes with [27:25] = b101 */
1867 if ((opcode
& 0x0e000000) == 0x0a000000) {
1868 /* Branch and branch with link */
1869 return evaluate_b_bl(opcode
, address
, instruction
);
1872 /* catch opcodes with [27:25] = b110 */
1873 if ((opcode
& 0x0e000000) == 0x0c000000) {
1874 /* Coprocessor load/store and double register transfers */
1875 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1878 /* catch opcodes with [27:25] = b111 */
1879 if ((opcode
& 0x0e000000) == 0x0e000000) {
1880 /* Software interrupt */
1881 if ((opcode
& 0x0f000000) == 0x0f000000)
1882 return evaluate_swi(opcode
, address
, instruction
);
1884 /* Coprocessor data processing */
1885 if ((opcode
& 0x0f000010) == 0x0e000000)
1886 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1888 /* Coprocessor register transfers */
1889 if ((opcode
& 0x0f000010) == 0x0e000010)
1890 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1893 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1898 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1899 uint32_t address
, struct arm_instruction
*instruction
)
1901 uint32_t offset
= opcode
& 0x7ff;
1902 uint32_t opc
= (opcode
>> 11) & 0x3;
1903 uint32_t target_address
;
1904 char *mnemonic
= NULL
;
1906 /* sign extend 11-bit offset */
1907 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1908 offset
= 0xfffff800 | offset
;
1910 target_address
= address
+ 4 + (offset
<< 1);
1913 /* unconditional branch */
1915 instruction
->type
= ARM_B
;
1920 instruction
->type
= ARM_BLX
;
1922 target_address
&= 0xfffffffc;
1926 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1927 mnemonic
= "prefix";
1928 target_address
= offset
<< 12;
1932 instruction
->type
= ARM_BL
;
1937 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1938 * these are effectively 32-bit instructions even in Thumb1. For
1939 * disassembly, it's simplest to always use the Thumb2 decoder.
1941 * But some cores will evidently handle them as two instructions,
1942 * where exceptions may occur between the two. The ETMv3.2+ ID
1943 * register has a bit which exposes this behavior.
1946 snprintf(instruction
->text
, 128,
1947 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1948 address
, opcode
, mnemonic
, target_address
);
1950 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1951 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1956 static int evaluate_add_sub_thumb(uint16_t opcode
,
1957 uint32_t address
, struct arm_instruction
*instruction
)
1959 uint8_t Rd
= (opcode
>> 0) & 0x7;
1960 uint8_t Rn
= (opcode
>> 3) & 0x7;
1961 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1962 uint32_t opc
= opcode
& (1 << 9);
1963 uint32_t reg_imm
= opcode
& (1 << 10);
1967 instruction
->type
= ARM_SUB
;
1970 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1971 instruction
->type
= ARM_ADD
;
1975 instruction
->info
.data_proc
.Rd
= Rd
;
1976 instruction
->info
.data_proc
.Rn
= Rn
;
1977 instruction
->info
.data_proc
.S
= 1;
1980 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
1981 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1982 snprintf(instruction
->text
, 128,
1983 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1984 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1986 instruction
->info
.data_proc
.variant
= 1;/*immediate shift*/
1987 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1988 snprintf(instruction
->text
, 128,
1989 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1990 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1996 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1997 uint32_t address
, struct arm_instruction
*instruction
)
1999 uint8_t Rd
= (opcode
>> 0) & 0x7;
2000 uint8_t Rm
= (opcode
>> 3) & 0x7;
2001 uint8_t imm
= (opcode
>> 6) & 0x1f;
2002 uint8_t opc
= (opcode
>> 11) & 0x3;
2003 char *mnemonic
= NULL
;
2007 instruction
->type
= ARM_MOV
;
2009 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
2012 instruction
->type
= ARM_MOV
;
2014 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
2017 instruction
->type
= ARM_MOV
;
2019 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
2023 if ((imm
== 0) && (opc
!= 0))
2026 instruction
->info
.data_proc
.Rd
= Rd
;
2027 instruction
->info
.data_proc
.Rn
= -1;
2028 instruction
->info
.data_proc
.S
= 1;
2030 instruction
->info
.data_proc
.variant
= 1;/*immediate_shift*/
2031 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2032 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
2034 snprintf(instruction
->text
, 128,
2035 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2036 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
2041 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
2042 uint32_t address
, struct arm_instruction
*instruction
)
2044 uint8_t imm
= opcode
& 0xff;
2045 uint8_t Rd
= (opcode
>> 8) & 0x7;
2046 uint32_t opc
= (opcode
>> 11) & 0x3;
2047 char *mnemonic
= NULL
;
2049 instruction
->info
.data_proc
.Rd
= Rd
;
2050 instruction
->info
.data_proc
.Rn
= Rd
;
2051 instruction
->info
.data_proc
.S
= 1;
2052 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2053 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
2057 instruction
->type
= ARM_MOV
;
2059 instruction
->info
.data_proc
.Rn
= -1;
2062 instruction
->type
= ARM_CMP
;
2064 instruction
->info
.data_proc
.Rd
= -1;
2067 instruction
->type
= ARM_ADD
;
2071 instruction
->type
= ARM_SUB
;
2076 snprintf(instruction
->text
, 128,
2077 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
2078 address
, opcode
, mnemonic
, Rd
, imm
);
2083 static int evaluate_data_proc_thumb(uint16_t opcode
,
2084 uint32_t address
, struct arm_instruction
*instruction
)
2086 uint8_t high_reg
, op
, Rm
, Rd
, H1
, H2
;
2087 char *mnemonic
= NULL
;
2090 high_reg
= (opcode
& 0x0400) >> 10;
2091 op
= (opcode
& 0x03C0) >> 6;
2093 Rd
= (opcode
& 0x0007);
2094 Rm
= (opcode
& 0x0038) >> 3;
2095 H1
= (opcode
& 0x0080) >> 7;
2096 H2
= (opcode
& 0x0040) >> 6;
2098 instruction
->info
.data_proc
.Rd
= Rd
;
2099 instruction
->info
.data_proc
.Rn
= Rd
;
2100 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2101 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2102 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2111 instruction
->type
= ARM_ADD
;
2115 instruction
->type
= ARM_CMP
;
2119 instruction
->type
= ARM_MOV
;
2125 if ((opcode
& 0x7) == 0x0) {
2126 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2128 instruction
->type
= ARM_BLX
;
2129 snprintf(instruction
->text
, 128,
2131 " 0x%4.4x \tBLX\tr%i",
2132 address
, opcode
, Rm
);
2134 instruction
->type
= ARM_BX
;
2135 snprintf(instruction
->text
, 128,
2137 " 0x%4.4x \tBX\tr%i",
2138 address
, opcode
, Rm
);
2141 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2142 snprintf(instruction
->text
, 128,
2145 "UNDEFINED INSTRUCTION",
2154 instruction
->type
= ARM_AND
;
2158 instruction
->type
= ARM_EOR
;
2162 instruction
->type
= ARM_MOV
;
2164 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2165 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2166 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2167 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2170 instruction
->type
= ARM_MOV
;
2172 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2173 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2174 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2175 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2178 instruction
->type
= ARM_MOV
;
2180 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2181 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2182 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2183 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2186 instruction
->type
= ARM_ADC
;
2190 instruction
->type
= ARM_SBC
;
2194 instruction
->type
= ARM_MOV
;
2196 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2197 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2198 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2199 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2202 instruction
->type
= ARM_TST
;
2206 instruction
->type
= ARM_RSB
;
2208 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2209 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2210 instruction
->info
.data_proc
.Rn
= Rm
;
2213 instruction
->type
= ARM_CMP
;
2217 instruction
->type
= ARM_CMN
;
2221 instruction
->type
= ARM_ORR
;
2225 instruction
->type
= ARM_MUL
;
2229 instruction
->type
= ARM_BIC
;
2233 instruction
->type
= ARM_MVN
;
2240 snprintf(instruction
->text
, 128,
2241 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2243 address
, opcode
, mnemonic
, Rd
, Rm
);
2245 snprintf(instruction
->text
, 128,
2246 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2247 address
, opcode
, mnemonic
, Rd
, Rm
);
2252 /* PC-relative data addressing is word-aligned even with Thumb */
2253 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2255 return (addr
+ 4) & ~3;
2258 static int evaluate_load_literal_thumb(uint16_t opcode
,
2259 uint32_t address
, struct arm_instruction
*instruction
)
2262 uint8_t Rd
= (opcode
>> 8) & 0x7;
2264 instruction
->type
= ARM_LDR
;
2265 immediate
= opcode
& 0x000000ff;
2268 instruction
->info
.load_store
.Rd
= Rd
;
2269 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2270 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2271 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2272 instruction
->info
.load_store
.offset
.offset
= immediate
;
2274 snprintf(instruction
->text
, 128,
2275 "0x%8.8" PRIx32
" 0x%4.4x \t"
2276 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2277 address
, opcode
, Rd
, immediate
,
2278 thumb_alignpc4(address
) + immediate
);
2283 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2284 uint32_t address
, struct arm_instruction
*instruction
)
2286 uint8_t Rd
= (opcode
>> 0) & 0x7;
2287 uint8_t Rn
= (opcode
>> 3) & 0x7;
2288 uint8_t Rm
= (opcode
>> 6) & 0x7;
2289 uint8_t opc
= (opcode
>> 9) & 0x7;
2290 char *mnemonic
= NULL
;
2294 instruction
->type
= ARM_STR
;
2298 instruction
->type
= ARM_STRH
;
2302 instruction
->type
= ARM_STRB
;
2306 instruction
->type
= ARM_LDRSB
;
2310 instruction
->type
= ARM_LDR
;
2314 instruction
->type
= ARM_LDRH
;
2318 instruction
->type
= ARM_LDRB
;
2322 instruction
->type
= ARM_LDRSH
;
2327 snprintf(instruction
->text
, 128,
2328 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2329 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2331 instruction
->info
.load_store
.Rd
= Rd
;
2332 instruction
->info
.load_store
.Rn
= Rn
;
2333 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2334 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2335 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2340 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2341 uint32_t address
, struct arm_instruction
*instruction
)
2343 uint32_t offset
= (opcode
>> 6) & 0x1f;
2344 uint8_t Rd
= (opcode
>> 0) & 0x7;
2345 uint8_t Rn
= (opcode
>> 3) & 0x7;
2346 uint32_t L
= opcode
& (1 << 11);
2347 uint32_t B
= opcode
& (1 << 12);
2353 instruction
->type
= ARM_LDR
;
2356 instruction
->type
= ARM_STR
;
2360 if ((opcode
&0xF000) == 0x8000) {
2368 snprintf(instruction
->text
, 128,
2369 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2370 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2372 instruction
->info
.load_store
.Rd
= Rd
;
2373 instruction
->info
.load_store
.Rn
= Rn
;
2374 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2375 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2376 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2381 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2382 uint32_t address
, struct arm_instruction
*instruction
)
2384 uint32_t offset
= opcode
& 0xff;
2385 uint8_t Rd
= (opcode
>> 8) & 0x7;
2386 uint32_t L
= opcode
& (1 << 11);
2390 instruction
->type
= ARM_LDR
;
2393 instruction
->type
= ARM_STR
;
2397 snprintf(instruction
->text
, 128,
2398 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2399 address
, opcode
, mnemonic
, Rd
, offset
*4);
2401 instruction
->info
.load_store
.Rd
= Rd
;
2402 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2403 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2404 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2405 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2410 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2411 uint32_t address
, struct arm_instruction
*instruction
)
2413 uint32_t imm
= opcode
& 0xff;
2414 uint8_t Rd
= (opcode
>> 8) & 0x7;
2416 uint32_t SP
= opcode
& (1 << 11);
2417 const char *reg_name
;
2419 instruction
->type
= ARM_ADD
;
2429 snprintf(instruction
->text
, 128,
2430 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2431 address
, opcode
, Rd
, reg_name
, imm
* 4);
2433 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2434 instruction
->info
.data_proc
.Rd
= Rd
;
2435 instruction
->info
.data_proc
.Rn
= Rn
;
2436 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2441 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2442 uint32_t address
, struct arm_instruction
*instruction
)
2444 uint32_t imm
= opcode
& 0x7f;
2445 uint8_t opc
= opcode
& (1 << 7);
2450 instruction
->type
= ARM_SUB
;
2453 instruction
->type
= ARM_ADD
;
2457 snprintf(instruction
->text
, 128,
2458 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2459 address
, opcode
, mnemonic
, imm
*4);
2461 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2462 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2463 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2464 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2469 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2470 uint32_t address
, struct arm_instruction
*instruction
)
2472 uint32_t imm
= opcode
& 0xff;
2474 instruction
->type
= ARM_BKPT
;
2476 snprintf(instruction
->text
, 128,
2477 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2478 address
, opcode
, imm
);
2483 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2484 uint32_t address
, struct arm_instruction
*instruction
)
2486 uint32_t reg_list
= opcode
& 0xff;
2487 uint32_t L
= opcode
& (1 << 11);
2488 uint32_t R
= opcode
& (1 << 8);
2489 uint8_t Rn
= (opcode
>> 8) & 7;
2490 uint8_t addr_mode
= 0 /* IA */;
2494 char ptr_name
[7] = "";
2497 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2498 * The STMIA and LDMIA opcodes are used for other instructions.
2501 if ((opcode
& 0xf000) == 0xc000) { /* generic load/store multiple */
2505 instruction
->type
= ARM_LDM
;
2507 if (opcode
& (1 << Rn
))
2510 instruction
->type
= ARM_STM
;
2513 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2514 } else {/* push/pop */
2517 instruction
->type
= ARM_LDM
;
2520 reg_list
|= (1 << 15) /*PC*/;
2522 instruction
->type
= ARM_STM
;
2524 addr_mode
= 3; /*DB*/
2526 reg_list
|= (1 << 14) /*LR*/;
2530 reg_names_p
= reg_names
;
2531 for (i
= 0; i
<= 15; i
++) {
2532 if (reg_list
& (1 << i
))
2533 reg_names_p
+= snprintf(reg_names_p
,
2534 (reg_names
+ 40 - reg_names_p
),
2538 if (reg_names_p
> reg_names
)
2539 reg_names_p
[-2] = '\0';
2540 else /* invalid op : no registers */
2541 reg_names
[0] = '\0';
2543 snprintf(instruction
->text
, 128,
2544 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2545 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2547 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2548 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2549 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2554 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2555 uint32_t address
, struct arm_instruction
*instruction
)
2557 uint32_t offset
= opcode
& 0xff;
2558 uint8_t cond
= (opcode
>> 8) & 0xf;
2559 uint32_t target_address
;
2562 instruction
->type
= ARM_SWI
;
2563 snprintf(instruction
->text
, 128,
2564 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2565 address
, opcode
, offset
);
2567 } else if (cond
== 0xe) {
2568 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2569 snprintf(instruction
->text
, 128,
2570 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2575 /* sign extend 8-bit offset */
2576 if (offset
& 0x00000080)
2577 offset
= 0xffffff00 | offset
;
2579 target_address
= address
+ 4 + (offset
<< 1);
2581 snprintf(instruction
->text
, 128,
2582 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2584 arm_condition_strings
[cond
], target_address
);
2586 instruction
->type
= ARM_B
;
2587 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2588 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2593 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2594 struct arm_instruction
*instruction
)
2598 /* added in Thumb2 */
2599 offset
= (opcode
>> 3) & 0x1f;
2600 offset
|= (opcode
& 0x0200) >> 4;
2602 snprintf(instruction
->text
, 128,
2603 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2605 (opcode
& 0x0800) ? "N" : "",
2606 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2611 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2612 struct arm_instruction
*instruction
)
2614 /* added in ARMv6 */
2615 snprintf(instruction
->text
, 128,
2616 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2618 (opcode
& 0x0080) ? 'U' : 'S',
2619 (opcode
& 0x0040) ? 'B' : 'H',
2620 opcode
& 0x7, (opcode
>> 3) & 0x7);
2625 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2626 struct arm_instruction
*instruction
)
2628 /* added in ARMv6 */
2629 if ((opcode
& 0x0ff0) == 0x0650)
2630 snprintf(instruction
->text
, 128,
2631 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2633 (opcode
& 0x80) ? "BE" : "LE");
2634 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2635 snprintf(instruction
->text
, 128,
2636 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2638 (opcode
& 0x0010) ? 'D' : 'E',
2639 (opcode
& 0x0004) ? "A" : "",
2640 (opcode
& 0x0002) ? "I" : "",
2641 (opcode
& 0x0001) ? "F" : "");
2646 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2647 struct arm_instruction
*instruction
)
2651 /* added in ARMv6 */
2652 switch ((opcode
>> 6) & 3) {
2663 snprintf(instruction
->text
, 128,
2664 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2665 address
, opcode
, suffix
,
2666 opcode
& 0x7, (opcode
>> 3) & 0x7);
2671 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2672 struct arm_instruction
*instruction
)
2676 switch ((opcode
>> 4) & 0x0f) {
2693 hint
= "HINT (UNRECOGNIZED)";
2697 snprintf(instruction
->text
, 128,
2698 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2699 address
, opcode
, hint
);
2704 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2705 struct arm_instruction
*instruction
)
2707 unsigned cond
= (opcode
>> 4) & 0x0f;
2708 char *x
= "", *y
= "", *z
= "";
2711 z
= (opcode
& 0x02) ? "T" : "E";
2713 y
= (opcode
& 0x04) ? "T" : "E";
2715 x
= (opcode
& 0x08) ? "T" : "E";
2717 snprintf(instruction
->text
, 128,
2718 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2720 x
, y
, z
, arm_condition_strings
[cond
]);
2722 /* NOTE: strictly speaking, the next 1-4 instructions should
2723 * now be displayed with the relevant conditional suffix...
2729 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2731 /* clear fields, to avoid confusion */
2732 memset(instruction
, 0, sizeof(struct arm_instruction
));
2733 instruction
->opcode
= opcode
;
2734 instruction
->instruction_size
= 2;
2736 if ((opcode
& 0xe000) == 0x0000) {
2737 /* add/substract register or immediate */
2738 if ((opcode
& 0x1800) == 0x1800)
2739 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2740 /* shift by immediate */
2742 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2745 /* Add/substract/compare/move immediate */
2746 if ((opcode
& 0xe000) == 0x2000)
2747 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2749 /* Data processing instructions */
2750 if ((opcode
& 0xf800) == 0x4000)
2751 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2753 /* Load from literal pool */
2754 if ((opcode
& 0xf800) == 0x4800)
2755 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2757 /* Load/Store register offset */
2758 if ((opcode
& 0xf000) == 0x5000)
2759 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2761 /* Load/Store immediate offset */
2762 if (((opcode
& 0xe000) == 0x6000)
2763 || ((opcode
& 0xf000) == 0x8000))
2764 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2766 /* Load/Store from/to stack */
2767 if ((opcode
& 0xf000) == 0x9000)
2768 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2771 if ((opcode
& 0xf000) == 0xa000)
2772 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2775 if ((opcode
& 0xf000) == 0xb000) {
2776 switch ((opcode
>> 8) & 0x0f) {
2778 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2783 return evaluate_cb_thumb(opcode
, address
, instruction
);
2785 return evaluate_extend_thumb(opcode
, address
, instruction
);
2790 return evaluate_load_store_multiple_thumb(opcode
, address
,
2793 return evaluate_cps_thumb(opcode
, address
, instruction
);
2795 if ((opcode
& 0x00c0) == 0x0080)
2797 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2799 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2801 if (opcode
& 0x000f)
2802 return evaluate_ifthen_thumb(opcode
, address
,
2805 return evaluate_hint_thumb(opcode
, address
,
2809 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2810 snprintf(instruction
->text
, 128,
2811 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2816 /* Load/Store multiple */
2817 if ((opcode
& 0xf000) == 0xc000)
2818 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2820 /* Conditional branch + SWI */
2821 if ((opcode
& 0xf000) == 0xd000)
2822 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2824 if ((opcode
& 0xe000) == 0xe000) {
2825 /* Undefined instructions */
2826 if ((opcode
& 0xf801) == 0xe801) {
2827 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2828 snprintf(instruction
->text
, 128,
2829 "0x%8.8" PRIx32
" 0x%8.8x\t"
2830 "UNDEFINED INSTRUCTION",
2833 } else /* Branch to offset */
2834 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2837 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2841 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2842 struct arm_instruction
*instruction
, char *cp
)
2845 unsigned b21
= 1 << 21;
2846 unsigned b22
= 1 << 22;
2848 /* instead of combining two smaller 16-bit branch instructions,
2849 * Thumb2 uses only one larger 32-bit instruction.
2851 offset
= opcode
& 0x7ff;
2852 offset
|= (opcode
& 0x03ff0000) >> 5;
2853 if (opcode
& (1 << 26)) {
2854 offset
|= 0xff << 23;
2855 if ((opcode
& (1 << 11)) == 0)
2857 if ((opcode
& (1 << 13)) == 0)
2860 if (opcode
& (1 << 11))
2862 if (opcode
& (1 << 13))
2870 address
+= offset
<< 1;
2872 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2873 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2874 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2875 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2876 (opcode
& (1 << 14)) ? "BL" : "B.W",
2882 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2883 struct arm_instruction
*instruction
, char *cp
)
2886 unsigned b17
= 1 << 17;
2887 unsigned b18
= 1 << 18;
2888 unsigned cond
= (opcode
>> 22) & 0x0f;
2890 offset
= opcode
& 0x7ff;
2891 offset
|= (opcode
& 0x003f0000) >> 5;
2892 if (opcode
& (1 << 26)) {
2893 offset
|= 0x1fff << 19;
2894 if ((opcode
& (1 << 11)) == 0)
2896 if ((opcode
& (1 << 13)) == 0)
2899 if (opcode
& (1 << 11))
2901 if (opcode
& (1 << 13))
2908 address
+= offset
<< 1;
2910 instruction
->type
= ARM_B
;
2911 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2912 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2913 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2914 arm_condition_strings
[cond
],
2920 static const char *special_name(int number
)
2922 char *special
= "(RESERVED)";
2953 special
= "primask";
2956 special
= "basepri";
2959 special
= "basepri_max";
2962 special
= "faultmask";
2965 special
= "control";
2971 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2972 struct arm_instruction
*instruction
, char *cp
)
2974 const char *mnemonic
;
2976 if (opcode
& 0x0700) {
2977 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2978 strcpy(cp
, "UNDEFINED");
2982 if (opcode
& 0x00f0) {
2983 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2987 switch (opcode
& 0x0f) {
2992 mnemonic
= "YIELD.W";
3004 mnemonic
= "HINT.W (UNRECOGNIZED)";
3007 strcpy(cp
, mnemonic
);
3011 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3012 struct arm_instruction
*instruction
, char *cp
)
3014 const char *mnemonic
;
3016 switch ((opcode
>> 4) & 0x0f) {
3018 mnemonic
= "LEAVEX";
3021 mnemonic
= "ENTERX";
3036 return ERROR_COMMAND_SYNTAX_ERROR
;
3038 strcpy(cp
, mnemonic
);
3042 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3043 struct arm_instruction
*instruction
, char *cp
)
3045 /* permanently undefined */
3046 if ((opcode
& 0x07f07000) == 0x07f02000) {
3047 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3048 strcpy(cp
, "UNDEFINED");
3052 switch ((opcode
>> 12) & 0x5) {
3055 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3059 if (((opcode
>> 23) & 0x07) != 0x07)
3060 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3061 if (opcode
& (1 << 26))
3066 switch ((opcode
>> 20) & 0x7f) {
3069 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3070 (int) (opcode
>> 16) & 0x0f);
3073 return t2ev_hint(opcode
, address
, instruction
, cp
);
3075 return t2ev_misc(opcode
, address
, instruction
, cp
);
3077 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3081 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3082 special_name(opcode
& 0xff));
3087 return ERROR_COMMAND_SYNTAX_ERROR
;
3090 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3091 struct arm_instruction
*instruction
, char *cp
)
3093 char *mnemonic
= NULL
;
3094 int rn
= (opcode
>> 16) & 0xf;
3095 int rd
= (opcode
>> 8) & 0xf;
3096 unsigned immed
= opcode
& 0xff;
3102 /* ARMv7-M: A5.3.2 Modified immediate constants */
3103 func
= (opcode
>> 11) & 0x0e;
3106 if (opcode
& (1 << 26))
3109 /* "Modified" immediates */
3110 switch (func
>> 1) {
3117 immed
+= immed
<< 16;
3120 immed
+= immed
<< 8;
3121 immed
+= immed
<< 16;
3125 immed
= ror(immed
, func
);
3128 if (opcode
& (1 << 20))
3131 switch ((opcode
>> 21) & 0xf) {
3134 instruction
->type
= ARM_TST
;
3140 instruction
->type
= ARM_AND
;
3145 instruction
->type
= ARM_BIC
;
3150 instruction
->type
= ARM_MOV
;
3155 instruction
->type
= ARM_ORR
;
3161 instruction
->type
= ARM_MVN
;
3165 /* instruction->type = ARM_ORN; */
3171 instruction
->type
= ARM_TEQ
;
3177 instruction
->type
= ARM_EOR
;
3183 instruction
->type
= ARM_CMN
;
3189 instruction
->type
= ARM_ADD
;
3195 instruction
->type
= ARM_ADC
;
3200 instruction
->type
= ARM_SBC
;
3205 instruction
->type
= ARM_CMP
;
3211 instruction
->type
= ARM_SUB
;
3217 instruction
->type
= ARM_RSB
;
3222 return ERROR_COMMAND_SYNTAX_ERROR
;
3226 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3227 mnemonic
, suffix2
, rd
, immed
, immed
);
3229 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3230 mnemonic
, suffix
, suffix2
,
3231 rd
, rn
, immed
, immed
);
3236 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3237 struct arm_instruction
*instruction
, char *cp
)
3239 char *mnemonic
= NULL
;
3240 int rn
= (opcode
>> 16) & 0xf;
3241 int rd
= (opcode
>> 8) & 0xf;
3244 bool is_signed
= false;
3246 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3247 if (opcode
& (1 << 26))
3250 switch ((opcode
>> 20) & 0x1f) {
3259 immed
|= (opcode
>> 4) & 0xf000;
3260 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3268 /* move constant to top 16 bits of register */
3269 immed
|= (opcode
>> 4) & 0xf000;
3270 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3277 /* signed/unsigned saturated add */
3278 immed
= (opcode
>> 6) & 0x03;
3279 immed
|= (opcode
>> 10) & 0x1c;
3280 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3281 is_signed
? "S" : "U",
3282 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3283 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3284 immed
? immed
: 32);
3290 /* signed/unsigned bitfield extract */
3291 immed
= (opcode
>> 6) & 0x03;
3292 immed
|= (opcode
>> 10) & 0x1c;
3293 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3294 is_signed
? "S" : "U",
3296 (int) (opcode
& 0x1f) + 1);
3299 immed
= (opcode
>> 6) & 0x03;
3300 immed
|= (opcode
>> 10) & 0x1c;
3301 if (rn
== 0xf) /* bitfield clear */
3302 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3304 (int) (opcode
& 0x1f) + 1 - immed
);
3305 else /* bitfield insert */
3306 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3308 (int) (opcode
& 0x1f) + 1 - immed
);
3311 return ERROR_COMMAND_SYNTAX_ERROR
;
3314 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3315 rd
, rn
, immed
, immed
);
3319 address
= thumb_alignpc4(address
);
3324 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3325 * not hiding the pc-relative stuff will sometimes be useful.
3327 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3331 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3332 struct arm_instruction
*instruction
, char *cp
)
3334 unsigned op
= (opcode
>> 20) & 0xf;
3340 unsigned rn
= (opcode
>> 16) & 0x0f;
3341 unsigned rt
= (opcode
>> 12) & 0x0f;
3344 return ERROR_COMMAND_SYNTAX_ERROR
;
3346 if (opcode
& 0x0800)
3381 return ERROR_COMMAND_SYNTAX_ERROR
;
3384 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3385 size
, rt
, rn
, (int) opcode
& 0x0f,
3386 (int) (opcode
>> 4) & 0x03);
3390 immed
= opcode
& 0x0fff;
3391 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3392 size
, rt
, rn
, immed
, immed
);
3396 immed
= opcode
& 0x00ff;
3398 switch (opcode
& 0x700) {
3404 return ERROR_COMMAND_SYNTAX_ERROR
;
3407 /* two indexed modes will write back rn */
3408 if (opcode
& 0x100) {
3409 if (opcode
& 0x400) /* pre-indexed */
3411 else { /* post-indexed */
3417 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3418 size
, suffix
, rt
, rn
, p1
,
3419 (opcode
& 0x200) ? "" : "-",
3424 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3425 struct arm_instruction
*instruction
, char *cp
)
3427 int ra
= (opcode
>> 12) & 0xf;
3429 switch (opcode
& 0x007000f0) {
3432 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3433 (int) (opcode
>> 8) & 0xf,
3434 (int) (opcode
>> 16) & 0xf,
3435 (int) (opcode
>> 0) & 0xf);
3437 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3438 (int) (opcode
>> 8) & 0xf,
3439 (int) (opcode
>> 16) & 0xf,
3440 (int) (opcode
>> 0) & 0xf, ra
);
3443 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3444 (int) (opcode
>> 8) & 0xf,
3445 (int) (opcode
>> 16) & 0xf,
3446 (int) (opcode
>> 0) & 0xf, ra
);
3449 return ERROR_COMMAND_SYNTAX_ERROR
;
3454 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3455 struct arm_instruction
*instruction
, char *cp
)
3457 int op
= (opcode
>> 4) & 0xf;
3458 char *infix
= "MUL";
3460 op
+= (opcode
>> 16) & 0x70;
3468 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3469 (op
& 0x20) ? 'U' : 'S',
3471 (int) (opcode
>> 12) & 0xf,
3472 (int) (opcode
>> 8) & 0xf,
3473 (int) (opcode
>> 16) & 0xf,
3474 (int) (opcode
>> 0) & 0xf);
3478 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3479 (op
& 0x20) ? 'U' : 'S',
3480 (int) (opcode
>> 8) & 0xf,
3481 (int) (opcode
>> 16) & 0xf,
3482 (int) (opcode
>> 0) & 0xf);
3485 return ERROR_COMMAND_SYNTAX_ERROR
;
3491 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3492 struct arm_instruction
*instruction
, char *cp
)
3494 int rn
= (opcode
>> 16) & 0xf;
3495 int op
= (opcode
>> 22) & 0x6;
3496 int t
= (opcode
>> 21) & 1;
3497 unsigned registers
= opcode
& 0xffff;
3500 if (opcode
& (1 << 20))
3508 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3510 (unsigned) (opcode
& 0x1f));
3516 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3517 (unsigned) ((opcode
>> 16) & 0xf),
3521 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3525 sprintf(cp
, "POP.W\t");
3527 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3531 sprintf(cp
, "PUSH.W\t");
3533 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3536 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3539 return ERROR_COMMAND_SYNTAX_ERROR
;
3544 for (t
= 0; registers
; t
++, registers
>>= 1) {
3545 if ((registers
& 1) == 0)
3548 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3557 /* load/store dual or exclusive, table branch */
3558 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3559 struct arm_instruction
*instruction
, char *cp
)
3561 unsigned op1op2
= (opcode
>> 20) & 0x3;
3562 unsigned op3
= (opcode
>> 4) & 0xf;
3564 unsigned rn
= (opcode
>> 16) & 0xf;
3565 unsigned rt
= (opcode
>> 12) & 0xf;
3566 unsigned rd
= (opcode
>> 8) & 0xf;
3567 unsigned imm
= opcode
& 0xff;
3571 op1op2
|= (opcode
>> 21) & 0xc;
3601 mnemonic
= "STREXB";
3604 mnemonic
= "STREXH";
3607 return ERROR_COMMAND_SYNTAX_ERROR
;
3615 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3618 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3621 mnemonic
= "LDREXB";
3624 mnemonic
= "LDREXH";
3627 return ERROR_COMMAND_SYNTAX_ERROR
;
3632 return ERROR_COMMAND_SYNTAX_ERROR
;
3637 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3638 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3640 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3641 mnemonic
, rd
, rt
, rn
);
3647 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3648 mnemonic
, rt
, rn
, imm
, imm
);
3650 sprintf(cp
, "%s\tr%u, [r%u]",
3655 /* two indexed modes will write back rn */
3656 if (opcode
& (1 << 21)) {
3657 if (opcode
& (1 << 24)) /* pre-indexed */
3659 else { /* post-indexed */
3666 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3667 mnemonic
, rt
, rd
, rn
, p1
,
3668 (opcode
& (1 << 23)) ? "" : "-",
3673 address
= thumb_alignpc4(address
);
3675 if (opcode
& (1 << 23))
3679 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3680 mnemonic
, rt
, rd
, address
);
3684 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3685 struct arm_instruction
*instruction
, char *cp
)
3687 int op
= (opcode
>> 21) & 0xf;
3688 int rd
= (opcode
>> 8) & 0xf;
3689 int rn
= (opcode
>> 16) & 0xf;
3690 int type
= (opcode
>> 4) & 0x3;
3691 int immed
= (opcode
>> 6) & 0x3;
3695 immed
|= (opcode
>> 10) & 0x1c;
3696 if (opcode
& (1 << 20))
3702 if (!(opcode
& (1 << 20)))
3703 return ERROR_COMMAND_SYNTAX_ERROR
;
3704 instruction
->type
= ARM_TST
;
3709 instruction
->type
= ARM_AND
;
3713 instruction
->type
= ARM_BIC
;
3718 instruction
->type
= ARM_MOV
;
3722 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3724 (int) (opcode
& 0xf));
3737 sprintf(cp
, "RRX%s\tr%d, r%d",
3739 (int) (opcode
& 0xf));
3747 instruction
->type
= ARM_ORR
;
3753 instruction
->type
= ARM_MVN
;
3758 /* instruction->type = ARM_ORN; */
3764 if (!(opcode
& (1 << 20)))
3765 return ERROR_COMMAND_SYNTAX_ERROR
;
3766 instruction
->type
= ARM_TEQ
;
3771 instruction
->type
= ARM_EOR
;
3776 if (!(opcode
& (1 << 20)))
3777 return ERROR_COMMAND_SYNTAX_ERROR
;
3778 instruction
->type
= ARM_CMN
;
3783 instruction
->type
= ARM_ADD
;
3787 instruction
->type
= ARM_ADC
;
3791 instruction
->type
= ARM_SBC
;
3796 if (!(opcode
& (1 << 21)))
3797 return ERROR_COMMAND_SYNTAX_ERROR
;
3798 instruction
->type
= ARM_CMP
;
3803 instruction
->type
= ARM_SUB
;
3807 instruction
->type
= ARM_RSB
;
3811 return ERROR_COMMAND_SYNTAX_ERROR
;
3814 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3815 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3838 strcpy(cp
, ", RRX");
3844 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3848 sprintf(cp
, "%s%s.W\tr%d, r%d",
3849 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3853 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3854 mnemonic
, suffix
, rd
,
3855 (int) (opcode
& 0xf), immed
? immed
: 32);
3859 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3860 struct arm_instruction
*instruction
, char *cp
)
3865 if (((opcode
>> 4) & 0xf) == 0) {
3866 switch ((opcode
>> 21) & 0x7) {
3880 return ERROR_COMMAND_SYNTAX_ERROR
;
3883 instruction
->type
= ARM_MOV
;
3884 if (opcode
& (1 << 20))
3886 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3888 (int) (opcode
>> 8) & 0xf,
3889 (int) (opcode
>> 16) & 0xf,
3890 (int) (opcode
>> 0) & 0xf);
3892 } else if (opcode
& (1 << 7)) {
3893 switch ((opcode
>> 20) & 0xf) {
3898 switch ((opcode
>> 4) & 0x3) {
3900 suffix
= ", ROR #8";
3903 suffix
= ", ROR #16";
3906 suffix
= ", ROR #24";
3909 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3910 (opcode
& (1 << 24)) ? 'U' : 'S',
3911 (opcode
& (1 << 26)) ? 'B' : 'H',
3912 (int) (opcode
>> 8) & 0xf,
3913 (int) (opcode
>> 0) & 0xf,
3920 if (opcode
& (1 << 6))
3921 return ERROR_COMMAND_SYNTAX_ERROR
;
3922 if (((opcode
>> 12) & 0xf) != 0xf)
3923 return ERROR_COMMAND_SYNTAX_ERROR
;
3924 if (!(opcode
& (1 << 20)))
3925 return ERROR_COMMAND_SYNTAX_ERROR
;
3927 switch (((opcode
>> 19) & 0x04)
3928 | ((opcode
>> 4) & 0x3)) {
3933 mnemonic
= "REV16.W";
3939 mnemonic
= "REVSH.W";
3945 return ERROR_COMMAND_SYNTAX_ERROR
;
3947 sprintf(cp
, "%s\tr%d, r%d",
3949 (int) (opcode
>> 8) & 0xf,
3950 (int) (opcode
>> 0) & 0xf);
3953 return ERROR_COMMAND_SYNTAX_ERROR
;
3960 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3961 struct arm_instruction
*instruction
, char *cp
)
3963 int rn
= (opcode
>> 16) & 0xf;
3966 instruction
->type
= ARM_LDR
;
3969 immed
= opcode
& 0x0fff;
3970 if ((opcode
& (1 << 23)) == 0)
3972 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3973 (int) (opcode
>> 12) & 0xf,
3974 thumb_alignpc4(address
) + immed
);
3978 if (opcode
& (1 << 23)) {
3979 immed
= opcode
& 0x0fff;
3980 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3981 (int) (opcode
>> 12) & 0xf,
3986 if (!(opcode
& (0x3f << 6))) {
3987 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3988 (int) (opcode
>> 12) & 0xf,
3990 (int) (opcode
>> 0) & 0xf,
3991 (int) (opcode
>> 4) & 0x3);
3996 if (((opcode
>> 8) & 0xf) == 0xe) {
3997 immed
= opcode
& 0x00ff;
3999 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4000 (int) (opcode
>> 12) & 0xf,
4005 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4006 char *p1
= "]", *p2
= "";
4008 if (!(opcode
& 0x0500))
4009 return ERROR_COMMAND_SYNTAX_ERROR
;
4011 immed
= opcode
& 0x00ff;
4013 /* two indexed modes will write back rn */
4014 if (opcode
& 0x100) {
4015 if (opcode
& 0x400) /* pre-indexed */
4017 else { /* post-indexed */
4023 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4024 (int) (opcode
>> 12) & 0xf,
4026 (opcode
& 0x200) ? "" : "-",
4031 return ERROR_COMMAND_SYNTAX_ERROR
;
4034 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4035 struct arm_instruction
*instruction
, char *cp
)
4037 int rn
= (opcode
>> 16) & 0xf;
4038 int rt
= (opcode
>> 12) & 0xf;
4039 int op2
= (opcode
>> 6) & 0x3f;
4041 char *p1
= "", *p2
= "]";
4044 switch ((opcode
>> 23) & 0x3) {
4046 if ((rn
& rt
) == 0xf) {
4048 immed
= opcode
& 0xfff;
4049 address
= thumb_alignpc4(address
);
4050 if (opcode
& (1 << 23))
4054 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4058 if (rn
== 0x0f && rt
!= 0x0f) {
4060 immed
= opcode
& 0xfff;
4061 address
= thumb_alignpc4(address
);
4062 if (opcode
& (1 << 23))
4066 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4072 if ((op2
& 0x3c) == 0x38) {
4073 immed
= opcode
& 0xff;
4074 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4075 rt
, rn
, immed
, immed
);
4078 if ((op2
& 0x3c) == 0x30) {
4080 immed
= opcode
& 0xff;
4083 p1
= (opcode
& (1 << 21)) ? "W" : "";
4084 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4085 p1
, rn
, immed
, immed
);
4090 immed
= opcode
& 0xff;
4091 if (!(opcode
& 0x200))
4094 /* two indexed modes will write back rn */
4095 if (opcode
& 0x100) {
4096 if (opcode
& 0x400) /* pre-indexed */
4098 else { /* post-indexed */
4104 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4105 mnemonic
, rt
, rn
, p1
,
4109 if ((op2
& 0x24) == 0x24) {
4111 goto ldrxb_immediate_t3
;
4114 int rm
= opcode
& 0xf;
4117 sprintf(cp
, "PLD\t");
4119 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4120 immed
= (opcode
>> 4) & 0x3;
4122 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4127 if ((rn
& rt
) == 0xf)
4130 immed
= opcode
& 0xfff;
4131 goto preload_immediate
;
4135 mnemonic
= "LDRB.W";
4136 immed
= opcode
& 0xfff;
4137 goto ldrxb_immediate_t2
;
4139 if ((rn
& rt
) == 0xf) {
4140 immed
= opcode
& 0xfff;
4141 address
= thumb_alignpc4(address
);
4142 if (opcode
& (1 << 23))
4146 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4149 if (rn
== 0xf && rt
!= 0xf) {
4151 immed
= opcode
& 0xfff;
4152 address
= thumb_alignpc4(address
);
4153 if (opcode
& (1 << 23))
4157 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4162 if ((op2
& 0x3c) == 0x38) {
4163 immed
= opcode
& 0xff;
4164 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4165 rt
, rn
, immed
, immed
);
4168 if ((op2
& 0x3c) == 0x30) {
4170 immed
= opcode
& 0xff;
4171 immed
= -immed
; /* pli */
4172 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4177 goto ldrxb_immediate_t3
;
4179 if ((op2
& 0x24) == 0x24) {
4181 goto ldrxb_immediate_t3
;
4184 int rm
= opcode
& 0xf;
4187 sprintf(cp
, "PLI\t");
4189 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4190 immed
= (opcode
>> 4) & 0x3;
4192 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4198 immed
= opcode
& 0xfff;
4199 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4205 immed
= opcode
& 0xfff;
4207 goto ldrxb_immediate_t2
;
4210 return ERROR_COMMAND_SYNTAX_ERROR
;
4213 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4214 struct arm_instruction
*instruction
, char *cp
)
4216 int rn
= (opcode
>> 16) & 0xf;
4217 int rt
= (opcode
>> 12) & 0xf;
4218 int op2
= (opcode
>> 6) & 0x3f;
4223 sprintf(cp
, "HINT (UNALLOCATED)");
4227 if (opcode
& (1 << 24))
4230 if ((opcode
& (1 << 23)) == 0) {
4233 immed
= opcode
& 0xfff;
4234 address
= thumb_alignpc4(address
);
4235 if (opcode
& (1 << 23))
4239 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4244 int rm
= opcode
& 0xf;
4246 immed
= (opcode
>> 4) & 0x3;
4247 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4248 sign
, rt
, rn
, rm
, immed
);
4251 if ((op2
& 0x3c) == 0x38) {
4252 immed
= opcode
& 0xff;
4253 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4254 sign
, rt
, rn
, immed
, immed
);
4257 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4258 char *p1
= "", *p2
= "]";
4260 immed
= opcode
& 0xff;
4261 if (!(opcode
& 0x200))
4264 /* two indexed modes will write back rn */
4265 if (opcode
& 0x100) {
4266 if (opcode
& 0x400) /* pre-indexed */
4268 else { /* post-indexed */
4273 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4274 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4281 immed
= opcode
& 0xfff;
4282 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4283 sign
, *sign
? "" : ".W",
4284 rt
, rn
, immed
, immed
);
4288 return ERROR_COMMAND_SYNTAX_ERROR
;
4292 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4293 * always set. That means eventual arm_simulate_step() support for Thumb2
4294 * will need work in this area.
4296 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4303 /* clear low bit ... it's set on function pointers */
4306 /* clear fields, to avoid confusion */
4307 memset(instruction
, 0, sizeof(struct arm_instruction
));
4309 /* read first halfword, see if this is the only one */
4310 retval
= target_read_u16(target
, address
, &op
);
4311 if (retval
!= ERROR_OK
)
4314 switch (op
& 0xf800) {
4318 /* 32-bit instructions */
4319 instruction
->instruction_size
= 4;
4321 retval
= target_read_u16(target
, address
+ 2, &op
);
4322 if (retval
!= ERROR_OK
)
4325 instruction
->opcode
= opcode
;
4328 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4329 return thumb_evaluate_opcode(op
, address
, instruction
);
4332 snprintf(instruction
->text
, 128,
4333 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4335 cp
= strchr(instruction
->text
, 0);
4336 retval
= ERROR_FAIL
;
4338 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4339 if ((opcode
& 0x1a008000) == 0x10000000)
4340 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4342 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4343 else if ((opcode
& 0x1a008000) == 0x12000000)
4344 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4346 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4347 else if ((opcode
& 0x18008000) == 0x10008000)
4348 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4350 /* ARMv7-M: A5.3.5 Load/store multiple */
4351 else if ((opcode
& 0x1e400000) == 0x08000000)
4352 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4354 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4355 else if ((opcode
& 0x1e400000) == 0x08400000)
4356 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4358 /* ARMv7-M: A5.3.7 Load word */
4359 else if ((opcode
& 0x1f700000) == 0x18500000)
4360 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4362 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4363 else if ((opcode
& 0x1e700000) == 0x18300000)
4364 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4366 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4367 else if ((opcode
& 0x1e700000) == 0x18100000)
4368 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4370 /* ARMv7-M: A5.3.10 Store single data item */
4371 else if ((opcode
& 0x1f100000) == 0x18000000)
4372 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4374 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4375 else if ((opcode
& 0x1e000000) == 0x0a000000)
4376 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4378 /* ARMv7-M: A5.3.12 Data processing (register)
4379 * and A5.3.13 Miscellaneous operations
4381 else if ((opcode
& 0x1f000000) == 0x1a000000)
4382 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4384 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4385 else if ((opcode
& 0x1f800000) == 0x1b000000)
4386 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4388 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4389 else if ((opcode
& 0x1f800000) == 0x1b800000)
4390 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4392 if (retval
== ERROR_OK
)
4396 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4397 * instructions; not yet handled here.
4400 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4401 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4402 strcpy(cp
, "UNDEFINED OPCODE");
4406 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4409 strcpy(cp
, "(32-bit Thumb2 ...)");
4413 int arm_access_size(struct arm_instruction
*instruction
)
4415 if ((instruction
->type
== ARM_LDRB
)
4416 || (instruction
->type
== ARM_LDRBT
)
4417 || (instruction
->type
== ARM_LDRSB
)
4418 || (instruction
->type
== ARM_STRB
)
4419 || (instruction
->type
== ARM_STRBT
))
4421 else if ((instruction
->type
== ARM_LDRH
)
4422 || (instruction
->type
== ARM_LDRSH
)
4423 || (instruction
->type
== ARM_STRH
))
4425 else if ((instruction
->type
== ARM_LDR
)
4426 || (instruction
->type
== ARM_LDRT
)
4427 || (instruction
->type
== ARM_STR
)
4428 || (instruction
->type
== ARM_STRT
))
4430 else if ((instruction
->type
== ARM_LDRD
)
4431 || (instruction
->type
== ARM_STRD
))
4434 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction",
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)