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 * * NEON instructions are not understood (ARMv7-A)
55 * - Thumb/Thumb2 decoding
56 * * UAL syntax should be consistently used
57 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
58 * be handled properly. Accordingly, so should the subset
59 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
61 * * Conditional effects of Thumb2 "IT" (if-then) instructions
62 * are not handled: the affected instructions are not shown
63 * with their now-conditional suffixes.
64 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
65 * handled (minimally for coprocessor access).
66 * * SIMD instructions, and some other Thumb2 instructions
67 * from ARMv7-A, are not understood.
70 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
71 * * Opcodes changed by ThumbEE mode are not handled; these
72 * instructions wrongly decode as LDM and STM.
74 * - Jazelle decoding ... no support whatsoever for Jazelle mode
75 * or decoding. ARM encourages use of the more generic ThumbEE
76 * mode, instead of Jazelle mode, in current chips.
78 * - Single-step/emulation ... spotty support, which is only weakly
79 * tested. Thumb2 is not supported. (Arguably a full simulator
80 * is not needed to support just single stepping. Recognizing
81 * branch vs non-branch instructions suffices, except when the
82 * instruction faults and triggers a synchronous exception which
83 * can be intercepted using other means.)
85 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
86 * ARM v7-R edition" gives the most complete coverage of the various
87 * generations of ARM instructions. At this writing it is publicly
88 * accessible to anyone willing to create an account at the ARM
89 * web site; see http://www.arm.com/documentation/ for information.
91 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
92 * more details relevant to the Thumb2-only processors (such as
93 * the Cortex-M implementations).
96 /* textual represenation of the condition field */
97 /* ALways (default) is ommitted (empty string) */
98 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_pld(uint32_t opcode
,
110 uint32_t address
, struct arm_instruction
*instruction
)
113 if ((opcode
& 0x0d70f000) == 0x0550f000)
115 instruction
->type
= ARM_PLD
;
117 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
123 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
127 LOG_ERROR("should never reach this point");
131 static int evaluate_swi(uint32_t opcode
,
132 uint32_t address
, struct arm_instruction
*instruction
)
134 instruction
->type
= ARM_SWI
;
136 snprintf(instruction
->text
, 128,
137 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
138 address
, opcode
, (opcode
& 0xffffff));
143 static int evaluate_blx_imm(uint32_t opcode
,
144 uint32_t address
, struct arm_instruction
*instruction
)
148 uint32_t target_address
;
150 instruction
->type
= ARM_BLX
;
151 immediate
= opcode
& 0x00ffffff;
153 /* sign extend 24-bit immediate */
154 if (immediate
& 0x00800000)
155 offset
= 0xff000000 | immediate
;
159 /* shift two bits left */
162 /* odd/event halfword */
163 if (opcode
& 0x01000000)
166 target_address
= address
+ 8 + offset
;
168 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
170 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
171 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
176 static int evaluate_b_bl(uint32_t opcode
,
177 uint32_t address
, struct arm_instruction
*instruction
)
182 uint32_t target_address
;
184 immediate
= opcode
& 0x00ffffff;
185 L
= (opcode
& 0x01000000) >> 24;
187 /* sign extend 24-bit immediate */
188 if (immediate
& 0x00800000)
189 offset
= 0xff000000 | immediate
;
193 /* shift two bits left */
196 target_address
= address
+ 8 + offset
;
199 instruction
->type
= ARM_BL
;
201 instruction
->type
= ARM_B
;
203 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
204 (L
) ? "L" : "", COND(opcode
), target_address
);
206 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
207 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
212 /* Coprocessor load/store and double register transfers */
213 /* both normal and extended instruction space (condition field b1111) */
214 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
215 uint32_t address
, struct arm_instruction
*instruction
)
217 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
220 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
222 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
225 cp_opcode
= (opcode
& 0xf0) >> 4;
226 Rd
= (opcode
& 0xf000) >> 12;
227 Rn
= (opcode
& 0xf0000) >> 16;
228 CRm
= (opcode
& 0xf);
231 if ((opcode
& 0x0ff00000) == 0x0c400000)
233 instruction
->type
= ARM_MCRR
;
238 if ((opcode
& 0x0ff00000) == 0x0c500000)
240 instruction
->type
= ARM_MRRC
;
244 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
245 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
247 else /* LDC or STC */
249 uint8_t CRd
, Rn
, offset
;
252 char addressing_mode
[32];
254 CRd
= (opcode
& 0xf000) >> 12;
255 Rn
= (opcode
& 0xf0000) >> 16;
256 offset
= (opcode
& 0xff);
259 if (opcode
& 0x00100000)
261 instruction
->type
= ARM_LDC
;
266 instruction
->type
= ARM_STC
;
270 U
= (opcode
& 0x00800000) >> 23;
271 N
= (opcode
& 0x00400000) >> 22;
273 /* addressing modes */
274 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
275 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
276 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
277 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
278 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
279 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
280 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
281 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
283 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
284 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
286 cp_num
, CRd
, addressing_mode
);
292 /* Coprocessor data processing instructions */
293 /* Coprocessor register transfer instructions */
294 /* both normal and extended instruction space (condition field b1111) */
295 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
296 uint32_t address
, struct arm_instruction
*instruction
)
300 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
302 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
303 cp_num
= (opcode
& 0xf00) >> 8;
304 CRd_Rd
= (opcode
& 0xf000) >> 12;
305 CRn
= (opcode
& 0xf0000) >> 16;
306 CRm
= (opcode
& 0xf);
307 opcode_2
= (opcode
& 0xe0) >> 5;
310 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
312 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
314 instruction
->type
= ARM_MRC
;
317 else /* bit 20 not set -> MCR */
319 instruction
->type
= ARM_MCR
;
323 opcode_1
= (opcode
& 0x00e00000) >> 21;
325 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",
326 address
, opcode
, mnemonic
, cond
,
327 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
329 else /* bit 4 not set -> CDP */
331 instruction
->type
= ARM_CDP
;
334 opcode_1
= (opcode
& 0x00f00000) >> 20;
336 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",
337 address
, opcode
, mnemonic
, cond
,
338 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
344 /* Load/store instructions */
345 static int evaluate_load_store(uint32_t opcode
,
346 uint32_t address
, struct arm_instruction
*instruction
)
348 uint8_t I
, P
, U
, B
, W
, L
;
350 char *operation
; /* "LDR" or "STR" */
351 char *suffix
; /* "", "B", "T", "BT" */
355 I
= (opcode
& 0x02000000) >> 25;
356 P
= (opcode
& 0x01000000) >> 24;
357 U
= (opcode
& 0x00800000) >> 23;
358 B
= (opcode
& 0x00400000) >> 22;
359 W
= (opcode
& 0x00200000) >> 21;
360 L
= (opcode
& 0x00100000) >> 20;
362 /* target register */
363 Rd
= (opcode
& 0xf000) >> 12;
366 Rn
= (opcode
& 0xf0000) >> 16;
368 instruction
->info
.load_store
.Rd
= Rd
;
369 instruction
->info
.load_store
.Rn
= Rn
;
370 instruction
->info
.load_store
.U
= U
;
372 /* determine operation */
378 /* determine instruction type and suffix */
381 if ((P
== 0) && (W
== 1))
384 instruction
->type
= ARM_LDRBT
;
386 instruction
->type
= ARM_STRBT
;
392 instruction
->type
= ARM_LDRB
;
394 instruction
->type
= ARM_STRB
;
400 if ((P
== 0) && (W
== 1))
403 instruction
->type
= ARM_LDRT
;
405 instruction
->type
= ARM_STRT
;
411 instruction
->type
= ARM_LDR
;
413 instruction
->type
= ARM_STR
;
418 if (!I
) /* #+-<offset_12> */
420 uint32_t offset_12
= (opcode
& 0xfff);
422 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
424 snprintf(offset
, 32, "%s", "");
426 instruction
->info
.load_store
.offset_mode
= 0;
427 instruction
->info
.load_store
.offset
.offset
= offset_12
;
429 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
431 uint8_t shift_imm
, shift
;
434 shift_imm
= (opcode
& 0xf80) >> 7;
435 shift
= (opcode
& 0x60) >> 5;
438 /* LSR encodes a shift by 32 bit as 0x0 */
439 if ((shift
== 0x1) && (shift_imm
== 0x0))
442 /* ASR encodes a shift by 32 bit as 0x0 */
443 if ((shift
== 0x2) && (shift_imm
== 0x0))
446 /* ROR by 32 bit is actually a RRX */
447 if ((shift
== 0x3) && (shift_imm
== 0x0))
450 instruction
->info
.load_store
.offset_mode
= 1;
451 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
452 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
453 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
455 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
457 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
459 else /* +-<Rm>, <Shift>, #<shift_imm> */
464 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
467 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
470 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
473 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
476 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
484 if (W
== 0) /* offset */
486 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
487 address
, opcode
, operation
, COND(opcode
), suffix
,
490 instruction
->info
.load_store
.index_mode
= 0;
492 else /* pre-indexed */
494 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
495 address
, opcode
, operation
, COND(opcode
), suffix
,
498 instruction
->info
.load_store
.index_mode
= 1;
501 else /* post-indexed */
503 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
504 address
, opcode
, operation
, COND(opcode
), suffix
,
507 instruction
->info
.load_store
.index_mode
= 2;
513 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
515 unsigned rm
= (opcode
>> 0) & 0xf;
516 unsigned rd
= (opcode
>> 12) & 0xf;
517 unsigned rn
= (opcode
>> 16) & 0xf;
520 switch ((opcode
>> 24) & 0x3) {
525 sprintf(cp
, "UNDEFINED");
526 return ARM_UNDEFINED_INSTRUCTION
;
535 switch ((opcode
>> 10) & 0x3) {
551 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
552 (opcode
& (1 << 22)) ? 'U' : 'S',
557 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
558 (opcode
& (1 << 22)) ? 'U' : 'S',
565 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
571 switch ((opcode
>> 20) & 0x7) {
594 switch ((opcode
>> 5) & 0x7) {
623 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
624 (int) (opcode
>> 12) & 0xf,
625 (int) (opcode
>> 16) & 0xf,
626 (int) (opcode
>> 0) & 0xf);
630 /* these opcodes might be used someday */
631 sprintf(cp
, "UNDEFINED");
632 return ARM_UNDEFINED_INSTRUCTION
;
635 /* ARMv6 and later support "media" instructions (includes SIMD) */
636 static int evaluate_media(uint32_t opcode
, uint32_t address
,
637 struct arm_instruction
*instruction
)
639 char *cp
= instruction
->text
;
640 char *mnemonic
= NULL
;
643 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
647 /* parallel add/subtract */
648 if ((opcode
& 0x01800000) == 0x00000000) {
649 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
654 if ((opcode
& 0x01f00020) == 0x00800000) {
656 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
658 if (opcode
& (1 << 6)) {
667 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
669 (int) (opcode
>> 12) & 0xf,
670 (int) (opcode
>> 16) & 0xf,
671 (int) (opcode
>> 0) & 0xf,
677 if ((opcode
& 0x01a00020) == 0x00a00000) {
679 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
681 if (opcode
& (1 << 6)) {
689 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
690 (opcode
& (1 << 22)) ? 'U' : 'S',
692 (int) (opcode
>> 12) & 0xf,
693 (int) (opcode
>> 16) & 0x1f,
694 (int) (opcode
>> 0) & 0xf,
700 if ((opcode
& 0x018000f0) == 0x00800070) {
701 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
706 if ((opcode
& 0x01f00080) == 0x01000000) {
707 unsigned rn
= (opcode
>> 12) & 0xf;
710 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
711 (opcode
& (1 << 6)) ? 'S' : 'A',
712 (opcode
& (1 << 5)) ? "X" : "",
714 (int) (opcode
>> 16) & 0xf,
715 (int) (opcode
>> 0) & 0xf,
716 (int) (opcode
>> 8) & 0xf,
719 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
720 (opcode
& (1 << 6)) ? 'S' : 'A',
721 (opcode
& (1 << 5)) ? "X" : "",
723 (int) (opcode
>> 16) & 0xf,
724 (int) (opcode
>> 0) & 0xf,
725 (int) (opcode
>> 8) & 0xf);
728 if ((opcode
& 0x01f00000) == 0x01400000) {
729 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
730 (opcode
& (1 << 6)) ? 'S' : 'A',
731 (opcode
& (1 << 5)) ? "X" : "",
733 (int) (opcode
>> 12) & 0xf,
734 (int) (opcode
>> 16) & 0xf,
735 (int) (opcode
>> 0) & 0xf,
736 (int) (opcode
>> 8) & 0xf);
739 if ((opcode
& 0x01f00000) == 0x01500000) {
740 unsigned rn
= (opcode
>> 12) & 0xf;
742 switch (opcode
& 0xc0) {
754 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
755 (opcode
& (1 << 6)) ? 'S' : 'A',
756 (opcode
& (1 << 5)) ? "R" : "",
758 (int) (opcode
>> 16) & 0xf,
759 (int) (opcode
>> 0) & 0xf,
760 (int) (opcode
>> 8) & 0xf,
763 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
764 (opcode
& (1 << 5)) ? "R" : "",
766 (int) (opcode
>> 16) & 0xf,
767 (int) (opcode
>> 0) & 0xf,
768 (int) (opcode
>> 8) & 0xf);
773 /* simple matches against the remaining decode bits */
774 switch (opcode
& 0x01f000f0) {
777 /* parallel halfword saturate */
778 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
779 (opcode
& (1 << 22)) ? 'U' : 'S',
781 (int) (opcode
>> 12) & 0xf,
782 (int) (opcode
>> 16) & 0xf,
783 (int) (opcode
>> 0) & 0xf);
796 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
797 (int) (opcode
>> 12) & 0xf,
798 (int) (opcode
>> 16) & 0xf,
799 (int) (opcode
>> 0) & 0xf);
802 /* unsigned sum of absolute differences */
803 if (((opcode
>> 12) & 0xf) == 0xf)
804 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
805 (int) (opcode
>> 16) & 0xf,
806 (int) (opcode
>> 0) & 0xf,
807 (int) (opcode
>> 8) & 0xf);
809 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
810 (int) (opcode
>> 16) & 0xf,
811 (int) (opcode
>> 0) & 0xf,
812 (int) (opcode
>> 8) & 0xf,
813 (int) (opcode
>> 12) & 0xf);
817 unsigned rm
= (opcode
>> 0) & 0xf;
818 unsigned rd
= (opcode
>> 12) & 0xf;
820 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
825 /* these opcodes might be used someday */
826 sprintf(cp
, "UNDEFINED");
830 /* Miscellaneous load/store instructions */
831 static int evaluate_misc_load_store(uint32_t opcode
,
832 uint32_t address
, struct arm_instruction
*instruction
)
834 uint8_t P
, U
, I
, W
, L
, S
, H
;
836 char *operation
; /* "LDR" or "STR" */
837 char *suffix
; /* "H", "SB", "SH", "D" */
841 P
= (opcode
& 0x01000000) >> 24;
842 U
= (opcode
& 0x00800000) >> 23;
843 I
= (opcode
& 0x00400000) >> 22;
844 W
= (opcode
& 0x00200000) >> 21;
845 L
= (opcode
& 0x00100000) >> 20;
846 S
= (opcode
& 0x00000040) >> 6;
847 H
= (opcode
& 0x00000020) >> 5;
849 /* target register */
850 Rd
= (opcode
& 0xf000) >> 12;
853 Rn
= (opcode
& 0xf0000) >> 16;
855 instruction
->info
.load_store
.Rd
= Rd
;
856 instruction
->info
.load_store
.Rn
= Rn
;
857 instruction
->info
.load_store
.U
= U
;
859 /* determine instruction type and suffix */
867 instruction
->type
= ARM_LDRSH
;
873 instruction
->type
= ARM_LDRSB
;
877 else /* there are no signed stores, so this is used to encode double-register load/stores */
883 instruction
->type
= ARM_STRD
;
888 instruction
->type
= ARM_LDRD
;
898 instruction
->type
= ARM_LDRH
;
903 instruction
->type
= ARM_STRH
;
907 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
909 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
910 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
912 instruction
->info
.load_store
.offset_mode
= 0;
913 instruction
->info
.load_store
.offset
.offset
= offset_8
;
915 else /* Register offset/index (+-<Rm>) */
919 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
921 instruction
->info
.load_store
.offset_mode
= 1;
922 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
923 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
924 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
929 if (W
== 0) /* offset */
931 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
932 address
, opcode
, operation
, COND(opcode
), suffix
,
935 instruction
->info
.load_store
.index_mode
= 0;
937 else /* pre-indexed */
939 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
940 address
, opcode
, operation
, COND(opcode
), suffix
,
943 instruction
->info
.load_store
.index_mode
= 1;
946 else /* post-indexed */
948 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
949 address
, opcode
, operation
, COND(opcode
), suffix
,
952 instruction
->info
.load_store
.index_mode
= 2;
958 /* Load/store multiples instructions */
959 static int evaluate_ldm_stm(uint32_t opcode
,
960 uint32_t address
, struct arm_instruction
*instruction
)
962 uint8_t P
, U
, S
, W
, L
, Rn
;
963 uint32_t register_list
;
964 char *addressing_mode
;
971 P
= (opcode
& 0x01000000) >> 24;
972 U
= (opcode
& 0x00800000) >> 23;
973 S
= (opcode
& 0x00400000) >> 22;
974 W
= (opcode
& 0x00200000) >> 21;
975 L
= (opcode
& 0x00100000) >> 20;
976 register_list
= (opcode
& 0xffff);
977 Rn
= (opcode
& 0xf0000) >> 16;
979 instruction
->info
.load_store_multiple
.Rn
= Rn
;
980 instruction
->info
.load_store_multiple
.register_list
= register_list
;
981 instruction
->info
.load_store_multiple
.S
= S
;
982 instruction
->info
.load_store_multiple
.W
= W
;
986 instruction
->type
= ARM_LDM
;
991 instruction
->type
= ARM_STM
;
999 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1000 addressing_mode
= "IB";
1004 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1005 addressing_mode
= "DB";
1012 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1013 /* "IA" is the default in UAL syntax */
1014 addressing_mode
= "";
1018 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1019 addressing_mode
= "DA";
1023 reg_list_p
= reg_list
;
1024 for (i
= 0; i
<= 15; i
++)
1026 if ((register_list
>> i
) & 1)
1031 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1035 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1040 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
1041 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
1042 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1047 /* Multiplies, extra load/stores */
1048 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1049 uint32_t address
, struct arm_instruction
*instruction
)
1051 /* Multiply (accumulate) (long) and Swap/swap byte */
1052 if ((opcode
& 0x000000f0) == 0x00000090)
1054 /* Multiply (accumulate) */
1055 if ((opcode
& 0x0f800000) == 0x00000000)
1057 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1059 Rs
= (opcode
& 0xf00) >> 8;
1060 Rn
= (opcode
& 0xf000) >> 12;
1061 Rd
= (opcode
& 0xf0000) >> 16;
1062 S
= (opcode
& 0x00100000) >> 20;
1064 /* examine A bit (accumulate) */
1065 if (opcode
& 0x00200000)
1067 instruction
->type
= ARM_MLA
;
1068 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1069 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1073 instruction
->type
= ARM_MUL
;
1074 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1075 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1081 /* Multiply (accumulate) long */
1082 if ((opcode
& 0x0f800000) == 0x00800000)
1084 char* mnemonic
= NULL
;
1085 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1087 Rs
= (opcode
& 0xf00) >> 8;
1088 RdHi
= (opcode
& 0xf000) >> 12;
1089 RdLow
= (opcode
& 0xf0000) >> 16;
1090 S
= (opcode
& 0x00100000) >> 20;
1092 switch ((opcode
& 0x00600000) >> 21)
1095 instruction
->type
= ARM_UMULL
;
1099 instruction
->type
= ARM_UMLAL
;
1103 instruction
->type
= ARM_SMULL
;
1107 instruction
->type
= ARM_SMLAL
;
1112 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1113 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1114 RdLow
, RdHi
, Rm
, Rs
);
1119 /* Swap/swap byte */
1120 if ((opcode
& 0x0f800000) == 0x01000000)
1124 Rd
= (opcode
& 0xf000) >> 12;
1125 Rn
= (opcode
& 0xf0000) >> 16;
1127 /* examine B flag */
1128 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1130 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1131 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1137 return evaluate_misc_load_store(opcode
, address
, instruction
);
1140 static int evaluate_mrs_msr(uint32_t opcode
,
1141 uint32_t address
, struct arm_instruction
*instruction
)
1143 int R
= (opcode
& 0x00400000) >> 22;
1144 char *PSR
= (R
) ? "SPSR" : "CPSR";
1146 /* Move register to status register (MSR) */
1147 if (opcode
& 0x00200000)
1149 instruction
->type
= ARM_MSR
;
1151 /* immediate variant */
1152 if (opcode
& 0x02000000)
1154 uint8_t immediate
= (opcode
& 0xff);
1155 uint8_t rotate
= (opcode
& 0xf00);
1157 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1158 address
, opcode
, COND(opcode
), PSR
,
1159 (opcode
& 0x10000) ? "c" : "",
1160 (opcode
& 0x20000) ? "x" : "",
1161 (opcode
& 0x40000) ? "s" : "",
1162 (opcode
& 0x80000) ? "f" : "",
1163 ror(immediate
, (rotate
* 2))
1166 else /* register variant */
1168 uint8_t Rm
= opcode
& 0xf;
1169 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1170 address
, opcode
, COND(opcode
), PSR
,
1171 (opcode
& 0x10000) ? "c" : "",
1172 (opcode
& 0x20000) ? "x" : "",
1173 (opcode
& 0x40000) ? "s" : "",
1174 (opcode
& 0x80000) ? "f" : "",
1180 else /* Move status register to register (MRS) */
1184 instruction
->type
= ARM_MRS
;
1185 Rd
= (opcode
& 0x0000f000) >> 12;
1187 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1188 address
, opcode
, COND(opcode
), Rd
, PSR
);
1194 /* Miscellaneous instructions */
1195 static int evaluate_misc_instr(uint32_t opcode
,
1196 uint32_t address
, struct arm_instruction
*instruction
)
1199 if ((opcode
& 0x000000f0) == 0x00000000)
1201 evaluate_mrs_msr(opcode
, address
, instruction
);
1205 if ((opcode
& 0x006000f0) == 0x00200010)
1208 instruction
->type
= ARM_BX
;
1211 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1212 address
, opcode
, COND(opcode
), Rm
);
1214 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1215 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1218 /* BXJ - "Jazelle" support (ARMv5-J) */
1219 if ((opcode
& 0x006000f0) == 0x00200020)
1222 instruction
->type
= ARM_BX
;
1225 snprintf(instruction
->text
, 128,
1226 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1227 address
, opcode
, COND(opcode
), Rm
);
1229 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1230 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1234 if ((opcode
& 0x006000f0) == 0x00600010)
1237 instruction
->type
= ARM_CLZ
;
1239 Rd
= (opcode
& 0xf000) >> 12;
1241 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1242 address
, opcode
, COND(opcode
), Rd
, Rm
);
1246 if ((opcode
& 0x006000f0) == 0x00200030)
1249 instruction
->type
= ARM_BLX
;
1252 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1253 address
, opcode
, COND(opcode
), Rm
);
1255 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1256 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1259 /* Enhanced DSP add/subtracts */
1260 if ((opcode
& 0x0000000f0) == 0x00000050)
1263 char *mnemonic
= NULL
;
1265 Rd
= (opcode
& 0xf000) >> 12;
1266 Rn
= (opcode
& 0xf0000) >> 16;
1268 switch ((opcode
& 0x00600000) >> 21)
1271 instruction
->type
= ARM_QADD
;
1275 instruction
->type
= ARM_QSUB
;
1279 instruction
->type
= ARM_QDADD
;
1283 instruction
->type
= ARM_QDSUB
;
1288 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1289 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1292 /* Software breakpoints */
1293 if ((opcode
& 0x0000000f0) == 0x00000070)
1296 instruction
->type
= ARM_BKPT
;
1297 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1299 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1300 address
, opcode
, immediate
);
1303 /* Enhanced DSP multiplies */
1304 if ((opcode
& 0x000000090) == 0x00000080)
1306 int x
= (opcode
& 0x20) >> 5;
1307 int y
= (opcode
& 0x40) >> 6;
1310 if ((opcode
& 0x00600000) == 0x00000000)
1312 uint8_t Rd
, Rm
, Rs
, Rn
;
1313 instruction
->type
= ARM_SMLAxy
;
1314 Rd
= (opcode
& 0xf0000) >> 16;
1315 Rm
= (opcode
& 0xf);
1316 Rs
= (opcode
& 0xf00) >> 8;
1317 Rn
= (opcode
& 0xf000) >> 12;
1319 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1320 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1325 if ((opcode
& 0x00600000) == 0x00400000)
1327 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1328 instruction
->type
= ARM_SMLAxy
;
1329 RdHi
= (opcode
& 0xf0000) >> 16;
1330 RdLow
= (opcode
& 0xf000) >> 12;
1331 Rm
= (opcode
& 0xf);
1332 Rs
= (opcode
& 0xf00) >> 8;
1334 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1335 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1336 RdLow
, RdHi
, Rm
, Rs
);
1340 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1342 uint8_t Rd
, Rm
, Rs
, Rn
;
1343 instruction
->type
= ARM_SMLAWy
;
1344 Rd
= (opcode
& 0xf0000) >> 16;
1345 Rm
= (opcode
& 0xf);
1346 Rs
= (opcode
& 0xf00) >> 8;
1347 Rn
= (opcode
& 0xf000) >> 12;
1349 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1350 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1355 if ((opcode
& 0x00600000) == 0x00300000)
1358 instruction
->type
= ARM_SMULxy
;
1359 Rd
= (opcode
& 0xf0000) >> 16;
1360 Rm
= (opcode
& 0xf);
1361 Rs
= (opcode
& 0xf00) >> 8;
1363 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1364 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1369 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1372 instruction
->type
= ARM_SMULWy
;
1373 Rd
= (opcode
& 0xf0000) >> 16;
1374 Rm
= (opcode
& 0xf);
1375 Rs
= (opcode
& 0xf00) >> 8;
1377 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1378 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1386 static int evaluate_data_proc(uint32_t opcode
,
1387 uint32_t address
, struct arm_instruction
*instruction
)
1389 uint8_t I
, op
, S
, Rn
, Rd
;
1390 char *mnemonic
= NULL
;
1391 char shifter_operand
[32];
1393 I
= (opcode
& 0x02000000) >> 25;
1394 op
= (opcode
& 0x01e00000) >> 21;
1395 S
= (opcode
& 0x00100000) >> 20;
1397 Rd
= (opcode
& 0xf000) >> 12;
1398 Rn
= (opcode
& 0xf0000) >> 16;
1400 instruction
->info
.data_proc
.Rd
= Rd
;
1401 instruction
->info
.data_proc
.Rn
= Rn
;
1402 instruction
->info
.data_proc
.S
= S
;
1407 instruction
->type
= ARM_AND
;
1411 instruction
->type
= ARM_EOR
;
1415 instruction
->type
= ARM_SUB
;
1419 instruction
->type
= ARM_RSB
;
1423 instruction
->type
= ARM_ADD
;
1427 instruction
->type
= ARM_ADC
;
1431 instruction
->type
= ARM_SBC
;
1435 instruction
->type
= ARM_RSC
;
1439 instruction
->type
= ARM_TST
;
1443 instruction
->type
= ARM_TEQ
;
1447 instruction
->type
= ARM_CMP
;
1451 instruction
->type
= ARM_CMN
;
1455 instruction
->type
= ARM_ORR
;
1459 instruction
->type
= ARM_MOV
;
1463 instruction
->type
= ARM_BIC
;
1467 instruction
->type
= ARM_MVN
;
1472 if (I
) /* immediate shifter operand (#<immediate>)*/
1474 uint8_t immed_8
= opcode
& 0xff;
1475 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1478 immediate
= ror(immed_8
, rotate_imm
* 2);
1480 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1482 instruction
->info
.data_proc
.variant
= 0;
1483 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1485 else /* register-based shifter operand */
1488 shift
= (opcode
& 0x60) >> 5;
1489 Rm
= (opcode
& 0xf);
1491 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1494 shift_imm
= (opcode
& 0xf80) >> 7;
1496 instruction
->info
.data_proc
.variant
= 1;
1497 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1498 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1499 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1501 /* LSR encodes a shift by 32 bit as 0x0 */
1502 if ((shift
== 0x1) && (shift_imm
== 0x0))
1505 /* ASR encodes a shift by 32 bit as 0x0 */
1506 if ((shift
== 0x2) && (shift_imm
== 0x0))
1509 /* ROR by 32 bit is actually a RRX */
1510 if ((shift
== 0x3) && (shift_imm
== 0x0))
1513 if ((shift_imm
== 0x0) && (shift
== 0x0))
1515 snprintf(shifter_operand
, 32, "r%i", Rm
);
1519 if (shift
== 0x0) /* LSL */
1521 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1523 else if (shift
== 0x1) /* LSR */
1525 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1527 else if (shift
== 0x2) /* ASR */
1529 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1531 else if (shift
== 0x3) /* ROR */
1533 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1535 else if (shift
== 0x4) /* RRX */
1537 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1541 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1543 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1545 instruction
->info
.data_proc
.variant
= 2;
1546 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1547 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1548 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1550 if (shift
== 0x0) /* LSL */
1552 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1554 else if (shift
== 0x1) /* LSR */
1556 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1558 else if (shift
== 0x2) /* ASR */
1560 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1562 else if (shift
== 0x3) /* ROR */
1564 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1569 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1571 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1572 address
, opcode
, mnemonic
, COND(opcode
),
1573 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1575 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1577 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1578 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1580 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1581 address
, opcode
, mnemonic
, COND(opcode
),
1582 (S
) ? "S" : "", Rd
, shifter_operand
);
1584 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1586 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1587 address
, opcode
, mnemonic
, COND(opcode
),
1588 Rn
, shifter_operand
);
1594 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
1596 /* clear fields, to avoid confusion */
1597 memset(instruction
, 0, sizeof(struct arm_instruction
));
1598 instruction
->opcode
= opcode
;
1599 instruction
->instruction_size
= 4;
1601 /* catch opcodes with condition field [31:28] = b1111 */
1602 if ((opcode
& 0xf0000000) == 0xf0000000)
1604 /* Undefined instruction (or ARMv5E cache preload PLD) */
1605 if ((opcode
& 0x08000000) == 0x00000000)
1606 return evaluate_pld(opcode
, address
, instruction
);
1608 /* Undefined instruction */
1609 if ((opcode
& 0x0e000000) == 0x08000000)
1611 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1612 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1616 /* Branch and branch with link and change to Thumb */
1617 if ((opcode
& 0x0e000000) == 0x0a000000)
1618 return evaluate_blx_imm(opcode
, address
, instruction
);
1620 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1621 /* Coprocessor load/store and double register transfers */
1622 if ((opcode
& 0x0e000000) == 0x0c000000)
1623 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1625 /* Coprocessor data processing */
1626 if ((opcode
& 0x0f000100) == 0x0c000000)
1627 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1629 /* Coprocessor register transfers */
1630 if ((opcode
& 0x0f000010) == 0x0c000010)
1631 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1633 /* Undefined instruction */
1634 if ((opcode
& 0x0f000000) == 0x0f000000)
1636 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1637 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1642 /* catch opcodes with [27:25] = b000 */
1643 if ((opcode
& 0x0e000000) == 0x00000000)
1645 /* Multiplies, extra load/stores */
1646 if ((opcode
& 0x00000090) == 0x00000090)
1647 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1649 /* Miscellaneous instructions */
1650 if ((opcode
& 0x0f900000) == 0x01000000)
1651 return evaluate_misc_instr(opcode
, address
, instruction
);
1653 return evaluate_data_proc(opcode
, address
, instruction
);
1656 /* catch opcodes with [27:25] = b001 */
1657 if ((opcode
& 0x0e000000) == 0x02000000)
1659 /* Undefined instruction */
1660 if ((opcode
& 0x0fb00000) == 0x03000000)
1662 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1663 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1667 /* Move immediate to status register */
1668 if ((opcode
& 0x0fb00000) == 0x03200000)
1669 return evaluate_mrs_msr(opcode
, address
, instruction
);
1671 return evaluate_data_proc(opcode
, address
, instruction
);
1675 /* catch opcodes with [27:25] = b010 */
1676 if ((opcode
& 0x0e000000) == 0x04000000)
1678 /* Load/store immediate offset */
1679 return evaluate_load_store(opcode
, address
, instruction
);
1682 /* catch opcodes with [27:25] = b011 */
1683 if ((opcode
& 0x0e000000) == 0x06000000)
1685 /* Load/store register offset */
1686 if ((opcode
& 0x00000010) == 0x00000000)
1687 return evaluate_load_store(opcode
, address
, instruction
);
1689 /* Architecturally Undefined instruction
1690 * ... don't expect these to ever be used
1692 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1694 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1695 snprintf(instruction
->text
, 128,
1696 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1701 /* "media" instructions */
1702 return evaluate_media(opcode
, address
, instruction
);
1705 /* catch opcodes with [27:25] = b100 */
1706 if ((opcode
& 0x0e000000) == 0x08000000)
1708 /* Load/store multiple */
1709 return evaluate_ldm_stm(opcode
, address
, instruction
);
1712 /* catch opcodes with [27:25] = b101 */
1713 if ((opcode
& 0x0e000000) == 0x0a000000)
1715 /* Branch and branch with link */
1716 return evaluate_b_bl(opcode
, address
, instruction
);
1719 /* catch opcodes with [27:25] = b110 */
1720 if ((opcode
& 0x0e000000) == 0x0a000000)
1722 /* Coprocessor load/store and double register transfers */
1723 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1726 /* catch opcodes with [27:25] = b111 */
1727 if ((opcode
& 0x0e000000) == 0x0e000000)
1729 /* Software interrupt */
1730 if ((opcode
& 0x0f000000) == 0x0f000000)
1731 return evaluate_swi(opcode
, address
, instruction
);
1733 /* Coprocessor data processing */
1734 if ((opcode
& 0x0f000010) == 0x0e000000)
1735 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1737 /* Coprocessor register transfers */
1738 if ((opcode
& 0x0f000010) == 0x0e000010)
1739 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1742 LOG_ERROR("should never reach this point");
1746 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1747 uint32_t address
, struct arm_instruction
*instruction
)
1749 uint32_t offset
= opcode
& 0x7ff;
1750 uint32_t opc
= (opcode
>> 11) & 0x3;
1751 uint32_t target_address
;
1752 char *mnemonic
= NULL
;
1754 /* sign extend 11-bit offset */
1755 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1756 offset
= 0xfffff800 | offset
;
1758 target_address
= address
+ 4 + (offset
<< 1);
1762 /* unconditional branch */
1764 instruction
->type
= ARM_B
;
1769 instruction
->type
= ARM_BLX
;
1771 target_address
&= 0xfffffffc;
1775 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1776 mnemonic
= "prefix";
1777 target_address
= offset
<< 12;
1781 instruction
->type
= ARM_BL
;
1786 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1787 * these are effectively 32-bit instructions even in Thumb1. For
1788 * disassembly, it's simplest to always use the Thumb2 decoder.
1790 * But some cores will evidently handle them as two instructions,
1791 * where exceptions may occur between the two. The ETMv3.2+ ID
1792 * register has a bit which exposes this behavior.
1795 snprintf(instruction
->text
, 128,
1796 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1797 address
, opcode
, mnemonic
, target_address
);
1799 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1800 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1805 static int evaluate_add_sub_thumb(uint16_t opcode
,
1806 uint32_t address
, struct arm_instruction
*instruction
)
1808 uint8_t Rd
= (opcode
>> 0) & 0x7;
1809 uint8_t Rn
= (opcode
>> 3) & 0x7;
1810 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1811 uint32_t opc
= opcode
& (1 << 9);
1812 uint32_t reg_imm
= opcode
& (1 << 10);
1817 instruction
->type
= ARM_SUB
;
1822 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1823 instruction
->type
= ARM_ADD
;
1827 instruction
->info
.data_proc
.Rd
= Rd
;
1828 instruction
->info
.data_proc
.Rn
= Rn
;
1829 instruction
->info
.data_proc
.S
= 1;
1833 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1834 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1835 snprintf(instruction
->text
, 128,
1836 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1837 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1841 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1842 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1843 snprintf(instruction
->text
, 128,
1844 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1845 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1851 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1852 uint32_t address
, struct arm_instruction
*instruction
)
1854 uint8_t Rd
= (opcode
>> 0) & 0x7;
1855 uint8_t Rm
= (opcode
>> 3) & 0x7;
1856 uint8_t imm
= (opcode
>> 6) & 0x1f;
1857 uint8_t opc
= (opcode
>> 11) & 0x3;
1858 char *mnemonic
= NULL
;
1863 instruction
->type
= ARM_MOV
;
1865 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1868 instruction
->type
= ARM_MOV
;
1870 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1873 instruction
->type
= ARM_MOV
;
1875 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1879 if ((imm
== 0) && (opc
!= 0))
1882 instruction
->info
.data_proc
.Rd
= Rd
;
1883 instruction
->info
.data_proc
.Rn
= -1;
1884 instruction
->info
.data_proc
.S
= 1;
1886 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1887 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1888 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1890 snprintf(instruction
->text
, 128,
1891 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1892 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1897 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1898 uint32_t address
, struct arm_instruction
*instruction
)
1900 uint8_t imm
= opcode
& 0xff;
1901 uint8_t Rd
= (opcode
>> 8) & 0x7;
1902 uint32_t opc
= (opcode
>> 11) & 0x3;
1903 char *mnemonic
= NULL
;
1905 instruction
->info
.data_proc
.Rd
= Rd
;
1906 instruction
->info
.data_proc
.Rn
= Rd
;
1907 instruction
->info
.data_proc
.S
= 1;
1908 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1909 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1914 instruction
->type
= ARM_MOV
;
1916 instruction
->info
.data_proc
.Rn
= -1;
1919 instruction
->type
= ARM_CMP
;
1921 instruction
->info
.data_proc
.Rd
= -1;
1924 instruction
->type
= ARM_ADD
;
1928 instruction
->type
= ARM_SUB
;
1933 snprintf(instruction
->text
, 128,
1934 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1935 address
, opcode
, mnemonic
, Rd
, imm
);
1940 static int evaluate_data_proc_thumb(uint16_t opcode
,
1941 uint32_t address
, struct arm_instruction
*instruction
)
1943 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1944 char *mnemonic
= NULL
;
1947 high_reg
= (opcode
& 0x0400) >> 10;
1948 op
= (opcode
& 0x03C0) >> 6;
1950 Rd
= (opcode
& 0x0007);
1951 Rm
= (opcode
& 0x0038) >> 3;
1952 H1
= (opcode
& 0x0080) >> 7;
1953 H2
= (opcode
& 0x0040) >> 6;
1955 instruction
->info
.data_proc
.Rd
= Rd
;
1956 instruction
->info
.data_proc
.Rn
= Rd
;
1957 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1958 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1959 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1970 instruction
->type
= ARM_ADD
;
1974 instruction
->type
= ARM_CMP
;
1978 instruction
->type
= ARM_MOV
;
1984 if ((opcode
& 0x7) == 0x0)
1986 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1989 instruction
->type
= ARM_BLX
;
1990 snprintf(instruction
->text
, 128,
1992 " 0x%4.4x \tBLX\tr%i",
1993 address
, opcode
, Rm
);
1997 instruction
->type
= ARM_BX
;
1998 snprintf(instruction
->text
, 128,
2000 " 0x%4.4x \tBX\tr%i",
2001 address
, opcode
, Rm
);
2006 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2007 snprintf(instruction
->text
, 128,
2010 "UNDEFINED INSTRUCTION",
2022 instruction
->type
= ARM_AND
;
2026 instruction
->type
= ARM_EOR
;
2030 instruction
->type
= ARM_MOV
;
2032 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2033 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2034 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2035 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2038 instruction
->type
= ARM_MOV
;
2040 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2041 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2042 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2043 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2046 instruction
->type
= ARM_MOV
;
2048 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2049 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2050 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2051 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2054 instruction
->type
= ARM_ADC
;
2058 instruction
->type
= ARM_SBC
;
2062 instruction
->type
= ARM_MOV
;
2064 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2065 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2066 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2067 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2070 instruction
->type
= ARM_TST
;
2074 instruction
->type
= ARM_RSB
;
2076 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2077 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2078 instruction
->info
.data_proc
.Rn
= Rm
;
2081 instruction
->type
= ARM_CMP
;
2085 instruction
->type
= ARM_CMN
;
2089 instruction
->type
= ARM_ORR
;
2093 instruction
->type
= ARM_MUL
;
2097 instruction
->type
= ARM_BIC
;
2101 instruction
->type
= ARM_MVN
;
2108 snprintf(instruction
->text
, 128,
2109 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2111 address
, opcode
, mnemonic
, Rd
, Rm
);
2113 snprintf(instruction
->text
, 128,
2114 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2115 address
, opcode
, mnemonic
, Rd
, Rm
);
2120 /* PC-relative data addressing is word-aligned even with Thumb */
2121 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2123 return (addr
+ 4) & ~3;
2126 static int evaluate_load_literal_thumb(uint16_t opcode
,
2127 uint32_t address
, struct arm_instruction
*instruction
)
2130 uint8_t Rd
= (opcode
>> 8) & 0x7;
2132 instruction
->type
= ARM_LDR
;
2133 immediate
= opcode
& 0x000000ff;
2136 instruction
->info
.load_store
.Rd
= Rd
;
2137 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2138 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2139 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2140 instruction
->info
.load_store
.offset
.offset
= immediate
;
2142 snprintf(instruction
->text
, 128,
2143 "0x%8.8" PRIx32
" 0x%4.4x \t"
2144 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2145 address
, opcode
, Rd
, immediate
,
2146 thumb_alignpc4(address
) + immediate
);
2151 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2152 uint32_t address
, struct arm_instruction
*instruction
)
2154 uint8_t Rd
= (opcode
>> 0) & 0x7;
2155 uint8_t Rn
= (opcode
>> 3) & 0x7;
2156 uint8_t Rm
= (opcode
>> 6) & 0x7;
2157 uint8_t opc
= (opcode
>> 9) & 0x7;
2158 char *mnemonic
= NULL
;
2163 instruction
->type
= ARM_STR
;
2167 instruction
->type
= ARM_STRH
;
2171 instruction
->type
= ARM_STRB
;
2175 instruction
->type
= ARM_LDRSB
;
2179 instruction
->type
= ARM_LDR
;
2183 instruction
->type
= ARM_LDRH
;
2187 instruction
->type
= ARM_LDRB
;
2191 instruction
->type
= ARM_LDRSH
;
2196 snprintf(instruction
->text
, 128,
2197 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2198 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2200 instruction
->info
.load_store
.Rd
= Rd
;
2201 instruction
->info
.load_store
.Rn
= Rn
;
2202 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2203 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2204 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2209 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2210 uint32_t address
, struct arm_instruction
*instruction
)
2212 uint32_t offset
= (opcode
>> 6) & 0x1f;
2213 uint8_t Rd
= (opcode
>> 0) & 0x7;
2214 uint8_t Rn
= (opcode
>> 3) & 0x7;
2215 uint32_t L
= opcode
& (1 << 11);
2216 uint32_t B
= opcode
& (1 << 12);
2223 instruction
->type
= ARM_LDR
;
2228 instruction
->type
= ARM_STR
;
2232 if ((opcode
&0xF000) == 0x8000)
2243 snprintf(instruction
->text
, 128,
2244 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2245 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2247 instruction
->info
.load_store
.Rd
= Rd
;
2248 instruction
->info
.load_store
.Rn
= Rn
;
2249 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2250 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2251 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2256 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2257 uint32_t address
, struct arm_instruction
*instruction
)
2259 uint32_t offset
= opcode
& 0xff;
2260 uint8_t Rd
= (opcode
>> 8) & 0x7;
2261 uint32_t L
= opcode
& (1 << 11);
2266 instruction
->type
= ARM_LDR
;
2271 instruction
->type
= ARM_STR
;
2275 snprintf(instruction
->text
, 128,
2276 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2277 address
, opcode
, mnemonic
, Rd
, offset
*4);
2279 instruction
->info
.load_store
.Rd
= Rd
;
2280 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2281 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2282 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2283 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2288 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2289 uint32_t address
, struct arm_instruction
*instruction
)
2291 uint32_t imm
= opcode
& 0xff;
2292 uint8_t Rd
= (opcode
>> 8) & 0x7;
2294 uint32_t SP
= opcode
& (1 << 11);
2297 instruction
->type
= ARM_ADD
;
2310 snprintf(instruction
->text
, 128,
2311 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2312 address
, opcode
, Rd
, reg_name
, imm
* 4);
2314 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2315 instruction
->info
.data_proc
.Rd
= Rd
;
2316 instruction
->info
.data_proc
.Rn
= Rn
;
2317 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2322 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2323 uint32_t address
, struct arm_instruction
*instruction
)
2325 uint32_t imm
= opcode
& 0x7f;
2326 uint8_t opc
= opcode
& (1 << 7);
2332 instruction
->type
= ARM_SUB
;
2337 instruction
->type
= ARM_ADD
;
2341 snprintf(instruction
->text
, 128,
2342 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2343 address
, opcode
, mnemonic
, imm
*4);
2345 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2346 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2347 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2348 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2353 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2354 uint32_t address
, struct arm_instruction
*instruction
)
2356 uint32_t imm
= opcode
& 0xff;
2358 instruction
->type
= ARM_BKPT
;
2360 snprintf(instruction
->text
, 128,
2361 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2362 address
, opcode
, imm
);
2367 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2368 uint32_t address
, struct arm_instruction
*instruction
)
2370 uint32_t reg_list
= opcode
& 0xff;
2371 uint32_t L
= opcode
& (1 << 11);
2372 uint32_t R
= opcode
& (1 << 8);
2373 uint8_t Rn
= (opcode
>> 8) & 7;
2374 uint8_t addr_mode
= 0 /* IA */;
2378 char ptr_name
[7] = "";
2381 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2382 * The STMIA and LDMIA opcodes are used for other instructions.
2385 if ((opcode
& 0xf000) == 0xc000)
2386 { /* generic load/store multiple */
2391 instruction
->type
= ARM_LDM
;
2393 if (opcode
& (1 << Rn
))
2398 instruction
->type
= ARM_STM
;
2401 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2408 instruction
->type
= ARM_LDM
;
2411 reg_list
|= (1 << 15) /*PC*/;
2415 instruction
->type
= ARM_STM
;
2417 addr_mode
= 3; /*DB*/
2419 reg_list
|= (1 << 14) /*LR*/;
2423 reg_names_p
= reg_names
;
2424 for (i
= 0; i
<= 15; i
++)
2426 if (reg_list
& (1 << i
))
2427 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2429 if (reg_names_p
> reg_names
)
2430 reg_names_p
[-2] = '\0';
2431 else /* invalid op : no registers */
2432 reg_names
[0] = '\0';
2434 snprintf(instruction
->text
, 128,
2435 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2436 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2438 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2439 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2440 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2445 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2446 uint32_t address
, struct arm_instruction
*instruction
)
2448 uint32_t offset
= opcode
& 0xff;
2449 uint8_t cond
= (opcode
>> 8) & 0xf;
2450 uint32_t target_address
;
2454 instruction
->type
= ARM_SWI
;
2455 snprintf(instruction
->text
, 128,
2456 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2457 address
, opcode
, offset
);
2460 else if (cond
== 0xe)
2462 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2463 snprintf(instruction
->text
, 128,
2464 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2469 /* sign extend 8-bit offset */
2470 if (offset
& 0x00000080)
2471 offset
= 0xffffff00 | offset
;
2473 target_address
= address
+ 4 + (offset
<< 1);
2475 snprintf(instruction
->text
, 128,
2476 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2478 arm_condition_strings
[cond
], target_address
);
2480 instruction
->type
= ARM_B
;
2481 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2482 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2487 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2488 struct arm_instruction
*instruction
)
2492 /* added in Thumb2 */
2493 offset
= (opcode
>> 3) & 0x1f;
2494 offset
|= (opcode
& 0x0200) >> 4;
2496 snprintf(instruction
->text
, 128,
2497 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2499 (opcode
& 0x0800) ? "N" : "",
2500 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2505 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2506 struct arm_instruction
*instruction
)
2508 /* added in ARMv6 */
2509 snprintf(instruction
->text
, 128,
2510 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2512 (opcode
& 0x0080) ? 'U' : 'S',
2513 (opcode
& 0x0040) ? 'B' : 'H',
2514 opcode
& 0x7, (opcode
>> 3) & 0x7);
2519 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2520 struct arm_instruction
*instruction
)
2522 /* added in ARMv6 */
2523 if ((opcode
& 0x0ff0) == 0x0650)
2524 snprintf(instruction
->text
, 128,
2525 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2527 (opcode
& 0x80) ? "BE" : "LE");
2528 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2529 snprintf(instruction
->text
, 128,
2530 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2532 (opcode
& 0x0010) ? 'D' : 'E',
2533 (opcode
& 0x0004) ? "A" : "",
2534 (opcode
& 0x0002) ? "I" : "",
2535 (opcode
& 0x0001) ? "F" : "");
2540 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2541 struct arm_instruction
*instruction
)
2545 /* added in ARMv6 */
2546 switch ((opcode
>> 6) & 3) {
2557 snprintf(instruction
->text
, 128,
2558 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2559 address
, opcode
, suffix
,
2560 opcode
& 0x7, (opcode
>> 3) & 0x7);
2565 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2566 struct arm_instruction
*instruction
)
2570 switch ((opcode
>> 4) & 0x0f) {
2587 hint
= "HINT (UNRECOGNIZED)";
2591 snprintf(instruction
->text
, 128,
2592 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2593 address
, opcode
, hint
);
2598 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2599 struct arm_instruction
*instruction
)
2601 unsigned cond
= (opcode
>> 4) & 0x0f;
2602 char *x
= "", *y
= "", *z
= "";
2605 z
= (opcode
& 0x02) ? "T" : "E";
2607 y
= (opcode
& 0x04) ? "T" : "E";
2609 x
= (opcode
& 0x08) ? "T" : "E";
2611 snprintf(instruction
->text
, 128,
2612 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2614 x
, y
, z
, arm_condition_strings
[cond
]);
2616 /* NOTE: strictly speaking, the next 1-4 instructions should
2617 * now be displayed with the relevant conditional suffix...
2623 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2625 /* clear fields, to avoid confusion */
2626 memset(instruction
, 0, sizeof(struct arm_instruction
));
2627 instruction
->opcode
= opcode
;
2628 instruction
->instruction_size
= 2;
2630 if ((opcode
& 0xe000) == 0x0000)
2632 /* add/substract register or immediate */
2633 if ((opcode
& 0x1800) == 0x1800)
2634 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2635 /* shift by immediate */
2637 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2640 /* Add/substract/compare/move immediate */
2641 if ((opcode
& 0xe000) == 0x2000)
2643 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2646 /* Data processing instructions */
2647 if ((opcode
& 0xf800) == 0x4000)
2649 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2652 /* Load from literal pool */
2653 if ((opcode
& 0xf800) == 0x4800)
2655 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2658 /* Load/Store register offset */
2659 if ((opcode
& 0xf000) == 0x5000)
2661 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2664 /* Load/Store immediate offset */
2665 if (((opcode
& 0xe000) == 0x6000)
2666 ||((opcode
& 0xf000) == 0x8000))
2668 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2671 /* Load/Store from/to stack */
2672 if ((opcode
& 0xf000) == 0x9000)
2674 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2678 if ((opcode
& 0xf000) == 0xa000)
2680 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2684 if ((opcode
& 0xf000) == 0xb000)
2686 switch ((opcode
>> 8) & 0x0f) {
2688 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2693 return evaluate_cb_thumb(opcode
, address
, instruction
);
2695 return evaluate_extend_thumb(opcode
, address
, instruction
);
2700 return evaluate_load_store_multiple_thumb(opcode
, address
,
2703 return evaluate_cps_thumb(opcode
, address
, instruction
);
2705 if ((opcode
& 0x00c0) == 0x0080)
2707 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2709 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2711 if (opcode
& 0x000f)
2712 return evaluate_ifthen_thumb(opcode
, address
,
2715 return evaluate_hint_thumb(opcode
, address
,
2719 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2720 snprintf(instruction
->text
, 128,
2721 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2726 /* Load/Store multiple */
2727 if ((opcode
& 0xf000) == 0xc000)
2729 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2732 /* Conditional branch + SWI */
2733 if ((opcode
& 0xf000) == 0xd000)
2735 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2738 if ((opcode
& 0xe000) == 0xe000)
2740 /* Undefined instructions */
2741 if ((opcode
& 0xf801) == 0xe801)
2743 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2744 snprintf(instruction
->text
, 128,
2745 "0x%8.8" PRIx32
" 0x%8.8x\t"
2746 "UNDEFINED INSTRUCTION",
2751 { /* Branch to offset */
2752 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2756 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2760 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2761 struct arm_instruction
*instruction
, char *cp
)
2764 unsigned b21
= 1 << 21;
2765 unsigned b22
= 1 << 22;
2767 /* instead of combining two smaller 16-bit branch instructions,
2768 * Thumb2 uses only one larger 32-bit instruction.
2770 offset
= opcode
& 0x7ff;
2771 offset
|= (opcode
& 0x03ff0000) >> 5;
2772 if (opcode
& (1 << 26)) {
2773 offset
|= 0xff << 23;
2774 if ((opcode
& (1 << 11)) == 0)
2776 if ((opcode
& (1 << 13)) == 0)
2779 if (opcode
& (1 << 11))
2781 if (opcode
& (1 << 13))
2789 address
+= offset
<< 1;
2791 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2792 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2793 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2794 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2795 (opcode
& (1 << 14)) ? "BL" : "B.W",
2801 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2802 struct arm_instruction
*instruction
, char *cp
)
2805 unsigned b17
= 1 << 17;
2806 unsigned b18
= 1 << 18;
2807 unsigned cond
= (opcode
>> 22) & 0x0f;
2809 offset
= opcode
& 0x7ff;
2810 offset
|= (opcode
& 0x003f0000) >> 5;
2811 if (opcode
& (1 << 26)) {
2812 offset
|= 0xffff << 19;
2813 if ((opcode
& (1 << 11)) == 0)
2815 if ((opcode
& (1 << 13)) == 0)
2818 if (opcode
& (1 << 11))
2820 if (opcode
& (1 << 13))
2827 address
+= offset
<< 1;
2829 instruction
->type
= ARM_B
;
2830 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2831 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2832 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2833 arm_condition_strings
[cond
],
2839 static const char *special_name(int number
)
2841 char *special
= "(RESERVED)";
2872 special
= "primask";
2875 special
= "basepri";
2878 special
= "basepri_max";
2881 special
= "faultmask";
2884 special
= "control";
2890 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2891 struct arm_instruction
*instruction
, char *cp
)
2893 const char *mnemonic
;
2895 if (opcode
& 0x0700) {
2896 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2897 strcpy(cp
, "UNDEFINED");
2901 if (opcode
& 0x00f0) {
2902 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2906 switch (opcode
& 0x0f) {
2911 mnemonic
= "YIELD.W";
2923 mnemonic
= "HINT.W (UNRECOGNIZED)";
2926 strcpy(cp
, mnemonic
);
2930 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2931 struct arm_instruction
*instruction
, char *cp
)
2933 const char *mnemonic
;
2935 switch ((opcode
>> 4) & 0x0f) {
2937 mnemonic
= "LEAVEX";
2940 mnemonic
= "ENTERX";
2955 return ERROR_INVALID_ARGUMENTS
;
2957 strcpy(cp
, mnemonic
);
2961 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2962 struct arm_instruction
*instruction
, char *cp
)
2964 /* permanently undefined */
2965 if ((opcode
& 0x07f07000) == 0x07f02000) {
2966 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2967 strcpy(cp
, "UNDEFINED");
2971 switch ((opcode
>> 12) & 0x5) {
2974 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2978 if (((opcode
>> 23) & 0x07) != 0x07)
2979 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2980 if (opcode
& (1 << 26))
2985 switch ((opcode
>> 20) & 0x7f) {
2988 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2989 (int) (opcode
>> 16) & 0x0f);
2992 return t2ev_hint(opcode
, address
, instruction
, cp
);
2994 return t2ev_misc(opcode
, address
, instruction
, cp
);
2996 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3000 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3001 special_name(opcode
& 0xff));
3006 return ERROR_INVALID_ARGUMENTS
;
3009 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3010 struct arm_instruction
*instruction
, char *cp
)
3012 char *mnemonic
= NULL
;
3013 int rn
= (opcode
>> 16) & 0xf;
3014 int rd
= (opcode
>> 8) & 0xf;
3015 unsigned immed
= opcode
& 0xff;
3021 /* ARMv7-M: A5.3.2 Modified immediate constants */
3022 func
= (opcode
>> 11) & 0x0e;
3025 if (opcode
& (1 << 26))
3028 /* "Modified" immediates */
3029 switch (func
>> 1) {
3036 immed
+= immed
<< 16;
3039 immed
+= immed
<< 8;
3040 immed
+= immed
<< 16;
3044 immed
= ror(immed
, func
);
3047 if (opcode
& (1 << 20))
3050 switch ((opcode
>> 21) & 0xf) {
3053 instruction
->type
= ARM_TST
;
3059 instruction
->type
= ARM_AND
;
3064 instruction
->type
= ARM_BIC
;
3069 instruction
->type
= ARM_MOV
;
3074 instruction
->type
= ARM_ORR
;
3080 instruction
->type
= ARM_MVN
;
3084 // instruction->type = ARM_ORN;
3090 instruction
->type
= ARM_TEQ
;
3096 instruction
->type
= ARM_EOR
;
3102 instruction
->type
= ARM_CMN
;
3108 instruction
->type
= ARM_ADD
;
3114 instruction
->type
= ARM_ADC
;
3119 instruction
->type
= ARM_SBC
;
3124 instruction
->type
= ARM_CMP
;
3130 instruction
->type
= ARM_SUB
;
3136 instruction
->type
= ARM_RSB
;
3141 return ERROR_INVALID_ARGUMENTS
;
3145 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3146 mnemonic
, suffix2
,rd
, immed
, immed
);
3148 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3149 mnemonic
, suffix
, suffix2
,
3150 rd
, rn
, immed
, immed
);
3155 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3156 struct arm_instruction
*instruction
, char *cp
)
3158 char *mnemonic
= NULL
;
3159 int rn
= (opcode
>> 16) & 0xf;
3160 int rd
= (opcode
>> 8) & 0xf;
3163 bool is_signed
= false;
3165 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3166 if (opcode
& (1 << 26))
3169 switch ((opcode
>> 20) & 0x1f) {
3178 immed
|= (opcode
>> 4) & 0xf000;
3179 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3187 /* move constant to top 16 bits of register */
3188 immed
|= (opcode
>> 4) & 0xf000;
3189 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3196 /* signed/unsigned saturated add */
3197 immed
= (opcode
>> 6) & 0x03;
3198 immed
|= (opcode
>> 10) & 0x1c;
3199 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3200 is_signed
? "S" : "U",
3201 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3202 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3203 immed
? immed
: 32);
3209 /* signed/unsigned bitfield extract */
3210 immed
= (opcode
>> 6) & 0x03;
3211 immed
|= (opcode
>> 10) & 0x1c;
3212 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3213 is_signed
? "S" : "U",
3215 (int) (opcode
& 0x1f) + 1);
3218 immed
= (opcode
>> 6) & 0x03;
3219 immed
|= (opcode
>> 10) & 0x1c;
3220 if (rn
== 0xf) /* bitfield clear */
3221 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3223 (int) (opcode
& 0x1f) + 1 - immed
);
3224 else /* bitfield insert */
3225 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3227 (int) (opcode
& 0x1f) + 1 - immed
);
3230 return ERROR_INVALID_ARGUMENTS
;
3233 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3234 rd
, rn
, immed
, immed
);
3238 address
= thumb_alignpc4(address
);
3243 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3244 * not hiding the pc-relative stuff will sometimes be useful.
3246 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3250 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3251 struct arm_instruction
*instruction
, char *cp
)
3253 unsigned op
= (opcode
>> 20) & 0xf;
3259 unsigned rn
= (opcode
>> 16) & 0x0f;
3260 unsigned rt
= (opcode
>> 12) & 0x0f;
3263 return ERROR_INVALID_ARGUMENTS
;
3265 if (opcode
& 0x0800)
3300 return ERROR_INVALID_ARGUMENTS
;
3303 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3304 size
, rt
, rn
, (int) opcode
& 0x0f,
3305 (int) (opcode
>> 4) & 0x03);
3309 immed
= opcode
& 0x0fff;
3310 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3311 size
, rt
, rn
, immed
, immed
);
3315 immed
= opcode
& 0x00ff;
3317 switch (opcode
& 0x700) {
3323 return ERROR_INVALID_ARGUMENTS
;
3326 /* two indexed modes will write back rn */
3327 if (opcode
& 0x100) {
3328 if (opcode
& 0x400) /* pre-indexed */
3330 else { /* post-indexed */
3336 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3337 size
, suffix
, rt
, rn
, p1
,
3338 (opcode
& 0x200) ? "" : "-",
3343 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3344 struct arm_instruction
*instruction
, char *cp
)
3346 int ra
= (opcode
>> 12) & 0xf;
3348 switch (opcode
& 0x007000f0) {
3351 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3352 (int) (opcode
>> 8) & 0xf,
3353 (int) (opcode
>> 16) & 0xf,
3354 (int) (opcode
>> 0) & 0xf);
3356 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3357 (int) (opcode
>> 8) & 0xf,
3358 (int) (opcode
>> 16) & 0xf,
3359 (int) (opcode
>> 0) & 0xf, ra
);
3362 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3363 (int) (opcode
>> 8) & 0xf,
3364 (int) (opcode
>> 16) & 0xf,
3365 (int) (opcode
>> 0) & 0xf, ra
);
3368 return ERROR_INVALID_ARGUMENTS
;
3373 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3374 struct arm_instruction
*instruction
, char *cp
)
3376 int op
= (opcode
>> 4) & 0xf;
3377 char *infix
= "MUL";
3379 op
+= (opcode
>> 16) & 0x70;
3387 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3388 (op
& 0x20) ? 'U' : 'S',
3390 (int) (opcode
>> 12) & 0xf,
3391 (int) (opcode
>> 8) & 0xf,
3392 (int) (opcode
>> 16) & 0xf,
3393 (int) (opcode
>> 0) & 0xf);
3397 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3398 (op
& 0x20) ? 'U' : 'S',
3399 (int) (opcode
>> 8) & 0xf,
3400 (int) (opcode
>> 16) & 0xf,
3401 (int) (opcode
>> 0) & 0xf);
3404 return ERROR_INVALID_ARGUMENTS
;
3410 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3411 struct arm_instruction
*instruction
, char *cp
)
3413 int rn
= (opcode
>> 16) & 0xf;
3414 int op
= (opcode
>> 22) & 0x6;
3415 int t
= (opcode
>> 21) & 1;
3416 unsigned registers
= opcode
& 0xffff;
3418 if (opcode
& (1 << 20))
3423 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3427 sprintf(cp
, "POP.W\t");
3429 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3433 sprintf(cp
, "PUSH.W\t");
3435 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3438 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3441 return ERROR_INVALID_ARGUMENTS
;
3446 for (t
= 0; registers
; t
++, registers
>>= 1) {
3447 if ((registers
& 1) == 0)
3450 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3459 /* load/store dual or exclusive, table branch */
3460 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3461 struct arm_instruction
*instruction
, char *cp
)
3463 unsigned op1op2
= (opcode
>> 20) & 0x3;
3464 unsigned op3
= (opcode
>> 4) & 0xf;
3466 unsigned rn
= (opcode
>> 16) & 0xf;
3467 unsigned rt
= (opcode
>> 12) & 0xf;
3468 unsigned rd
= (opcode
>> 8) & 0xf;
3469 unsigned imm
= opcode
& 0xff;
3473 op1op2
|= (opcode
>> 21) & 0xc;
3503 mnemonic
= "STREXB";
3506 mnemonic
= "STREXH";
3509 return ERROR_INVALID_ARGUMENTS
;
3517 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3520 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3523 mnemonic
= "LDREXB";
3526 mnemonic
= "LDREXH";
3529 return ERROR_INVALID_ARGUMENTS
;
3534 return ERROR_INVALID_ARGUMENTS
;
3539 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3540 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3542 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3543 mnemonic
, rd
, rt
, rn
);
3549 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3550 mnemonic
, rt
, rn
, imm
, imm
);
3552 sprintf(cp
, "%s\tr%u, [r%u]",
3557 /* two indexed modes will write back rn */
3558 if (opcode
& (1 << 21)) {
3559 if (opcode
& (1 << 24)) /* pre-indexed */
3561 else { /* post-indexed */
3568 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3569 mnemonic
, rt
, rd
, rn
, p1
,
3570 (opcode
& (1 << 23)) ? "" : "-",
3575 address
= thumb_alignpc4(address
);
3577 if (opcode
& (1 << 23))
3581 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3582 mnemonic
, rt
, rd
, address
);
3586 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3587 struct arm_instruction
*instruction
, char *cp
)
3589 int op
= (opcode
>> 21) & 0xf;
3590 int rd
= (opcode
>> 8) & 0xf;
3591 int rn
= (opcode
>> 16) & 0xf;
3592 int type
= (opcode
>> 4) & 0x3;
3593 int immed
= (opcode
>> 6) & 0x3;
3597 immed
|= (opcode
>> 10) & 0x1c;
3598 if (opcode
& (1 << 20))
3604 if (!(opcode
& (1 << 20)))
3605 return ERROR_INVALID_ARGUMENTS
;
3606 instruction
->type
= ARM_TST
;
3611 instruction
->type
= ARM_AND
;
3615 instruction
->type
= ARM_BIC
;
3620 instruction
->type
= ARM_MOV
;
3624 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3626 (int) (opcode
& 0xf));
3639 sprintf(cp
, "RRX%s\tr%d, r%d",
3641 (int) (opcode
& 0xf));
3649 instruction
->type
= ARM_ORR
;
3655 instruction
->type
= ARM_MVN
;
3660 // instruction->type = ARM_ORN;
3666 if (!(opcode
& (1 << 20)))
3667 return ERROR_INVALID_ARGUMENTS
;
3668 instruction
->type
= ARM_TEQ
;
3673 instruction
->type
= ARM_EOR
;
3678 if (!(opcode
& (1 << 20)))
3679 return ERROR_INVALID_ARGUMENTS
;
3680 instruction
->type
= ARM_CMN
;
3685 instruction
->type
= ARM_ADD
;
3689 instruction
->type
= ARM_ADC
;
3693 instruction
->type
= ARM_SBC
;
3698 if (!(opcode
& (1 << 21)))
3699 return ERROR_INVALID_ARGUMENTS
;
3700 instruction
->type
= ARM_CMP
;
3705 instruction
->type
= ARM_SUB
;
3709 instruction
->type
= ARM_RSB
;
3713 return ERROR_INVALID_ARGUMENTS
;
3716 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3717 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3740 strcpy(cp
, ", RRX");
3746 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3750 sprintf(cp
, "%s%s.W\tr%d, r%d",
3751 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3755 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3756 mnemonic
, suffix
, rd
,
3757 (int) (opcode
& 0xf), immed
? immed
: 32);
3761 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3762 struct arm_instruction
*instruction
, char *cp
)
3767 if (((opcode
>> 4) & 0xf) == 0) {
3768 switch ((opcode
>> 21) & 0x7) {
3782 return ERROR_INVALID_ARGUMENTS
;
3785 instruction
->type
= ARM_MOV
;
3786 if (opcode
& (1 << 20))
3788 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3790 (int) (opcode
>> 8) & 0xf,
3791 (int) (opcode
>> 16) & 0xf,
3792 (int) (opcode
>> 0) & 0xf);
3794 } else if (opcode
& (1 << 7)) {
3795 switch ((opcode
>> 20) & 0xf) {
3800 switch ((opcode
>> 4) & 0x3) {
3802 suffix
= ", ROR #8";
3805 suffix
= ", ROR #16";
3808 suffix
= ", ROR #24";
3811 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3812 (opcode
& (1 << 24)) ? 'U' : 'S',
3813 (opcode
& (1 << 26)) ? 'B' : 'H',
3814 (int) (opcode
>> 8) & 0xf,
3815 (int) (opcode
>> 0) & 0xf,
3822 if (opcode
& (1 << 6))
3823 return ERROR_INVALID_ARGUMENTS
;
3824 if (((opcode
>> 12) & 0xf) != 0xf)
3825 return ERROR_INVALID_ARGUMENTS
;
3826 if (!(opcode
& (1 << 20)))
3827 return ERROR_INVALID_ARGUMENTS
;
3829 switch (((opcode
>> 19) & 0x04)
3830 | ((opcode
>> 4) & 0x3)) {
3835 mnemonic
= "REV16.W";
3841 mnemonic
= "REVSH.W";
3847 return ERROR_INVALID_ARGUMENTS
;
3849 sprintf(cp
, "%s\tr%d, r%d",
3851 (int) (opcode
>> 8) & 0xf,
3852 (int) (opcode
>> 0) & 0xf);
3855 return ERROR_INVALID_ARGUMENTS
;
3862 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3863 struct arm_instruction
*instruction
, char *cp
)
3865 int rn
= (opcode
>> 16) & 0xf;
3868 instruction
->type
= ARM_LDR
;
3871 immed
= opcode
& 0x0fff;
3872 if ((opcode
& (1 << 23)) == 0)
3874 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3875 (int) (opcode
>> 12) & 0xf,
3876 thumb_alignpc4(address
) + immed
);
3880 if (opcode
& (1 << 23)) {
3881 immed
= opcode
& 0x0fff;
3882 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3883 (int) (opcode
>> 12) & 0xf,
3888 if (!(opcode
& (0x3f << 6))) {
3889 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3890 (int) (opcode
>> 12) & 0xf,
3892 (int) (opcode
>> 0) & 0xf,
3893 (int) (opcode
>> 4) & 0x3);
3898 if (((opcode
>> 8) & 0xf) == 0xe) {
3899 immed
= opcode
& 0x00ff;
3901 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3902 (int) (opcode
>> 12) & 0xf,
3907 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3908 char *p1
= "]", *p2
= "";
3910 if (!(opcode
& 0x0500))
3911 return ERROR_INVALID_ARGUMENTS
;
3913 immed
= opcode
& 0x00ff;
3915 /* two indexed modes will write back rn */
3916 if (opcode
& 0x100) {
3917 if (opcode
& 0x400) /* pre-indexed */
3919 else { /* post-indexed */
3925 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3926 (int) (opcode
>> 12) & 0xf,
3928 (opcode
& 0x200) ? "" : "-",
3933 return ERROR_INVALID_ARGUMENTS
;
3936 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3937 struct arm_instruction
*instruction
, char *cp
)
3939 int rn
= (opcode
>> 16) & 0xf;
3940 int rt
= (opcode
>> 12) & 0xf;
3941 int op2
= (opcode
>> 6) & 0x3f;
3943 char *p1
= "", *p2
= "]";
3946 switch ((opcode
>> 23) & 0x3) {
3948 if ((rn
& rt
) == 0xf) {
3950 immed
= opcode
& 0xfff;
3951 address
= thumb_alignpc4(address
);
3952 if (opcode
& (1 << 23))
3956 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
3960 if (rn
== 0x0f && rt
!= 0x0f) {
3962 immed
= opcode
& 0xfff;
3963 address
= thumb_alignpc4(address
);
3964 if (opcode
& (1 << 23))
3968 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
3974 if ((op2
& 0x3c) == 0x38) {
3975 immed
= opcode
& 0xff;
3976 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3977 rt
, rn
, immed
, immed
);
3980 if ((op2
& 0x3c) == 0x30) {
3982 immed
= opcode
& 0xff;
3985 p1
= (opcode
& (1 << 21)) ? "W" : "";
3986 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3987 p1
, rn
, immed
, immed
);
3992 immed
= opcode
& 0xff;
3993 if (!(opcode
& 0x200))
3996 /* two indexed modes will write back rn */
3997 if (opcode
& 0x100) {
3998 if (opcode
& 0x400) /* pre-indexed */
4000 else { /* post-indexed */
4006 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4007 mnemonic
, rt
, rn
, p1
,
4011 if ((op2
& 0x24) == 0x24) {
4013 goto ldrxb_immediate_t3
;
4016 int rm
= opcode
& 0xf;
4019 sprintf(cp
, "PLD\t");
4021 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4022 immed
= (opcode
>> 4) & 0x3;
4024 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4029 if ((rn
& rt
) == 0xf)
4032 immed
= opcode
& 0xfff;
4033 goto preload_immediate
;
4037 mnemonic
= "LDRB.W";
4038 immed
= opcode
& 0xfff;
4039 goto ldrxb_immediate_t2
;
4041 if ((rn
& rt
) == 0xf) {
4042 immed
= opcode
& 0xfff;
4043 address
= thumb_alignpc4(address
);
4044 if (opcode
& (1 << 23))
4048 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4051 if (rn
== 0xf && rt
!= 0xf) {
4053 immed
= opcode
& 0xfff;
4054 address
= thumb_alignpc4(address
);
4055 if (opcode
& (1 << 23))
4059 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4064 if ((op2
& 0x3c) == 0x38) {
4065 immed
= opcode
& 0xff;
4066 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4067 rt
, rn
, immed
, immed
);
4070 if ((op2
& 0x3c) == 0x30) {
4072 immed
= opcode
& 0xff;
4073 immed
= -immed
; // pli
4074 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4079 goto ldrxb_immediate_t3
;
4081 if ((op2
& 0x24) == 0x24) {
4083 goto ldrxb_immediate_t3
;
4086 int rm
= opcode
& 0xf;
4089 sprintf(cp
, "PLI\t");
4091 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4092 immed
= (opcode
>> 4) & 0x3;
4094 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4100 immed
= opcode
& 0xfff;
4101 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4107 immed
= opcode
& 0xfff;
4109 goto ldrxb_immediate_t2
;
4112 return ERROR_INVALID_ARGUMENTS
;
4115 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4116 struct arm_instruction
*instruction
, char *cp
)
4118 int rn
= (opcode
>> 16) & 0xf;
4119 int rt
= (opcode
>> 12) & 0xf;
4120 int op2
= (opcode
>> 6) & 0x3f;
4125 sprintf(cp
, "HINT (UNALLOCATED)");
4129 if (opcode
& (1 << 24))
4132 if ((opcode
& (1 << 23)) == 0) {
4135 immed
= opcode
& 0xfff;
4136 address
= thumb_alignpc4(address
);
4137 if (opcode
& (1 << 23))
4141 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4146 int rm
= opcode
& 0xf;
4148 immed
= (opcode
>> 4) & 0x3;
4149 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4150 sign
, rt
, rn
, rm
, immed
);
4153 if ((op2
& 0x3c) == 0x38) {
4154 immed
= opcode
& 0xff;
4155 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4156 sign
, rt
, rn
, immed
, immed
);
4159 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4160 char *p1
= "", *p2
= "]";
4162 immed
= opcode
& 0xff;
4163 if (!(opcode
& 0x200))
4166 /* two indexed modes will write back rn */
4167 if (opcode
& 0x100) {
4168 if (opcode
& 0x400) /* pre-indexed */
4170 else { /* post-indexed */
4175 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4176 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4183 immed
= opcode
& 0xfff;
4184 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4185 sign
, *sign
? "" : ".W",
4186 rt
, rn
, immed
, immed
);
4190 return ERROR_INVALID_ARGUMENTS
;
4194 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4195 * always set. That means eventual arm_simulate_step() support for Thumb2
4196 * will need work in this area.
4198 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4205 /* clear low bit ... it's set on function pointers */
4208 /* clear fields, to avoid confusion */
4209 memset(instruction
, 0, sizeof(struct arm_instruction
));
4211 /* read first halfword, see if this is the only one */
4212 retval
= target_read_u16(target
, address
, &op
);
4213 if (retval
!= ERROR_OK
)
4216 switch (op
& 0xf800) {
4220 /* 32-bit instructions */
4221 instruction
->instruction_size
= 4;
4223 retval
= target_read_u16(target
, address
+ 2, &op
);
4224 if (retval
!= ERROR_OK
)
4227 instruction
->opcode
= opcode
;
4230 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4231 return thumb_evaluate_opcode(op
, address
, instruction
);
4234 snprintf(instruction
->text
, 128,
4235 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4237 cp
= strchr(instruction
->text
, 0);
4238 retval
= ERROR_FAIL
;
4240 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4241 if ((opcode
& 0x1a008000) == 0x10000000)
4242 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4244 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4245 else if ((opcode
& 0x1a008000) == 0x12000000)
4246 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4248 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4249 else if ((opcode
& 0x18008000) == 0x10008000)
4250 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4252 /* ARMv7-M: A5.3.5 Load/store multiple */
4253 else if ((opcode
& 0x1e400000) == 0x08000000)
4254 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4256 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4257 else if ((opcode
& 0x1e400000) == 0x08400000)
4258 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4260 /* ARMv7-M: A5.3.7 Load word */
4261 else if ((opcode
& 0x1f700000) == 0x18500000)
4262 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4264 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4265 else if ((opcode
& 0x1e700000) == 0x18300000)
4266 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4268 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4269 else if ((opcode
& 0x1e700000) == 0x18100000)
4270 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4272 /* ARMv7-M: A5.3.10 Store single data item */
4273 else if ((opcode
& 0x1f100000) == 0x18000000)
4274 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4276 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4277 else if ((opcode
& 0x1e000000) == 0x0a000000)
4278 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4280 /* ARMv7-M: A5.3.12 Data processing (register)
4281 * and A5.3.13 Miscellaneous operations
4283 else if ((opcode
& 0x1f000000) == 0x1a000000)
4284 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4286 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4287 else if ((opcode
& 0x1f800000) == 0x1b000000)
4288 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4290 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4291 else if ((opcode
& 0x1f800000) == 0x1b800000)
4292 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4294 if (retval
== ERROR_OK
)
4298 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4299 * instructions; not yet handled here.
4302 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4303 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4304 strcpy(cp
, "UNDEFINED OPCODE");
4308 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4311 strcpy(cp
, "(32-bit Thumb2 ...)");
4315 int arm_access_size(struct arm_instruction
*instruction
)
4317 if ((instruction
->type
== ARM_LDRB
)
4318 || (instruction
->type
== ARM_LDRBT
)
4319 || (instruction
->type
== ARM_LDRSB
)
4320 || (instruction
->type
== ARM_STRB
)
4321 || (instruction
->type
== ARM_STRBT
))
4325 else if ((instruction
->type
== ARM_LDRH
)
4326 || (instruction
->type
== ARM_LDRSH
)
4327 || (instruction
->type
== ARM_STRH
))
4331 else if ((instruction
->type
== ARM_LDR
)
4332 || (instruction
->type
== ARM_LDRT
)
4333 || (instruction
->type
== ARM_STR
)
4334 || (instruction
->type
== ARM_STRT
))
4338 else if ((instruction
->type
== ARM_LDRD
)
4339 || (instruction
->type
== ARM_STRD
))
4345 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)