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"
28 #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
[] =
101 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
104 /* make up for C's missing ROR */
105 static uint32_t ror(uint32_t value
, int places
)
107 return (value
>> places
) | (value
<< (32 - places
));
110 static int evaluate_unknown(uint32_t opcode
,
111 uint32_t address
, struct arm_instruction
*instruction
)
113 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
114 snprintf(instruction
->text
, 128,
115 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
116 "\tUNDEFINED INSTRUCTION", address
, opcode
);
120 static int evaluate_pld(uint32_t opcode
,
121 uint32_t address
, struct arm_instruction
*instruction
)
124 if ((opcode
& 0x0d70f000) == 0x0550f000)
126 instruction
->type
= ARM_PLD
;
128 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
132 return evaluate_unknown(opcode
, address
, instruction
);
135 static int evaluate_srs(uint32_t opcode
,
136 uint32_t address
, struct arm_instruction
*instruction
)
138 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
139 const char *mode
= "";
141 switch ((opcode
>> 23) & 0x3) {
146 /* "IA" is default */
156 switch (opcode
& 0x0e500000) {
158 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
160 "\tSRS%s\tSP%s, #%d",
163 (unsigned)(opcode
& 0x1f));
166 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
171 (unsigned)((opcode
>> 16) & 0xf), wback
);
174 return evaluate_unknown(opcode
, address
, instruction
);
179 static int evaluate_swi(uint32_t opcode
,
180 uint32_t address
, struct arm_instruction
*instruction
)
182 instruction
->type
= ARM_SWI
;
184 snprintf(instruction
->text
, 128,
185 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
186 address
, opcode
, (opcode
& 0xffffff));
191 static int evaluate_blx_imm(uint32_t opcode
,
192 uint32_t address
, struct arm_instruction
*instruction
)
196 uint32_t target_address
;
198 instruction
->type
= ARM_BLX
;
199 immediate
= opcode
& 0x00ffffff;
201 /* sign extend 24-bit immediate */
202 if (immediate
& 0x00800000)
203 offset
= 0xff000000 | immediate
;
207 /* shift two bits left */
210 /* odd/event halfword */
211 if (opcode
& 0x01000000)
214 target_address
= address
+ 8 + offset
;
216 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
218 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
219 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
224 static int evaluate_b_bl(uint32_t opcode
,
225 uint32_t address
, struct arm_instruction
*instruction
)
230 uint32_t target_address
;
232 immediate
= opcode
& 0x00ffffff;
233 L
= (opcode
& 0x01000000) >> 24;
235 /* sign extend 24-bit immediate */
236 if (immediate
& 0x00800000)
237 offset
= 0xff000000 | immediate
;
241 /* shift two bits left */
244 target_address
= address
+ 8 + offset
;
247 instruction
->type
= ARM_BL
;
249 instruction
->type
= ARM_B
;
251 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
252 (L
) ? "L" : "", COND(opcode
), target_address
);
254 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
255 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
260 /* Coprocessor load/store and double register transfers */
261 /* both normal and extended instruction space (condition field b1111) */
262 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
263 uint32_t address
, struct arm_instruction
*instruction
)
265 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
268 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
270 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
273 cp_opcode
= (opcode
& 0xf0) >> 4;
274 Rd
= (opcode
& 0xf000) >> 12;
275 Rn
= (opcode
& 0xf0000) >> 16;
276 CRm
= (opcode
& 0xf);
279 if ((opcode
& 0x0ff00000) == 0x0c400000)
281 instruction
->type
= ARM_MCRR
;
286 if ((opcode
& 0x0ff00000) == 0x0c500000)
288 instruction
->type
= ARM_MRRC
;
292 snprintf(instruction
->text
, 128,
293 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
294 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
295 address
, opcode
, mnemonic
,
296 ((opcode
& 0xf0000000) == 0xf0000000)
297 ? "2" : COND(opcode
),
298 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
300 else /* LDC or STC */
302 uint8_t CRd
, Rn
, offset
;
305 char addressing_mode
[32];
307 CRd
= (opcode
& 0xf000) >> 12;
308 Rn
= (opcode
& 0xf0000) >> 16;
309 offset
= (opcode
& 0xff) << 2;
312 if (opcode
& 0x00100000)
314 instruction
->type
= ARM_LDC
;
319 instruction
->type
= ARM_STC
;
323 U
= (opcode
& 0x00800000) >> 23;
325 /* addressing modes */
326 if ((opcode
& 0x01200000) == 0x01000000) /* offset */
327 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
328 Rn
, U
? "" : "-", offset
);
329 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
330 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
331 Rn
, U
? "" : "-", offset
);
332 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
333 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
334 Rn
, U
? "" : "-", offset
);
335 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
336 snprintf(addressing_mode
, 32, "[r%i], {%d}",
339 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
341 "\t%s%s%s p%i, c%i, %s",
342 address
, opcode
, mnemonic
,
343 ((opcode
& 0xf0000000) == 0xf0000000)
344 ? "2" : COND(opcode
),
345 (opcode
& (1 << 22)) ? "L" : "",
346 cp_num
, CRd
, addressing_mode
);
352 /* Coprocessor data processing instructions */
353 /* Coprocessor register transfer instructions */
354 /* both normal and extended instruction space (condition field b1111) */
355 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
356 uint32_t address
, struct arm_instruction
*instruction
)
360 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
362 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
363 cp_num
= (opcode
& 0xf00) >> 8;
364 CRd_Rd
= (opcode
& 0xf000) >> 12;
365 CRn
= (opcode
& 0xf0000) >> 16;
366 CRm
= (opcode
& 0xf);
367 opcode_2
= (opcode
& 0xe0) >> 5;
370 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
372 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
374 instruction
->type
= ARM_MRC
;
377 else /* bit 20 not set -> MCR */
379 instruction
->type
= ARM_MCR
;
383 opcode_1
= (opcode
& 0x00e00000) >> 21;
385 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",
386 address
, opcode
, mnemonic
, cond
,
387 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
389 else /* bit 4 not set -> CDP */
391 instruction
->type
= ARM_CDP
;
394 opcode_1
= (opcode
& 0x00f00000) >> 20;
396 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",
397 address
, opcode
, mnemonic
, cond
,
398 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
404 /* Load/store instructions */
405 static int evaluate_load_store(uint32_t opcode
,
406 uint32_t address
, struct arm_instruction
*instruction
)
408 uint8_t I
, P
, U
, B
, W
, L
;
410 char *operation
; /* "LDR" or "STR" */
411 char *suffix
; /* "", "B", "T", "BT" */
415 I
= (opcode
& 0x02000000) >> 25;
416 P
= (opcode
& 0x01000000) >> 24;
417 U
= (opcode
& 0x00800000) >> 23;
418 B
= (opcode
& 0x00400000) >> 22;
419 W
= (opcode
& 0x00200000) >> 21;
420 L
= (opcode
& 0x00100000) >> 20;
422 /* target register */
423 Rd
= (opcode
& 0xf000) >> 12;
426 Rn
= (opcode
& 0xf0000) >> 16;
428 instruction
->info
.load_store
.Rd
= Rd
;
429 instruction
->info
.load_store
.Rn
= Rn
;
430 instruction
->info
.load_store
.U
= U
;
432 /* determine operation */
438 /* determine instruction type and suffix */
441 if ((P
== 0) && (W
== 1))
444 instruction
->type
= ARM_LDRBT
;
446 instruction
->type
= ARM_STRBT
;
452 instruction
->type
= ARM_LDRB
;
454 instruction
->type
= ARM_STRB
;
460 if ((P
== 0) && (W
== 1))
463 instruction
->type
= ARM_LDRT
;
465 instruction
->type
= ARM_STRT
;
471 instruction
->type
= ARM_LDR
;
473 instruction
->type
= ARM_STR
;
478 if (!I
) /* #+-<offset_12> */
480 uint32_t offset_12
= (opcode
& 0xfff);
482 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
484 snprintf(offset
, 32, "%s", "");
486 instruction
->info
.load_store
.offset_mode
= 0;
487 instruction
->info
.load_store
.offset
.offset
= offset_12
;
489 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
491 uint8_t shift_imm
, shift
;
494 shift_imm
= (opcode
& 0xf80) >> 7;
495 shift
= (opcode
& 0x60) >> 5;
498 /* LSR encodes a shift by 32 bit as 0x0 */
499 if ((shift
== 0x1) && (shift_imm
== 0x0))
502 /* ASR encodes a shift by 32 bit as 0x0 */
503 if ((shift
== 0x2) && (shift_imm
== 0x0))
506 /* ROR by 32 bit is actually a RRX */
507 if ((shift
== 0x3) && (shift_imm
== 0x0))
510 instruction
->info
.load_store
.offset_mode
= 1;
511 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
512 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
513 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
515 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
517 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
519 else /* +-<Rm>, <Shift>, #<shift_imm> */
524 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
527 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
530 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
533 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
536 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
544 if (W
== 0) /* offset */
546 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
547 address
, opcode
, operation
, COND(opcode
), suffix
,
550 instruction
->info
.load_store
.index_mode
= 0;
552 else /* pre-indexed */
554 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
555 address
, opcode
, operation
, COND(opcode
), suffix
,
558 instruction
->info
.load_store
.index_mode
= 1;
561 else /* post-indexed */
563 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
564 address
, opcode
, operation
, COND(opcode
), suffix
,
567 instruction
->info
.load_store
.index_mode
= 2;
573 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
575 unsigned rm
= (opcode
>> 0) & 0xf;
576 unsigned rd
= (opcode
>> 12) & 0xf;
577 unsigned rn
= (opcode
>> 16) & 0xf;
580 switch ((opcode
>> 24) & 0x3) {
585 sprintf(cp
, "UNDEFINED");
586 return ARM_UNDEFINED_INSTRUCTION
;
595 switch ((opcode
>> 10) & 0x3) {
611 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
612 (opcode
& (1 << 22)) ? 'U' : 'S',
617 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
618 (opcode
& (1 << 22)) ? 'U' : 'S',
625 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
631 switch ((opcode
>> 20) & 0x7) {
654 switch ((opcode
>> 5) & 0x7) {
683 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
684 (int) (opcode
>> 12) & 0xf,
685 (int) (opcode
>> 16) & 0xf,
686 (int) (opcode
>> 0) & 0xf);
690 /* these opcodes might be used someday */
691 sprintf(cp
, "UNDEFINED");
692 return ARM_UNDEFINED_INSTRUCTION
;
695 /* ARMv6 and later support "media" instructions (includes SIMD) */
696 static int evaluate_media(uint32_t opcode
, uint32_t address
,
697 struct arm_instruction
*instruction
)
699 char *cp
= instruction
->text
;
700 char *mnemonic
= NULL
;
703 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
707 /* parallel add/subtract */
708 if ((opcode
& 0x01800000) == 0x00000000) {
709 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
714 if ((opcode
& 0x01f00020) == 0x00800000) {
716 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
718 if (opcode
& (1 << 6)) {
727 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
729 (int) (opcode
>> 12) & 0xf,
730 (int) (opcode
>> 16) & 0xf,
731 (int) (opcode
>> 0) & 0xf,
737 if ((opcode
& 0x01a00020) == 0x00a00000) {
739 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
741 if (opcode
& (1 << 6)) {
749 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
750 (opcode
& (1 << 22)) ? 'U' : 'S',
752 (int) (opcode
>> 12) & 0xf,
753 (int) (opcode
>> 16) & 0x1f,
754 (int) (opcode
>> 0) & 0xf,
760 if ((opcode
& 0x018000f0) == 0x00800070) {
761 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
766 if ((opcode
& 0x01f00080) == 0x01000000) {
767 unsigned rn
= (opcode
>> 12) & 0xf;
770 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
771 (opcode
& (1 << 6)) ? 'S' : 'A',
772 (opcode
& (1 << 5)) ? "X" : "",
774 (int) (opcode
>> 16) & 0xf,
775 (int) (opcode
>> 0) & 0xf,
776 (int) (opcode
>> 8) & 0xf,
779 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
780 (opcode
& (1 << 6)) ? 'S' : 'A',
781 (opcode
& (1 << 5)) ? "X" : "",
783 (int) (opcode
>> 16) & 0xf,
784 (int) (opcode
>> 0) & 0xf,
785 (int) (opcode
>> 8) & 0xf);
788 if ((opcode
& 0x01f00000) == 0x01400000) {
789 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
790 (opcode
& (1 << 6)) ? 'S' : 'A',
791 (opcode
& (1 << 5)) ? "X" : "",
793 (int) (opcode
>> 12) & 0xf,
794 (int) (opcode
>> 16) & 0xf,
795 (int) (opcode
>> 0) & 0xf,
796 (int) (opcode
>> 8) & 0xf);
799 if ((opcode
& 0x01f00000) == 0x01500000) {
800 unsigned rn
= (opcode
>> 12) & 0xf;
802 switch (opcode
& 0xc0) {
814 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
815 (opcode
& (1 << 6)) ? 'S' : 'A',
816 (opcode
& (1 << 5)) ? "R" : "",
818 (int) (opcode
>> 16) & 0xf,
819 (int) (opcode
>> 0) & 0xf,
820 (int) (opcode
>> 8) & 0xf,
823 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
824 (opcode
& (1 << 5)) ? "R" : "",
826 (int) (opcode
>> 16) & 0xf,
827 (int) (opcode
>> 0) & 0xf,
828 (int) (opcode
>> 8) & 0xf);
833 /* simple matches against the remaining decode bits */
834 switch (opcode
& 0x01f000f0) {
837 /* parallel halfword saturate */
838 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
839 (opcode
& (1 << 22)) ? 'U' : 'S',
841 (int) (opcode
>> 12) & 0xf,
842 (int) (opcode
>> 16) & 0xf,
843 (int) (opcode
>> 0) & 0xf);
856 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
857 (int) (opcode
>> 12) & 0xf,
858 (int) (opcode
>> 16) & 0xf,
859 (int) (opcode
>> 0) & 0xf);
862 /* unsigned sum of absolute differences */
863 if (((opcode
>> 12) & 0xf) == 0xf)
864 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
865 (int) (opcode
>> 16) & 0xf,
866 (int) (opcode
>> 0) & 0xf,
867 (int) (opcode
>> 8) & 0xf);
869 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
870 (int) (opcode
>> 16) & 0xf,
871 (int) (opcode
>> 0) & 0xf,
872 (int) (opcode
>> 8) & 0xf,
873 (int) (opcode
>> 12) & 0xf);
877 unsigned rm
= (opcode
>> 0) & 0xf;
878 unsigned rd
= (opcode
>> 12) & 0xf;
880 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
885 /* these opcodes might be used someday */
886 sprintf(cp
, "UNDEFINED");
890 /* Miscellaneous load/store instructions */
891 static int evaluate_misc_load_store(uint32_t opcode
,
892 uint32_t address
, struct arm_instruction
*instruction
)
894 uint8_t P
, U
, I
, W
, L
, S
, H
;
896 char *operation
; /* "LDR" or "STR" */
897 char *suffix
; /* "H", "SB", "SH", "D" */
901 P
= (opcode
& 0x01000000) >> 24;
902 U
= (opcode
& 0x00800000) >> 23;
903 I
= (opcode
& 0x00400000) >> 22;
904 W
= (opcode
& 0x00200000) >> 21;
905 L
= (opcode
& 0x00100000) >> 20;
906 S
= (opcode
& 0x00000040) >> 6;
907 H
= (opcode
& 0x00000020) >> 5;
909 /* target register */
910 Rd
= (opcode
& 0xf000) >> 12;
913 Rn
= (opcode
& 0xf0000) >> 16;
915 instruction
->info
.load_store
.Rd
= Rd
;
916 instruction
->info
.load_store
.Rn
= Rn
;
917 instruction
->info
.load_store
.U
= U
;
919 /* determine instruction type and suffix */
927 instruction
->type
= ARM_LDRSH
;
933 instruction
->type
= ARM_LDRSB
;
937 else /* there are no signed stores, so this is used to encode double-register load/stores */
943 instruction
->type
= ARM_STRD
;
948 instruction
->type
= ARM_LDRD
;
958 instruction
->type
= ARM_LDRH
;
963 instruction
->type
= ARM_STRH
;
967 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
969 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
970 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
972 instruction
->info
.load_store
.offset_mode
= 0;
973 instruction
->info
.load_store
.offset
.offset
= offset_8
;
975 else /* Register offset/index (+-<Rm>) */
979 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
981 instruction
->info
.load_store
.offset_mode
= 1;
982 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
983 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
984 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
989 if (W
== 0) /* offset */
991 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
992 address
, opcode
, operation
, COND(opcode
), suffix
,
995 instruction
->info
.load_store
.index_mode
= 0;
997 else /* pre-indexed */
999 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1000 address
, opcode
, operation
, COND(opcode
), suffix
,
1003 instruction
->info
.load_store
.index_mode
= 1;
1006 else /* post-indexed */
1008 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1009 address
, opcode
, operation
, COND(opcode
), suffix
,
1012 instruction
->info
.load_store
.index_mode
= 2;
1018 /* Load/store multiples instructions */
1019 static int evaluate_ldm_stm(uint32_t opcode
,
1020 uint32_t address
, struct arm_instruction
*instruction
)
1022 uint8_t P
, U
, S
, W
, L
, Rn
;
1023 uint32_t register_list
;
1024 char *addressing_mode
;
1031 P
= (opcode
& 0x01000000) >> 24;
1032 U
= (opcode
& 0x00800000) >> 23;
1033 S
= (opcode
& 0x00400000) >> 22;
1034 W
= (opcode
& 0x00200000) >> 21;
1035 L
= (opcode
& 0x00100000) >> 20;
1036 register_list
= (opcode
& 0xffff);
1037 Rn
= (opcode
& 0xf0000) >> 16;
1039 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1040 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1041 instruction
->info
.load_store_multiple
.S
= S
;
1042 instruction
->info
.load_store_multiple
.W
= W
;
1046 instruction
->type
= ARM_LDM
;
1051 instruction
->type
= ARM_STM
;
1059 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1060 addressing_mode
= "IB";
1064 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1065 addressing_mode
= "DB";
1072 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1073 /* "IA" is the default in UAL syntax */
1074 addressing_mode
= "";
1078 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1079 addressing_mode
= "DA";
1083 reg_list_p
= reg_list
;
1084 for (i
= 0; i
<= 15; i
++)
1086 if ((register_list
>> i
) & 1)
1091 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1095 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1100 snprintf(instruction
->text
, 128,
1101 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1102 "\t%s%s%s r%i%s, {%s}%s",
1104 mnemonic
, addressing_mode
, COND(opcode
),
1105 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1110 /* Multiplies, extra load/stores */
1111 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1112 uint32_t address
, struct arm_instruction
*instruction
)
1114 /* Multiply (accumulate) (long) and Swap/swap byte */
1115 if ((opcode
& 0x000000f0) == 0x00000090)
1117 /* Multiply (accumulate) */
1118 if ((opcode
& 0x0f800000) == 0x00000000)
1120 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1122 Rs
= (opcode
& 0xf00) >> 8;
1123 Rn
= (opcode
& 0xf000) >> 12;
1124 Rd
= (opcode
& 0xf0000) >> 16;
1125 S
= (opcode
& 0x00100000) >> 20;
1127 /* examine A bit (accumulate) */
1128 if (opcode
& 0x00200000)
1130 instruction
->type
= ARM_MLA
;
1131 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1132 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1136 instruction
->type
= ARM_MUL
;
1137 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1138 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1144 /* Multiply (accumulate) long */
1145 if ((opcode
& 0x0f800000) == 0x00800000)
1147 char* mnemonic
= NULL
;
1148 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1150 Rs
= (opcode
& 0xf00) >> 8;
1151 RdHi
= (opcode
& 0xf000) >> 12;
1152 RdLow
= (opcode
& 0xf0000) >> 16;
1153 S
= (opcode
& 0x00100000) >> 20;
1155 switch ((opcode
& 0x00600000) >> 21)
1158 instruction
->type
= ARM_UMULL
;
1162 instruction
->type
= ARM_UMLAL
;
1166 instruction
->type
= ARM_SMULL
;
1170 instruction
->type
= ARM_SMLAL
;
1175 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1176 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1177 RdLow
, RdHi
, Rm
, Rs
);
1182 /* Swap/swap byte */
1183 if ((opcode
& 0x0f800000) == 0x01000000)
1187 Rd
= (opcode
& 0xf000) >> 12;
1188 Rn
= (opcode
& 0xf0000) >> 16;
1190 /* examine B flag */
1191 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1193 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1194 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1200 return evaluate_misc_load_store(opcode
, address
, instruction
);
1203 static int evaluate_mrs_msr(uint32_t opcode
,
1204 uint32_t address
, struct arm_instruction
*instruction
)
1206 int R
= (opcode
& 0x00400000) >> 22;
1207 char *PSR
= (R
) ? "SPSR" : "CPSR";
1209 /* Move register to status register (MSR) */
1210 if (opcode
& 0x00200000)
1212 instruction
->type
= ARM_MSR
;
1214 /* immediate variant */
1215 if (opcode
& 0x02000000)
1217 uint8_t immediate
= (opcode
& 0xff);
1218 uint8_t rotate
= (opcode
& 0xf00);
1220 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1221 address
, opcode
, COND(opcode
), PSR
,
1222 (opcode
& 0x10000) ? "c" : "",
1223 (opcode
& 0x20000) ? "x" : "",
1224 (opcode
& 0x40000) ? "s" : "",
1225 (opcode
& 0x80000) ? "f" : "",
1226 ror(immediate
, (rotate
* 2))
1229 else /* register variant */
1231 uint8_t Rm
= opcode
& 0xf;
1232 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1233 address
, opcode
, COND(opcode
), PSR
,
1234 (opcode
& 0x10000) ? "c" : "",
1235 (opcode
& 0x20000) ? "x" : "",
1236 (opcode
& 0x40000) ? "s" : "",
1237 (opcode
& 0x80000) ? "f" : "",
1243 else /* Move status register to register (MRS) */
1247 instruction
->type
= ARM_MRS
;
1248 Rd
= (opcode
& 0x0000f000) >> 12;
1250 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1251 address
, opcode
, COND(opcode
), Rd
, PSR
);
1257 /* Miscellaneous instructions */
1258 static int evaluate_misc_instr(uint32_t opcode
,
1259 uint32_t address
, struct arm_instruction
*instruction
)
1262 if ((opcode
& 0x000000f0) == 0x00000000)
1264 evaluate_mrs_msr(opcode
, address
, instruction
);
1268 if ((opcode
& 0x006000f0) == 0x00200010)
1271 instruction
->type
= ARM_BX
;
1274 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1275 address
, opcode
, COND(opcode
), Rm
);
1277 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1278 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1281 /* BXJ - "Jazelle" support (ARMv5-J) */
1282 if ((opcode
& 0x006000f0) == 0x00200020)
1285 instruction
->type
= ARM_BX
;
1288 snprintf(instruction
->text
, 128,
1289 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1290 address
, opcode
, COND(opcode
), Rm
);
1292 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1293 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1297 if ((opcode
& 0x006000f0) == 0x00600010)
1300 instruction
->type
= ARM_CLZ
;
1302 Rd
= (opcode
& 0xf000) >> 12;
1304 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1305 address
, opcode
, COND(opcode
), Rd
, Rm
);
1309 if ((opcode
& 0x006000f0) == 0x00200030)
1312 instruction
->type
= ARM_BLX
;
1315 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1316 address
, opcode
, COND(opcode
), Rm
);
1318 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1319 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1322 /* Enhanced DSP add/subtracts */
1323 if ((opcode
& 0x0000000f0) == 0x00000050)
1326 char *mnemonic
= NULL
;
1328 Rd
= (opcode
& 0xf000) >> 12;
1329 Rn
= (opcode
& 0xf0000) >> 16;
1331 switch ((opcode
& 0x00600000) >> 21)
1334 instruction
->type
= ARM_QADD
;
1338 instruction
->type
= ARM_QSUB
;
1342 instruction
->type
= ARM_QDADD
;
1346 instruction
->type
= ARM_QDSUB
;
1351 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1352 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1355 /* Software breakpoints */
1356 if ((opcode
& 0x0000000f0) == 0x00000070)
1359 instruction
->type
= ARM_BKPT
;
1360 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1362 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1363 address
, opcode
, immediate
);
1366 /* Enhanced DSP multiplies */
1367 if ((opcode
& 0x000000090) == 0x00000080)
1369 int x
= (opcode
& 0x20) >> 5;
1370 int y
= (opcode
& 0x40) >> 6;
1373 if ((opcode
& 0x00600000) == 0x00000000)
1375 uint8_t Rd
, Rm
, Rs
, Rn
;
1376 instruction
->type
= ARM_SMLAxy
;
1377 Rd
= (opcode
& 0xf0000) >> 16;
1378 Rm
= (opcode
& 0xf);
1379 Rs
= (opcode
& 0xf00) >> 8;
1380 Rn
= (opcode
& 0xf000) >> 12;
1382 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1383 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1388 if ((opcode
& 0x00600000) == 0x00400000)
1390 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1391 instruction
->type
= ARM_SMLAxy
;
1392 RdHi
= (opcode
& 0xf0000) >> 16;
1393 RdLow
= (opcode
& 0xf000) >> 12;
1394 Rm
= (opcode
& 0xf);
1395 Rs
= (opcode
& 0xf00) >> 8;
1397 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1398 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1399 RdLow
, RdHi
, Rm
, Rs
);
1403 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1405 uint8_t Rd
, Rm
, Rs
, Rn
;
1406 instruction
->type
= ARM_SMLAWy
;
1407 Rd
= (opcode
& 0xf0000) >> 16;
1408 Rm
= (opcode
& 0xf);
1409 Rs
= (opcode
& 0xf00) >> 8;
1410 Rn
= (opcode
& 0xf000) >> 12;
1412 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1413 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1418 if ((opcode
& 0x00600000) == 0x00300000)
1421 instruction
->type
= ARM_SMULxy
;
1422 Rd
= (opcode
& 0xf0000) >> 16;
1423 Rm
= (opcode
& 0xf);
1424 Rs
= (opcode
& 0xf00) >> 8;
1426 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1427 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1432 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1435 instruction
->type
= ARM_SMULWy
;
1436 Rd
= (opcode
& 0xf0000) >> 16;
1437 Rm
= (opcode
& 0xf);
1438 Rs
= (opcode
& 0xf00) >> 8;
1440 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1441 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1449 static int evaluate_data_proc(uint32_t opcode
,
1450 uint32_t address
, struct arm_instruction
*instruction
)
1452 uint8_t I
, op
, S
, Rn
, Rd
;
1453 char *mnemonic
= NULL
;
1454 char shifter_operand
[32];
1456 I
= (opcode
& 0x02000000) >> 25;
1457 op
= (opcode
& 0x01e00000) >> 21;
1458 S
= (opcode
& 0x00100000) >> 20;
1460 Rd
= (opcode
& 0xf000) >> 12;
1461 Rn
= (opcode
& 0xf0000) >> 16;
1463 instruction
->info
.data_proc
.Rd
= Rd
;
1464 instruction
->info
.data_proc
.Rn
= Rn
;
1465 instruction
->info
.data_proc
.S
= S
;
1470 instruction
->type
= ARM_AND
;
1474 instruction
->type
= ARM_EOR
;
1478 instruction
->type
= ARM_SUB
;
1482 instruction
->type
= ARM_RSB
;
1486 instruction
->type
= ARM_ADD
;
1490 instruction
->type
= ARM_ADC
;
1494 instruction
->type
= ARM_SBC
;
1498 instruction
->type
= ARM_RSC
;
1502 instruction
->type
= ARM_TST
;
1506 instruction
->type
= ARM_TEQ
;
1510 instruction
->type
= ARM_CMP
;
1514 instruction
->type
= ARM_CMN
;
1518 instruction
->type
= ARM_ORR
;
1522 instruction
->type
= ARM_MOV
;
1526 instruction
->type
= ARM_BIC
;
1530 instruction
->type
= ARM_MVN
;
1535 if (I
) /* immediate shifter operand (#<immediate>)*/
1537 uint8_t immed_8
= opcode
& 0xff;
1538 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1541 immediate
= ror(immed_8
, rotate_imm
* 2);
1543 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1545 instruction
->info
.data_proc
.variant
= 0;
1546 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1548 else /* register-based shifter operand */
1551 shift
= (opcode
& 0x60) >> 5;
1552 Rm
= (opcode
& 0xf);
1554 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1557 shift_imm
= (opcode
& 0xf80) >> 7;
1559 instruction
->info
.data_proc
.variant
= 1;
1560 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1561 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1562 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1564 /* LSR encodes a shift by 32 bit as 0x0 */
1565 if ((shift
== 0x1) && (shift_imm
== 0x0))
1568 /* ASR encodes a shift by 32 bit as 0x0 */
1569 if ((shift
== 0x2) && (shift_imm
== 0x0))
1572 /* ROR by 32 bit is actually a RRX */
1573 if ((shift
== 0x3) && (shift_imm
== 0x0))
1576 if ((shift_imm
== 0x0) && (shift
== 0x0))
1578 snprintf(shifter_operand
, 32, "r%i", Rm
);
1582 if (shift
== 0x0) /* LSL */
1584 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1586 else if (shift
== 0x1) /* LSR */
1588 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1590 else if (shift
== 0x2) /* ASR */
1592 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1594 else if (shift
== 0x3) /* ROR */
1596 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1598 else if (shift
== 0x4) /* RRX */
1600 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1604 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1606 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1608 instruction
->info
.data_proc
.variant
= 2;
1609 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1610 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1611 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1613 if (shift
== 0x0) /* LSL */
1615 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1617 else if (shift
== 0x1) /* LSR */
1619 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1621 else if (shift
== 0x2) /* ASR */
1623 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1625 else if (shift
== 0x3) /* ROR */
1627 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1632 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1634 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1635 address
, opcode
, mnemonic
, COND(opcode
),
1636 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1638 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1640 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1641 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1643 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1644 address
, opcode
, mnemonic
, COND(opcode
),
1645 (S
) ? "S" : "", Rd
, shifter_operand
);
1647 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1649 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1650 address
, opcode
, mnemonic
, COND(opcode
),
1651 Rn
, shifter_operand
);
1657 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1658 struct arm_instruction
*instruction
)
1660 /* clear fields, to avoid confusion */
1661 memset(instruction
, 0, sizeof(struct arm_instruction
));
1662 instruction
->opcode
= opcode
;
1663 instruction
->instruction_size
= 4;
1665 /* catch opcodes with condition field [31:28] = b1111 */
1666 if ((opcode
& 0xf0000000) == 0xf0000000)
1668 /* Undefined instruction (or ARMv5E cache preload PLD) */
1669 if ((opcode
& 0x08000000) == 0x00000000)
1670 return evaluate_pld(opcode
, address
, instruction
);
1672 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1673 if ((opcode
& 0x0e000000) == 0x08000000)
1674 return evaluate_srs(opcode
, address
, instruction
);
1676 /* Branch and branch with link and change to Thumb */
1677 if ((opcode
& 0x0e000000) == 0x0a000000)
1678 return evaluate_blx_imm(opcode
, address
, instruction
);
1680 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1681 /* Coprocessor load/store and double register transfers */
1682 if ((opcode
& 0x0e000000) == 0x0c000000)
1683 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1685 /* Coprocessor data processing */
1686 if ((opcode
& 0x0f000100) == 0x0c000000)
1687 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1689 /* Coprocessor register transfers */
1690 if ((opcode
& 0x0f000010) == 0x0c000010)
1691 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1693 /* Undefined instruction */
1694 if ((opcode
& 0x0f000000) == 0x0f000000)
1696 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1697 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1702 /* catch opcodes with [27:25] = b000 */
1703 if ((opcode
& 0x0e000000) == 0x00000000)
1705 /* Multiplies, extra load/stores */
1706 if ((opcode
& 0x00000090) == 0x00000090)
1707 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1709 /* Miscellaneous instructions */
1710 if ((opcode
& 0x0f900000) == 0x01000000)
1711 return evaluate_misc_instr(opcode
, address
, instruction
);
1713 return evaluate_data_proc(opcode
, address
, instruction
);
1716 /* catch opcodes with [27:25] = b001 */
1717 if ((opcode
& 0x0e000000) == 0x02000000)
1719 /* Undefined instruction */
1720 if ((opcode
& 0x0fb00000) == 0x03000000)
1722 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1723 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1727 /* Move immediate to status register */
1728 if ((opcode
& 0x0fb00000) == 0x03200000)
1729 return evaluate_mrs_msr(opcode
, address
, instruction
);
1731 return evaluate_data_proc(opcode
, address
, instruction
);
1735 /* catch opcodes with [27:25] = b010 */
1736 if ((opcode
& 0x0e000000) == 0x04000000)
1738 /* Load/store immediate offset */
1739 return evaluate_load_store(opcode
, address
, instruction
);
1742 /* catch opcodes with [27:25] = b011 */
1743 if ((opcode
& 0x0e000000) == 0x06000000)
1745 /* Load/store register offset */
1746 if ((opcode
& 0x00000010) == 0x00000000)
1747 return evaluate_load_store(opcode
, address
, instruction
);
1749 /* Architecturally Undefined instruction
1750 * ... don't expect these to ever be used
1752 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1754 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1755 snprintf(instruction
->text
, 128,
1756 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1761 /* "media" instructions */
1762 return evaluate_media(opcode
, address
, instruction
);
1765 /* catch opcodes with [27:25] = b100 */
1766 if ((opcode
& 0x0e000000) == 0x08000000)
1768 /* Load/store multiple */
1769 return evaluate_ldm_stm(opcode
, address
, instruction
);
1772 /* catch opcodes with [27:25] = b101 */
1773 if ((opcode
& 0x0e000000) == 0x0a000000)
1775 /* Branch and branch with link */
1776 return evaluate_b_bl(opcode
, address
, instruction
);
1779 /* catch opcodes with [27:25] = b110 */
1780 if ((opcode
& 0x0e000000) == 0x0c000000)
1782 /* Coprocessor load/store and double register transfers */
1783 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1786 /* catch opcodes with [27:25] = b111 */
1787 if ((opcode
& 0x0e000000) == 0x0e000000)
1789 /* Software interrupt */
1790 if ((opcode
& 0x0f000000) == 0x0f000000)
1791 return evaluate_swi(opcode
, address
, instruction
);
1793 /* Coprocessor data processing */
1794 if ((opcode
& 0x0f000010) == 0x0e000000)
1795 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1797 /* Coprocessor register transfers */
1798 if ((opcode
& 0x0f000010) == 0x0e000010)
1799 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1802 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1807 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1808 uint32_t address
, struct arm_instruction
*instruction
)
1810 uint32_t offset
= opcode
& 0x7ff;
1811 uint32_t opc
= (opcode
>> 11) & 0x3;
1812 uint32_t target_address
;
1813 char *mnemonic
= NULL
;
1815 /* sign extend 11-bit offset */
1816 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1817 offset
= 0xfffff800 | offset
;
1819 target_address
= address
+ 4 + (offset
<< 1);
1823 /* unconditional branch */
1825 instruction
->type
= ARM_B
;
1830 instruction
->type
= ARM_BLX
;
1832 target_address
&= 0xfffffffc;
1836 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1837 mnemonic
= "prefix";
1838 target_address
= offset
<< 12;
1842 instruction
->type
= ARM_BL
;
1847 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1848 * these are effectively 32-bit instructions even in Thumb1. For
1849 * disassembly, it's simplest to always use the Thumb2 decoder.
1851 * But some cores will evidently handle them as two instructions,
1852 * where exceptions may occur between the two. The ETMv3.2+ ID
1853 * register has a bit which exposes this behavior.
1856 snprintf(instruction
->text
, 128,
1857 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1858 address
, opcode
, mnemonic
, target_address
);
1860 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1861 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1866 static int evaluate_add_sub_thumb(uint16_t opcode
,
1867 uint32_t address
, struct arm_instruction
*instruction
)
1869 uint8_t Rd
= (opcode
>> 0) & 0x7;
1870 uint8_t Rn
= (opcode
>> 3) & 0x7;
1871 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1872 uint32_t opc
= opcode
& (1 << 9);
1873 uint32_t reg_imm
= opcode
& (1 << 10);
1878 instruction
->type
= ARM_SUB
;
1883 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1884 instruction
->type
= ARM_ADD
;
1888 instruction
->info
.data_proc
.Rd
= Rd
;
1889 instruction
->info
.data_proc
.Rn
= Rn
;
1890 instruction
->info
.data_proc
.S
= 1;
1894 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1895 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1896 snprintf(instruction
->text
, 128,
1897 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1898 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1902 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1903 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1904 snprintf(instruction
->text
, 128,
1905 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1906 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1912 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1913 uint32_t address
, struct arm_instruction
*instruction
)
1915 uint8_t Rd
= (opcode
>> 0) & 0x7;
1916 uint8_t Rm
= (opcode
>> 3) & 0x7;
1917 uint8_t imm
= (opcode
>> 6) & 0x1f;
1918 uint8_t opc
= (opcode
>> 11) & 0x3;
1919 char *mnemonic
= NULL
;
1924 instruction
->type
= ARM_MOV
;
1926 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1929 instruction
->type
= ARM_MOV
;
1931 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1934 instruction
->type
= ARM_MOV
;
1936 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1940 if ((imm
== 0) && (opc
!= 0))
1943 instruction
->info
.data_proc
.Rd
= Rd
;
1944 instruction
->info
.data_proc
.Rn
= -1;
1945 instruction
->info
.data_proc
.S
= 1;
1947 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1948 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1949 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1951 snprintf(instruction
->text
, 128,
1952 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1953 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1958 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1959 uint32_t address
, struct arm_instruction
*instruction
)
1961 uint8_t imm
= opcode
& 0xff;
1962 uint8_t Rd
= (opcode
>> 8) & 0x7;
1963 uint32_t opc
= (opcode
>> 11) & 0x3;
1964 char *mnemonic
= NULL
;
1966 instruction
->info
.data_proc
.Rd
= Rd
;
1967 instruction
->info
.data_proc
.Rn
= Rd
;
1968 instruction
->info
.data_proc
.S
= 1;
1969 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1970 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1975 instruction
->type
= ARM_MOV
;
1977 instruction
->info
.data_proc
.Rn
= -1;
1980 instruction
->type
= ARM_CMP
;
1982 instruction
->info
.data_proc
.Rd
= -1;
1985 instruction
->type
= ARM_ADD
;
1989 instruction
->type
= ARM_SUB
;
1994 snprintf(instruction
->text
, 128,
1995 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1996 address
, opcode
, mnemonic
, Rd
, imm
);
2001 static int evaluate_data_proc_thumb(uint16_t opcode
,
2002 uint32_t address
, struct arm_instruction
*instruction
)
2004 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
2005 char *mnemonic
= NULL
;
2008 high_reg
= (opcode
& 0x0400) >> 10;
2009 op
= (opcode
& 0x03C0) >> 6;
2011 Rd
= (opcode
& 0x0007);
2012 Rm
= (opcode
& 0x0038) >> 3;
2013 H1
= (opcode
& 0x0080) >> 7;
2014 H2
= (opcode
& 0x0040) >> 6;
2016 instruction
->info
.data_proc
.Rd
= Rd
;
2017 instruction
->info
.data_proc
.Rn
= Rd
;
2018 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2019 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2020 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2031 instruction
->type
= ARM_ADD
;
2035 instruction
->type
= ARM_CMP
;
2039 instruction
->type
= ARM_MOV
;
2045 if ((opcode
& 0x7) == 0x0)
2047 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2050 instruction
->type
= ARM_BLX
;
2051 snprintf(instruction
->text
, 128,
2053 " 0x%4.4x \tBLX\tr%i",
2054 address
, opcode
, Rm
);
2058 instruction
->type
= ARM_BX
;
2059 snprintf(instruction
->text
, 128,
2061 " 0x%4.4x \tBX\tr%i",
2062 address
, opcode
, Rm
);
2067 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2068 snprintf(instruction
->text
, 128,
2071 "UNDEFINED INSTRUCTION",
2083 instruction
->type
= ARM_AND
;
2087 instruction
->type
= ARM_EOR
;
2091 instruction
->type
= ARM_MOV
;
2093 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2094 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2095 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2096 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2099 instruction
->type
= ARM_MOV
;
2101 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2102 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2103 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2104 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2107 instruction
->type
= ARM_MOV
;
2109 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2110 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2111 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2112 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2115 instruction
->type
= ARM_ADC
;
2119 instruction
->type
= ARM_SBC
;
2123 instruction
->type
= ARM_MOV
;
2125 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2126 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2127 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2128 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2131 instruction
->type
= ARM_TST
;
2135 instruction
->type
= ARM_RSB
;
2137 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2138 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2139 instruction
->info
.data_proc
.Rn
= Rm
;
2142 instruction
->type
= ARM_CMP
;
2146 instruction
->type
= ARM_CMN
;
2150 instruction
->type
= ARM_ORR
;
2154 instruction
->type
= ARM_MUL
;
2158 instruction
->type
= ARM_BIC
;
2162 instruction
->type
= ARM_MVN
;
2169 snprintf(instruction
->text
, 128,
2170 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2172 address
, opcode
, mnemonic
, Rd
, Rm
);
2174 snprintf(instruction
->text
, 128,
2175 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2176 address
, opcode
, mnemonic
, Rd
, Rm
);
2181 /* PC-relative data addressing is word-aligned even with Thumb */
2182 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2184 return (addr
+ 4) & ~3;
2187 static int evaluate_load_literal_thumb(uint16_t opcode
,
2188 uint32_t address
, struct arm_instruction
*instruction
)
2191 uint8_t Rd
= (opcode
>> 8) & 0x7;
2193 instruction
->type
= ARM_LDR
;
2194 immediate
= opcode
& 0x000000ff;
2197 instruction
->info
.load_store
.Rd
= Rd
;
2198 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2199 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2200 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2201 instruction
->info
.load_store
.offset
.offset
= immediate
;
2203 snprintf(instruction
->text
, 128,
2204 "0x%8.8" PRIx32
" 0x%4.4x \t"
2205 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2206 address
, opcode
, Rd
, immediate
,
2207 thumb_alignpc4(address
) + immediate
);
2212 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2213 uint32_t address
, struct arm_instruction
*instruction
)
2215 uint8_t Rd
= (opcode
>> 0) & 0x7;
2216 uint8_t Rn
= (opcode
>> 3) & 0x7;
2217 uint8_t Rm
= (opcode
>> 6) & 0x7;
2218 uint8_t opc
= (opcode
>> 9) & 0x7;
2219 char *mnemonic
= NULL
;
2224 instruction
->type
= ARM_STR
;
2228 instruction
->type
= ARM_STRH
;
2232 instruction
->type
= ARM_STRB
;
2236 instruction
->type
= ARM_LDRSB
;
2240 instruction
->type
= ARM_LDR
;
2244 instruction
->type
= ARM_LDRH
;
2248 instruction
->type
= ARM_LDRB
;
2252 instruction
->type
= ARM_LDRSH
;
2257 snprintf(instruction
->text
, 128,
2258 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2259 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2261 instruction
->info
.load_store
.Rd
= Rd
;
2262 instruction
->info
.load_store
.Rn
= Rn
;
2263 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2264 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2265 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2270 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2271 uint32_t address
, struct arm_instruction
*instruction
)
2273 uint32_t offset
= (opcode
>> 6) & 0x1f;
2274 uint8_t Rd
= (opcode
>> 0) & 0x7;
2275 uint8_t Rn
= (opcode
>> 3) & 0x7;
2276 uint32_t L
= opcode
& (1 << 11);
2277 uint32_t B
= opcode
& (1 << 12);
2284 instruction
->type
= ARM_LDR
;
2289 instruction
->type
= ARM_STR
;
2293 if ((opcode
&0xF000) == 0x8000)
2304 snprintf(instruction
->text
, 128,
2305 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2306 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2308 instruction
->info
.load_store
.Rd
= Rd
;
2309 instruction
->info
.load_store
.Rn
= Rn
;
2310 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2311 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2312 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2317 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2318 uint32_t address
, struct arm_instruction
*instruction
)
2320 uint32_t offset
= opcode
& 0xff;
2321 uint8_t Rd
= (opcode
>> 8) & 0x7;
2322 uint32_t L
= opcode
& (1 << 11);
2327 instruction
->type
= ARM_LDR
;
2332 instruction
->type
= ARM_STR
;
2336 snprintf(instruction
->text
, 128,
2337 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2338 address
, opcode
, mnemonic
, Rd
, offset
*4);
2340 instruction
->info
.load_store
.Rd
= Rd
;
2341 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2342 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2343 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2344 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2349 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2350 uint32_t address
, struct arm_instruction
*instruction
)
2352 uint32_t imm
= opcode
& 0xff;
2353 uint8_t Rd
= (opcode
>> 8) & 0x7;
2355 uint32_t SP
= opcode
& (1 << 11);
2356 const char *reg_name
;
2358 instruction
->type
= ARM_ADD
;
2371 snprintf(instruction
->text
, 128,
2372 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2373 address
, opcode
, Rd
, reg_name
, imm
* 4);
2375 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2376 instruction
->info
.data_proc
.Rd
= Rd
;
2377 instruction
->info
.data_proc
.Rn
= Rn
;
2378 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2383 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2384 uint32_t address
, struct arm_instruction
*instruction
)
2386 uint32_t imm
= opcode
& 0x7f;
2387 uint8_t opc
= opcode
& (1 << 7);
2393 instruction
->type
= ARM_SUB
;
2398 instruction
->type
= ARM_ADD
;
2402 snprintf(instruction
->text
, 128,
2403 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2404 address
, opcode
, mnemonic
, imm
*4);
2406 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2407 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2408 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2409 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2414 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2415 uint32_t address
, struct arm_instruction
*instruction
)
2417 uint32_t imm
= opcode
& 0xff;
2419 instruction
->type
= ARM_BKPT
;
2421 snprintf(instruction
->text
, 128,
2422 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2423 address
, opcode
, imm
);
2428 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2429 uint32_t address
, struct arm_instruction
*instruction
)
2431 uint32_t reg_list
= opcode
& 0xff;
2432 uint32_t L
= opcode
& (1 << 11);
2433 uint32_t R
= opcode
& (1 << 8);
2434 uint8_t Rn
= (opcode
>> 8) & 7;
2435 uint8_t addr_mode
= 0 /* IA */;
2439 char ptr_name
[7] = "";
2442 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2443 * The STMIA and LDMIA opcodes are used for other instructions.
2446 if ((opcode
& 0xf000) == 0xc000)
2447 { /* generic load/store multiple */
2452 instruction
->type
= ARM_LDM
;
2454 if (opcode
& (1 << Rn
))
2459 instruction
->type
= ARM_STM
;
2462 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2469 instruction
->type
= ARM_LDM
;
2472 reg_list
|= (1 << 15) /*PC*/;
2476 instruction
->type
= ARM_STM
;
2478 addr_mode
= 3; /*DB*/
2480 reg_list
|= (1 << 14) /*LR*/;
2484 reg_names_p
= reg_names
;
2485 for (i
= 0; i
<= 15; i
++)
2487 if (reg_list
& (1 << i
))
2488 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2490 if (reg_names_p
> reg_names
)
2491 reg_names_p
[-2] = '\0';
2492 else /* invalid op : no registers */
2493 reg_names
[0] = '\0';
2495 snprintf(instruction
->text
, 128,
2496 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2497 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2499 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2500 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2501 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2506 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2507 uint32_t address
, struct arm_instruction
*instruction
)
2509 uint32_t offset
= opcode
& 0xff;
2510 uint8_t cond
= (opcode
>> 8) & 0xf;
2511 uint32_t target_address
;
2515 instruction
->type
= ARM_SWI
;
2516 snprintf(instruction
->text
, 128,
2517 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2518 address
, opcode
, offset
);
2521 else if (cond
== 0xe)
2523 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2524 snprintf(instruction
->text
, 128,
2525 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2530 /* sign extend 8-bit offset */
2531 if (offset
& 0x00000080)
2532 offset
= 0xffffff00 | offset
;
2534 target_address
= address
+ 4 + (offset
<< 1);
2536 snprintf(instruction
->text
, 128,
2537 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2539 arm_condition_strings
[cond
], target_address
);
2541 instruction
->type
= ARM_B
;
2542 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2543 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2548 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2549 struct arm_instruction
*instruction
)
2553 /* added in Thumb2 */
2554 offset
= (opcode
>> 3) & 0x1f;
2555 offset
|= (opcode
& 0x0200) >> 4;
2557 snprintf(instruction
->text
, 128,
2558 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2560 (opcode
& 0x0800) ? "N" : "",
2561 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2566 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2567 struct arm_instruction
*instruction
)
2569 /* added in ARMv6 */
2570 snprintf(instruction
->text
, 128,
2571 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2573 (opcode
& 0x0080) ? 'U' : 'S',
2574 (opcode
& 0x0040) ? 'B' : 'H',
2575 opcode
& 0x7, (opcode
>> 3) & 0x7);
2580 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2581 struct arm_instruction
*instruction
)
2583 /* added in ARMv6 */
2584 if ((opcode
& 0x0ff0) == 0x0650)
2585 snprintf(instruction
->text
, 128,
2586 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2588 (opcode
& 0x80) ? "BE" : "LE");
2589 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2590 snprintf(instruction
->text
, 128,
2591 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2593 (opcode
& 0x0010) ? 'D' : 'E',
2594 (opcode
& 0x0004) ? "A" : "",
2595 (opcode
& 0x0002) ? "I" : "",
2596 (opcode
& 0x0001) ? "F" : "");
2601 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2602 struct arm_instruction
*instruction
)
2606 /* added in ARMv6 */
2607 switch ((opcode
>> 6) & 3) {
2618 snprintf(instruction
->text
, 128,
2619 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2620 address
, opcode
, suffix
,
2621 opcode
& 0x7, (opcode
>> 3) & 0x7);
2626 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2627 struct arm_instruction
*instruction
)
2631 switch ((opcode
>> 4) & 0x0f) {
2648 hint
= "HINT (UNRECOGNIZED)";
2652 snprintf(instruction
->text
, 128,
2653 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2654 address
, opcode
, hint
);
2659 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2660 struct arm_instruction
*instruction
)
2662 unsigned cond
= (opcode
>> 4) & 0x0f;
2663 char *x
= "", *y
= "", *z
= "";
2666 z
= (opcode
& 0x02) ? "T" : "E";
2668 y
= (opcode
& 0x04) ? "T" : "E";
2670 x
= (opcode
& 0x08) ? "T" : "E";
2672 snprintf(instruction
->text
, 128,
2673 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2675 x
, y
, z
, arm_condition_strings
[cond
]);
2677 /* NOTE: strictly speaking, the next 1-4 instructions should
2678 * now be displayed with the relevant conditional suffix...
2684 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2686 /* clear fields, to avoid confusion */
2687 memset(instruction
, 0, sizeof(struct arm_instruction
));
2688 instruction
->opcode
= opcode
;
2689 instruction
->instruction_size
= 2;
2691 if ((opcode
& 0xe000) == 0x0000)
2693 /* add/substract register or immediate */
2694 if ((opcode
& 0x1800) == 0x1800)
2695 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2696 /* shift by immediate */
2698 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2701 /* Add/substract/compare/move immediate */
2702 if ((opcode
& 0xe000) == 0x2000)
2704 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2707 /* Data processing instructions */
2708 if ((opcode
& 0xf800) == 0x4000)
2710 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2713 /* Load from literal pool */
2714 if ((opcode
& 0xf800) == 0x4800)
2716 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2719 /* Load/Store register offset */
2720 if ((opcode
& 0xf000) == 0x5000)
2722 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2725 /* Load/Store immediate offset */
2726 if (((opcode
& 0xe000) == 0x6000)
2727 ||((opcode
& 0xf000) == 0x8000))
2729 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2732 /* Load/Store from/to stack */
2733 if ((opcode
& 0xf000) == 0x9000)
2735 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2739 if ((opcode
& 0xf000) == 0xa000)
2741 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2745 if ((opcode
& 0xf000) == 0xb000)
2747 switch ((opcode
>> 8) & 0x0f) {
2749 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2754 return evaluate_cb_thumb(opcode
, address
, instruction
);
2756 return evaluate_extend_thumb(opcode
, address
, instruction
);
2761 return evaluate_load_store_multiple_thumb(opcode
, address
,
2764 return evaluate_cps_thumb(opcode
, address
, instruction
);
2766 if ((opcode
& 0x00c0) == 0x0080)
2768 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2770 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2772 if (opcode
& 0x000f)
2773 return evaluate_ifthen_thumb(opcode
, address
,
2776 return evaluate_hint_thumb(opcode
, address
,
2780 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2781 snprintf(instruction
->text
, 128,
2782 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2787 /* Load/Store multiple */
2788 if ((opcode
& 0xf000) == 0xc000)
2790 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2793 /* Conditional branch + SWI */
2794 if ((opcode
& 0xf000) == 0xd000)
2796 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2799 if ((opcode
& 0xe000) == 0xe000)
2801 /* Undefined instructions */
2802 if ((opcode
& 0xf801) == 0xe801)
2804 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2805 snprintf(instruction
->text
, 128,
2806 "0x%8.8" PRIx32
" 0x%8.8x\t"
2807 "UNDEFINED INSTRUCTION",
2812 { /* Branch to offset */
2813 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2817 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2821 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2822 struct arm_instruction
*instruction
, char *cp
)
2825 unsigned b21
= 1 << 21;
2826 unsigned b22
= 1 << 22;
2828 /* instead of combining two smaller 16-bit branch instructions,
2829 * Thumb2 uses only one larger 32-bit instruction.
2831 offset
= opcode
& 0x7ff;
2832 offset
|= (opcode
& 0x03ff0000) >> 5;
2833 if (opcode
& (1 << 26)) {
2834 offset
|= 0xff << 23;
2835 if ((opcode
& (1 << 11)) == 0)
2837 if ((opcode
& (1 << 13)) == 0)
2840 if (opcode
& (1 << 11))
2842 if (opcode
& (1 << 13))
2850 address
+= offset
<< 1;
2852 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2853 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2854 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2855 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2856 (opcode
& (1 << 14)) ? "BL" : "B.W",
2862 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2863 struct arm_instruction
*instruction
, char *cp
)
2866 unsigned b17
= 1 << 17;
2867 unsigned b18
= 1 << 18;
2868 unsigned cond
= (opcode
>> 22) & 0x0f;
2870 offset
= opcode
& 0x7ff;
2871 offset
|= (opcode
& 0x003f0000) >> 5;
2872 if (opcode
& (1 << 26)) {
2873 offset
|= 0xffff << 19;
2874 if ((opcode
& (1 << 11)) == 0)
2876 if ((opcode
& (1 << 13)) == 0)
2879 if (opcode
& (1 << 11))
2881 if (opcode
& (1 << 13))
2888 address
+= offset
<< 1;
2890 instruction
->type
= ARM_B
;
2891 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2892 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2893 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2894 arm_condition_strings
[cond
],
2900 static const char *special_name(int number
)
2902 char *special
= "(RESERVED)";
2933 special
= "primask";
2936 special
= "basepri";
2939 special
= "basepri_max";
2942 special
= "faultmask";
2945 special
= "control";
2951 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2952 struct arm_instruction
*instruction
, char *cp
)
2954 const char *mnemonic
;
2956 if (opcode
& 0x0700) {
2957 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2958 strcpy(cp
, "UNDEFINED");
2962 if (opcode
& 0x00f0) {
2963 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2967 switch (opcode
& 0x0f) {
2972 mnemonic
= "YIELD.W";
2984 mnemonic
= "HINT.W (UNRECOGNIZED)";
2987 strcpy(cp
, mnemonic
);
2991 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2992 struct arm_instruction
*instruction
, char *cp
)
2994 const char *mnemonic
;
2996 switch ((opcode
>> 4) & 0x0f) {
2998 mnemonic
= "LEAVEX";
3001 mnemonic
= "ENTERX";
3016 return ERROR_INVALID_ARGUMENTS
;
3018 strcpy(cp
, mnemonic
);
3022 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3023 struct arm_instruction
*instruction
, char *cp
)
3025 /* permanently undefined */
3026 if ((opcode
& 0x07f07000) == 0x07f02000) {
3027 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3028 strcpy(cp
, "UNDEFINED");
3032 switch ((opcode
>> 12) & 0x5) {
3035 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3039 if (((opcode
>> 23) & 0x07) != 0x07)
3040 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3041 if (opcode
& (1 << 26))
3046 switch ((opcode
>> 20) & 0x7f) {
3049 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3050 (int) (opcode
>> 16) & 0x0f);
3053 return t2ev_hint(opcode
, address
, instruction
, cp
);
3055 return t2ev_misc(opcode
, address
, instruction
, cp
);
3057 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3061 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3062 special_name(opcode
& 0xff));
3067 return ERROR_INVALID_ARGUMENTS
;
3070 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3071 struct arm_instruction
*instruction
, char *cp
)
3073 char *mnemonic
= NULL
;
3074 int rn
= (opcode
>> 16) & 0xf;
3075 int rd
= (opcode
>> 8) & 0xf;
3076 unsigned immed
= opcode
& 0xff;
3082 /* ARMv7-M: A5.3.2 Modified immediate constants */
3083 func
= (opcode
>> 11) & 0x0e;
3086 if (opcode
& (1 << 26))
3089 /* "Modified" immediates */
3090 switch (func
>> 1) {
3097 immed
+= immed
<< 16;
3100 immed
+= immed
<< 8;
3101 immed
+= immed
<< 16;
3105 immed
= ror(immed
, func
);
3108 if (opcode
& (1 << 20))
3111 switch ((opcode
>> 21) & 0xf) {
3114 instruction
->type
= ARM_TST
;
3120 instruction
->type
= ARM_AND
;
3125 instruction
->type
= ARM_BIC
;
3130 instruction
->type
= ARM_MOV
;
3135 instruction
->type
= ARM_ORR
;
3141 instruction
->type
= ARM_MVN
;
3145 // instruction->type = ARM_ORN;
3151 instruction
->type
= ARM_TEQ
;
3157 instruction
->type
= ARM_EOR
;
3163 instruction
->type
= ARM_CMN
;
3169 instruction
->type
= ARM_ADD
;
3175 instruction
->type
= ARM_ADC
;
3180 instruction
->type
= ARM_SBC
;
3185 instruction
->type
= ARM_CMP
;
3191 instruction
->type
= ARM_SUB
;
3197 instruction
->type
= ARM_RSB
;
3202 return ERROR_INVALID_ARGUMENTS
;
3206 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3207 mnemonic
, suffix2
,rd
, immed
, immed
);
3209 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3210 mnemonic
, suffix
, suffix2
,
3211 rd
, rn
, immed
, immed
);
3216 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3217 struct arm_instruction
*instruction
, char *cp
)
3219 char *mnemonic
= NULL
;
3220 int rn
= (opcode
>> 16) & 0xf;
3221 int rd
= (opcode
>> 8) & 0xf;
3224 bool is_signed
= false;
3226 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3227 if (opcode
& (1 << 26))
3230 switch ((opcode
>> 20) & 0x1f) {
3239 immed
|= (opcode
>> 4) & 0xf000;
3240 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3248 /* move constant to top 16 bits of register */
3249 immed
|= (opcode
>> 4) & 0xf000;
3250 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3257 /* signed/unsigned saturated add */
3258 immed
= (opcode
>> 6) & 0x03;
3259 immed
|= (opcode
>> 10) & 0x1c;
3260 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3261 is_signed
? "S" : "U",
3262 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3263 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3264 immed
? immed
: 32);
3270 /* signed/unsigned bitfield extract */
3271 immed
= (opcode
>> 6) & 0x03;
3272 immed
|= (opcode
>> 10) & 0x1c;
3273 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3274 is_signed
? "S" : "U",
3276 (int) (opcode
& 0x1f) + 1);
3279 immed
= (opcode
>> 6) & 0x03;
3280 immed
|= (opcode
>> 10) & 0x1c;
3281 if (rn
== 0xf) /* bitfield clear */
3282 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3284 (int) (opcode
& 0x1f) + 1 - immed
);
3285 else /* bitfield insert */
3286 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3288 (int) (opcode
& 0x1f) + 1 - immed
);
3291 return ERROR_INVALID_ARGUMENTS
;
3294 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3295 rd
, rn
, immed
, immed
);
3299 address
= thumb_alignpc4(address
);
3304 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3305 * not hiding the pc-relative stuff will sometimes be useful.
3307 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3311 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3312 struct arm_instruction
*instruction
, char *cp
)
3314 unsigned op
= (opcode
>> 20) & 0xf;
3320 unsigned rn
= (opcode
>> 16) & 0x0f;
3321 unsigned rt
= (opcode
>> 12) & 0x0f;
3324 return ERROR_INVALID_ARGUMENTS
;
3326 if (opcode
& 0x0800)
3361 return ERROR_INVALID_ARGUMENTS
;
3364 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3365 size
, rt
, rn
, (int) opcode
& 0x0f,
3366 (int) (opcode
>> 4) & 0x03);
3370 immed
= opcode
& 0x0fff;
3371 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3372 size
, rt
, rn
, immed
, immed
);
3376 immed
= opcode
& 0x00ff;
3378 switch (opcode
& 0x700) {
3384 return ERROR_INVALID_ARGUMENTS
;
3387 /* two indexed modes will write back rn */
3388 if (opcode
& 0x100) {
3389 if (opcode
& 0x400) /* pre-indexed */
3391 else { /* post-indexed */
3397 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3398 size
, suffix
, rt
, rn
, p1
,
3399 (opcode
& 0x200) ? "" : "-",
3404 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3405 struct arm_instruction
*instruction
, char *cp
)
3407 int ra
= (opcode
>> 12) & 0xf;
3409 switch (opcode
& 0x007000f0) {
3412 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3413 (int) (opcode
>> 8) & 0xf,
3414 (int) (opcode
>> 16) & 0xf,
3415 (int) (opcode
>> 0) & 0xf);
3417 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3418 (int) (opcode
>> 8) & 0xf,
3419 (int) (opcode
>> 16) & 0xf,
3420 (int) (opcode
>> 0) & 0xf, ra
);
3423 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3424 (int) (opcode
>> 8) & 0xf,
3425 (int) (opcode
>> 16) & 0xf,
3426 (int) (opcode
>> 0) & 0xf, ra
);
3429 return ERROR_INVALID_ARGUMENTS
;
3434 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3435 struct arm_instruction
*instruction
, char *cp
)
3437 int op
= (opcode
>> 4) & 0xf;
3438 char *infix
= "MUL";
3440 op
+= (opcode
>> 16) & 0x70;
3448 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3449 (op
& 0x20) ? 'U' : 'S',
3451 (int) (opcode
>> 12) & 0xf,
3452 (int) (opcode
>> 8) & 0xf,
3453 (int) (opcode
>> 16) & 0xf,
3454 (int) (opcode
>> 0) & 0xf);
3458 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3459 (op
& 0x20) ? 'U' : 'S',
3460 (int) (opcode
>> 8) & 0xf,
3461 (int) (opcode
>> 16) & 0xf,
3462 (int) (opcode
>> 0) & 0xf);
3465 return ERROR_INVALID_ARGUMENTS
;
3471 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3472 struct arm_instruction
*instruction
, char *cp
)
3474 int rn
= (opcode
>> 16) & 0xf;
3475 int op
= (opcode
>> 22) & 0x6;
3476 int t
= (opcode
>> 21) & 1;
3477 unsigned registers
= opcode
& 0xffff;
3480 if (opcode
& (1 << 20))
3488 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3490 (unsigned) (opcode
& 0x1f));
3496 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3497 (unsigned) ((opcode
>> 16) & 0xf),
3501 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3505 sprintf(cp
, "POP.W\t");
3507 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3511 sprintf(cp
, "PUSH.W\t");
3513 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3516 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3519 return ERROR_INVALID_ARGUMENTS
;
3524 for (t
= 0; registers
; t
++, registers
>>= 1) {
3525 if ((registers
& 1) == 0)
3528 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3537 /* load/store dual or exclusive, table branch */
3538 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3539 struct arm_instruction
*instruction
, char *cp
)
3541 unsigned op1op2
= (opcode
>> 20) & 0x3;
3542 unsigned op3
= (opcode
>> 4) & 0xf;
3544 unsigned rn
= (opcode
>> 16) & 0xf;
3545 unsigned rt
= (opcode
>> 12) & 0xf;
3546 unsigned rd
= (opcode
>> 8) & 0xf;
3547 unsigned imm
= opcode
& 0xff;
3551 op1op2
|= (opcode
>> 21) & 0xc;
3581 mnemonic
= "STREXB";
3584 mnemonic
= "STREXH";
3587 return ERROR_INVALID_ARGUMENTS
;
3595 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3598 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3601 mnemonic
= "LDREXB";
3604 mnemonic
= "LDREXH";
3607 return ERROR_INVALID_ARGUMENTS
;
3612 return ERROR_INVALID_ARGUMENTS
;
3617 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3618 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3620 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3621 mnemonic
, rd
, rt
, rn
);
3627 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3628 mnemonic
, rt
, rn
, imm
, imm
);
3630 sprintf(cp
, "%s\tr%u, [r%u]",
3635 /* two indexed modes will write back rn */
3636 if (opcode
& (1 << 21)) {
3637 if (opcode
& (1 << 24)) /* pre-indexed */
3639 else { /* post-indexed */
3646 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3647 mnemonic
, rt
, rd
, rn
, p1
,
3648 (opcode
& (1 << 23)) ? "" : "-",
3653 address
= thumb_alignpc4(address
);
3655 if (opcode
& (1 << 23))
3659 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3660 mnemonic
, rt
, rd
, address
);
3664 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3665 struct arm_instruction
*instruction
, char *cp
)
3667 int op
= (opcode
>> 21) & 0xf;
3668 int rd
= (opcode
>> 8) & 0xf;
3669 int rn
= (opcode
>> 16) & 0xf;
3670 int type
= (opcode
>> 4) & 0x3;
3671 int immed
= (opcode
>> 6) & 0x3;
3675 immed
|= (opcode
>> 10) & 0x1c;
3676 if (opcode
& (1 << 20))
3682 if (!(opcode
& (1 << 20)))
3683 return ERROR_INVALID_ARGUMENTS
;
3684 instruction
->type
= ARM_TST
;
3689 instruction
->type
= ARM_AND
;
3693 instruction
->type
= ARM_BIC
;
3698 instruction
->type
= ARM_MOV
;
3702 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3704 (int) (opcode
& 0xf));
3717 sprintf(cp
, "RRX%s\tr%d, r%d",
3719 (int) (opcode
& 0xf));
3727 instruction
->type
= ARM_ORR
;
3733 instruction
->type
= ARM_MVN
;
3738 // instruction->type = ARM_ORN;
3744 if (!(opcode
& (1 << 20)))
3745 return ERROR_INVALID_ARGUMENTS
;
3746 instruction
->type
= ARM_TEQ
;
3751 instruction
->type
= ARM_EOR
;
3756 if (!(opcode
& (1 << 20)))
3757 return ERROR_INVALID_ARGUMENTS
;
3758 instruction
->type
= ARM_CMN
;
3763 instruction
->type
= ARM_ADD
;
3767 instruction
->type
= ARM_ADC
;
3771 instruction
->type
= ARM_SBC
;
3776 if (!(opcode
& (1 << 21)))
3777 return ERROR_INVALID_ARGUMENTS
;
3778 instruction
->type
= ARM_CMP
;
3783 instruction
->type
= ARM_SUB
;
3787 instruction
->type
= ARM_RSB
;
3791 return ERROR_INVALID_ARGUMENTS
;
3794 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3795 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3818 strcpy(cp
, ", RRX");
3824 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3828 sprintf(cp
, "%s%s.W\tr%d, r%d",
3829 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3833 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3834 mnemonic
, suffix
, rd
,
3835 (int) (opcode
& 0xf), immed
? immed
: 32);
3839 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3840 struct arm_instruction
*instruction
, char *cp
)
3845 if (((opcode
>> 4) & 0xf) == 0) {
3846 switch ((opcode
>> 21) & 0x7) {
3860 return ERROR_INVALID_ARGUMENTS
;
3863 instruction
->type
= ARM_MOV
;
3864 if (opcode
& (1 << 20))
3866 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3868 (int) (opcode
>> 8) & 0xf,
3869 (int) (opcode
>> 16) & 0xf,
3870 (int) (opcode
>> 0) & 0xf);
3872 } else if (opcode
& (1 << 7)) {
3873 switch ((opcode
>> 20) & 0xf) {
3878 switch ((opcode
>> 4) & 0x3) {
3880 suffix
= ", ROR #8";
3883 suffix
= ", ROR #16";
3886 suffix
= ", ROR #24";
3889 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3890 (opcode
& (1 << 24)) ? 'U' : 'S',
3891 (opcode
& (1 << 26)) ? 'B' : 'H',
3892 (int) (opcode
>> 8) & 0xf,
3893 (int) (opcode
>> 0) & 0xf,
3900 if (opcode
& (1 << 6))
3901 return ERROR_INVALID_ARGUMENTS
;
3902 if (((opcode
>> 12) & 0xf) != 0xf)
3903 return ERROR_INVALID_ARGUMENTS
;
3904 if (!(opcode
& (1 << 20)))
3905 return ERROR_INVALID_ARGUMENTS
;
3907 switch (((opcode
>> 19) & 0x04)
3908 | ((opcode
>> 4) & 0x3)) {
3913 mnemonic
= "REV16.W";
3919 mnemonic
= "REVSH.W";
3925 return ERROR_INVALID_ARGUMENTS
;
3927 sprintf(cp
, "%s\tr%d, r%d",
3929 (int) (opcode
>> 8) & 0xf,
3930 (int) (opcode
>> 0) & 0xf);
3933 return ERROR_INVALID_ARGUMENTS
;
3940 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3941 struct arm_instruction
*instruction
, char *cp
)
3943 int rn
= (opcode
>> 16) & 0xf;
3946 instruction
->type
= ARM_LDR
;
3949 immed
= opcode
& 0x0fff;
3950 if ((opcode
& (1 << 23)) == 0)
3952 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3953 (int) (opcode
>> 12) & 0xf,
3954 thumb_alignpc4(address
) + immed
);
3958 if (opcode
& (1 << 23)) {
3959 immed
= opcode
& 0x0fff;
3960 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3961 (int) (opcode
>> 12) & 0xf,
3966 if (!(opcode
& (0x3f << 6))) {
3967 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3968 (int) (opcode
>> 12) & 0xf,
3970 (int) (opcode
>> 0) & 0xf,
3971 (int) (opcode
>> 4) & 0x3);
3976 if (((opcode
>> 8) & 0xf) == 0xe) {
3977 immed
= opcode
& 0x00ff;
3979 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3980 (int) (opcode
>> 12) & 0xf,
3985 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3986 char *p1
= "]", *p2
= "";
3988 if (!(opcode
& 0x0500))
3989 return ERROR_INVALID_ARGUMENTS
;
3991 immed
= opcode
& 0x00ff;
3993 /* two indexed modes will write back rn */
3994 if (opcode
& 0x100) {
3995 if (opcode
& 0x400) /* pre-indexed */
3997 else { /* post-indexed */
4003 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4004 (int) (opcode
>> 12) & 0xf,
4006 (opcode
& 0x200) ? "" : "-",
4011 return ERROR_INVALID_ARGUMENTS
;
4014 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4015 struct arm_instruction
*instruction
, char *cp
)
4017 int rn
= (opcode
>> 16) & 0xf;
4018 int rt
= (opcode
>> 12) & 0xf;
4019 int op2
= (opcode
>> 6) & 0x3f;
4021 char *p1
= "", *p2
= "]";
4024 switch ((opcode
>> 23) & 0x3) {
4026 if ((rn
& rt
) == 0xf) {
4028 immed
= opcode
& 0xfff;
4029 address
= thumb_alignpc4(address
);
4030 if (opcode
& (1 << 23))
4034 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4038 if (rn
== 0x0f && rt
!= 0x0f) {
4040 immed
= opcode
& 0xfff;
4041 address
= thumb_alignpc4(address
);
4042 if (opcode
& (1 << 23))
4046 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4052 if ((op2
& 0x3c) == 0x38) {
4053 immed
= opcode
& 0xff;
4054 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4055 rt
, rn
, immed
, immed
);
4058 if ((op2
& 0x3c) == 0x30) {
4060 immed
= opcode
& 0xff;
4063 p1
= (opcode
& (1 << 21)) ? "W" : "";
4064 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4065 p1
, rn
, immed
, immed
);
4070 immed
= opcode
& 0xff;
4071 if (!(opcode
& 0x200))
4074 /* two indexed modes will write back rn */
4075 if (opcode
& 0x100) {
4076 if (opcode
& 0x400) /* pre-indexed */
4078 else { /* post-indexed */
4084 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4085 mnemonic
, rt
, rn
, p1
,
4089 if ((op2
& 0x24) == 0x24) {
4091 goto ldrxb_immediate_t3
;
4094 int rm
= opcode
& 0xf;
4097 sprintf(cp
, "PLD\t");
4099 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4100 immed
= (opcode
>> 4) & 0x3;
4102 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4107 if ((rn
& rt
) == 0xf)
4110 immed
= opcode
& 0xfff;
4111 goto preload_immediate
;
4115 mnemonic
= "LDRB.W";
4116 immed
= opcode
& 0xfff;
4117 goto ldrxb_immediate_t2
;
4119 if ((rn
& rt
) == 0xf) {
4120 immed
= opcode
& 0xfff;
4121 address
= thumb_alignpc4(address
);
4122 if (opcode
& (1 << 23))
4126 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4129 if (rn
== 0xf && rt
!= 0xf) {
4131 immed
= opcode
& 0xfff;
4132 address
= thumb_alignpc4(address
);
4133 if (opcode
& (1 << 23))
4137 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4142 if ((op2
& 0x3c) == 0x38) {
4143 immed
= opcode
& 0xff;
4144 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4145 rt
, rn
, immed
, immed
);
4148 if ((op2
& 0x3c) == 0x30) {
4150 immed
= opcode
& 0xff;
4151 immed
= -immed
; // pli
4152 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4157 goto ldrxb_immediate_t3
;
4159 if ((op2
& 0x24) == 0x24) {
4161 goto ldrxb_immediate_t3
;
4164 int rm
= opcode
& 0xf;
4167 sprintf(cp
, "PLI\t");
4169 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4170 immed
= (opcode
>> 4) & 0x3;
4172 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4178 immed
= opcode
& 0xfff;
4179 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4185 immed
= opcode
& 0xfff;
4187 goto ldrxb_immediate_t2
;
4190 return ERROR_INVALID_ARGUMENTS
;
4193 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4194 struct arm_instruction
*instruction
, char *cp
)
4196 int rn
= (opcode
>> 16) & 0xf;
4197 int rt
= (opcode
>> 12) & 0xf;
4198 int op2
= (opcode
>> 6) & 0x3f;
4203 sprintf(cp
, "HINT (UNALLOCATED)");
4207 if (opcode
& (1 << 24))
4210 if ((opcode
& (1 << 23)) == 0) {
4213 immed
= opcode
& 0xfff;
4214 address
= thumb_alignpc4(address
);
4215 if (opcode
& (1 << 23))
4219 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4224 int rm
= opcode
& 0xf;
4226 immed
= (opcode
>> 4) & 0x3;
4227 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4228 sign
, rt
, rn
, rm
, immed
);
4231 if ((op2
& 0x3c) == 0x38) {
4232 immed
= opcode
& 0xff;
4233 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4234 sign
, rt
, rn
, immed
, immed
);
4237 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4238 char *p1
= "", *p2
= "]";
4240 immed
= opcode
& 0xff;
4241 if (!(opcode
& 0x200))
4244 /* two indexed modes will write back rn */
4245 if (opcode
& 0x100) {
4246 if (opcode
& 0x400) /* pre-indexed */
4248 else { /* post-indexed */
4253 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4254 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4261 immed
= opcode
& 0xfff;
4262 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4263 sign
, *sign
? "" : ".W",
4264 rt
, rn
, immed
, immed
);
4268 return ERROR_INVALID_ARGUMENTS
;
4272 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4273 * always set. That means eventual arm_simulate_step() support for Thumb2
4274 * will need work in this area.
4276 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4283 /* clear low bit ... it's set on function pointers */
4286 /* clear fields, to avoid confusion */
4287 memset(instruction
, 0, sizeof(struct arm_instruction
));
4289 /* read first halfword, see if this is the only one */
4290 retval
= target_read_u16(target
, address
, &op
);
4291 if (retval
!= ERROR_OK
)
4294 switch (op
& 0xf800) {
4298 /* 32-bit instructions */
4299 instruction
->instruction_size
= 4;
4301 retval
= target_read_u16(target
, address
+ 2, &op
);
4302 if (retval
!= ERROR_OK
)
4305 instruction
->opcode
= opcode
;
4308 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4309 return thumb_evaluate_opcode(op
, address
, instruction
);
4312 snprintf(instruction
->text
, 128,
4313 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4315 cp
= strchr(instruction
->text
, 0);
4316 retval
= ERROR_FAIL
;
4318 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4319 if ((opcode
& 0x1a008000) == 0x10000000)
4320 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4322 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4323 else if ((opcode
& 0x1a008000) == 0x12000000)
4324 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4326 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4327 else if ((opcode
& 0x18008000) == 0x10008000)
4328 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4330 /* ARMv7-M: A5.3.5 Load/store multiple */
4331 else if ((opcode
& 0x1e400000) == 0x08000000)
4332 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4334 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4335 else if ((opcode
& 0x1e400000) == 0x08400000)
4336 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4338 /* ARMv7-M: A5.3.7 Load word */
4339 else if ((opcode
& 0x1f700000) == 0x18500000)
4340 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4342 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4343 else if ((opcode
& 0x1e700000) == 0x18300000)
4344 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4346 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4347 else if ((opcode
& 0x1e700000) == 0x18100000)
4348 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4350 /* ARMv7-M: A5.3.10 Store single data item */
4351 else if ((opcode
& 0x1f100000) == 0x18000000)
4352 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4354 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4355 else if ((opcode
& 0x1e000000) == 0x0a000000)
4356 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4358 /* ARMv7-M: A5.3.12 Data processing (register)
4359 * and A5.3.13 Miscellaneous operations
4361 else if ((opcode
& 0x1f000000) == 0x1a000000)
4362 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4364 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4365 else if ((opcode
& 0x1f800000) == 0x1b000000)
4366 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4368 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4369 else if ((opcode
& 0x1f800000) == 0x1b800000)
4370 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4372 if (retval
== ERROR_OK
)
4376 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4377 * instructions; not yet handled here.
4380 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4381 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4382 strcpy(cp
, "UNDEFINED OPCODE");
4386 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4389 strcpy(cp
, "(32-bit Thumb2 ...)");
4393 int arm_access_size(struct arm_instruction
*instruction
)
4395 if ((instruction
->type
== ARM_LDRB
)
4396 || (instruction
->type
== ARM_LDRBT
)
4397 || (instruction
->type
== ARM_LDRSB
)
4398 || (instruction
->type
== ARM_STRB
)
4399 || (instruction
->type
== ARM_STRBT
))
4403 else if ((instruction
->type
== ARM_LDRH
)
4404 || (instruction
->type
== ARM_LDRSH
)
4405 || (instruction
->type
== ARM_STRH
))
4409 else if ((instruction
->type
== ARM_LDR
)
4410 || (instruction
->type
== ARM_LDRT
)
4411 || (instruction
->type
== ARM_STR
)
4412 || (instruction
->type
== ARM_STRT
))
4416 else if ((instruction
->type
== ARM_LDRD
)
4417 || (instruction
->type
== ARM_STRD
))
4423 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)