1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
21 ***************************************************************************/
28 #include "arm_disassembler.h"
29 #include <helper/log.h>
32 * This disassembler supports two main functions for OpenOCD:
34 * - Various "disassemble" commands. OpenOCD can serve as a
35 * machine-language debugger, without help from GDB.
37 * - Single stepping. Not all ARM cores support hardware single
38 * stepping. To work without that support, the debugger must
39 * be able to decode instructions to find out where to put a
40 * "next instruction" breakpoint.
42 * In addition, interpretation of ETM trace data needs some of the
43 * decoding mechanisms.
45 * At this writing (September 2009) neither function is complete.
48 * * Old-style syntax (not UAL) is generally used
49 * * VFP instructions are not understood (ARMv5 and later)
50 * except as coprocessor 10/11 operations
51 * * Most ARM instructions through ARMv6 are decoded, but some
52 * of the post-ARMv4 opcodes may not be handled yet
53 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
54 * * NEON instructions are not understood (ARMv7-A)
56 * - Thumb/Thumb2 decoding
57 * * UAL syntax should be consistently used
58 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
59 * be handled properly. Accordingly, so should the subset
60 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
62 * * Conditional effects of Thumb2 "IT" (if-then) instructions
63 * are not handled: the affected instructions are not shown
64 * with their now-conditional suffixes.
65 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
66 * handled (minimally for coprocessor access).
67 * * SIMD instructions, and some other Thumb2 instructions
68 * from ARMv7-A, are not understood.
71 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
72 * * Opcodes changed by ThumbEE mode are not handled; these
73 * instructions wrongly decode as LDM and STM.
75 * - Jazelle decoding ... no support whatsoever for Jazelle mode
76 * or decoding. ARM encourages use of the more generic ThumbEE
77 * mode, instead of Jazelle mode, in current chips.
79 * - Single-step/emulation ... spotty support, which is only weakly
80 * tested. Thumb2 is not supported. (Arguably a full simulator
81 * is not needed to support just single stepping. Recognizing
82 * branch vs non-branch instructions suffices, except when the
83 * instruction faults and triggers a synchronous exception which
84 * can be intercepted using other means.)
86 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
87 * ARM v7-R edition" gives the most complete coverage of the various
88 * generations of ARM instructions. At this writing it is publicly
89 * accessible to anyone willing to create an account at the ARM
90 * web site; see http://www.arm.com/documentation/ for information.
92 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
93 * more details relevant to the Thumb2-only processors (such as
94 * the Cortex-M implementations).
97 /* textual represenation of the condition field
98 * ALways (default) is ommitted (empty string) */
99 static const char *arm_condition_strings
[] = {
100 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
103 /* make up for C's missing ROR */
104 static uint32_t ror(uint32_t value
, int places
)
106 return (value
>> places
) | (value
<< (32 - places
));
109 static int evaluate_unknown(uint32_t opcode
,
110 uint32_t address
, struct arm_instruction
*instruction
)
112 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
113 snprintf(instruction
->text
, 128,
114 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
115 "\tUNDEFINED INSTRUCTION", address
, opcode
);
119 static int evaluate_pld(uint32_t opcode
,
120 uint32_t address
, struct arm_instruction
*instruction
)
123 if ((opcode
& 0x0d70f000) == 0x0550f000) {
124 instruction
->type
= ARM_PLD
;
126 snprintf(instruction
->text
,
128 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...",
134 return evaluate_unknown(opcode
, address
, instruction
);
137 static int evaluate_srs(uint32_t opcode
,
138 uint32_t address
, struct arm_instruction
*instruction
)
140 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
141 const char *mode
= "";
143 switch ((opcode
>> 23) & 0x3) {
148 /* "IA" is default */
158 switch (opcode
& 0x0e500000) {
160 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
162 "\tSRS%s\tSP%s, #%d",
165 (unsigned)(opcode
& 0x1f));
168 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
173 (unsigned)((opcode
>> 16) & 0xf), wback
);
176 return evaluate_unknown(opcode
, address
, instruction
);
181 static int evaluate_swi(uint32_t opcode
,
182 uint32_t address
, struct arm_instruction
*instruction
)
184 instruction
->type
= ARM_SWI
;
186 snprintf(instruction
->text
, 128,
187 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
188 address
, opcode
, (opcode
& 0xffffff));
193 static int evaluate_blx_imm(uint32_t opcode
,
194 uint32_t address
, struct arm_instruction
*instruction
)
198 uint32_t target_address
;
200 instruction
->type
= ARM_BLX
;
201 immediate
= opcode
& 0x00ffffff;
203 /* sign extend 24-bit immediate */
204 if (immediate
& 0x00800000)
205 offset
= 0xff000000 | immediate
;
209 /* shift two bits left */
212 /* odd/event halfword */
213 if (opcode
& 0x01000000)
216 target_address
= address
+ 8 + offset
;
218 snprintf(instruction
->text
,
220 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"",
225 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
226 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
231 static int evaluate_b_bl(uint32_t opcode
,
232 uint32_t address
, struct arm_instruction
*instruction
)
237 uint32_t target_address
;
239 immediate
= opcode
& 0x00ffffff;
240 L
= (opcode
& 0x01000000) >> 24;
242 /* sign extend 24-bit immediate */
243 if (immediate
& 0x00800000)
244 offset
= 0xff000000 | immediate
;
248 /* shift two bits left */
251 target_address
= address
+ 8 + offset
;
254 instruction
->type
= ARM_BL
;
256 instruction
->type
= ARM_B
;
258 snprintf(instruction
->text
,
260 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
,
267 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
268 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
273 /* Coprocessor load/store and double register transfers
274 * both normal and extended instruction space (condition field b1111) */
275 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
276 uint32_t address
, struct arm_instruction
*instruction
)
278 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
281 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c500000)) {
282 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
285 cp_opcode
= (opcode
& 0xf0) >> 4;
286 Rd
= (opcode
& 0xf000) >> 12;
287 Rn
= (opcode
& 0xf0000) >> 16;
288 CRm
= (opcode
& 0xf);
291 if ((opcode
& 0x0ff00000) == 0x0c400000) {
292 instruction
->type
= ARM_MCRR
;
294 } else if ((opcode
& 0x0ff00000) == 0x0c500000) {
296 instruction
->type
= ARM_MRRC
;
299 LOG_ERROR("Unknown instruction");
303 snprintf(instruction
->text
, 128,
304 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
305 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
306 address
, opcode
, mnemonic
,
307 ((opcode
& 0xf0000000) == 0xf0000000)
308 ? "2" : COND(opcode
),
309 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
310 } else {/* LDC or STC */
311 uint8_t CRd
, Rn
, offset
;
314 char addressing_mode
[32];
316 CRd
= (opcode
& 0xf000) >> 12;
317 Rn
= (opcode
& 0xf0000) >> 16;
318 offset
= (opcode
& 0xff) << 2;
321 if (opcode
& 0x00100000) {
322 instruction
->type
= ARM_LDC
;
325 instruction
->type
= ARM_STC
;
329 U
= (opcode
& 0x00800000) >> 23;
331 /* addressing modes */
332 if ((opcode
& 0x01200000) == 0x01000000)/* offset */
333 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
334 Rn
, U
? "" : "-", offset
);
335 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
336 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
337 Rn
, U
? "" : "-", offset
);
338 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
339 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
340 Rn
, U
? "" : "-", offset
);
341 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
342 snprintf(addressing_mode
, 32, "[r%i], {%d}",
345 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
347 "\t%s%s%s p%i, c%i, %s",
348 address
, opcode
, mnemonic
,
349 ((opcode
& 0xf0000000) == 0xf0000000)
350 ? "2" : COND(opcode
),
351 (opcode
& (1 << 22)) ? "L" : "",
352 cp_num
, CRd
, addressing_mode
);
358 /* Coprocessor data processing instructions
359 * Coprocessor register transfer instructions
360 * both normal and extended instruction space (condition field b1111) */
361 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
362 uint32_t address
, struct arm_instruction
*instruction
)
366 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
368 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
369 cp_num
= (opcode
& 0xf00) >> 8;
370 CRd_Rd
= (opcode
& 0xf000) >> 12;
371 CRn
= (opcode
& 0xf0000) >> 16;
372 CRm
= (opcode
& 0xf);
373 opcode_2
= (opcode
& 0xe0) >> 5;
376 if (opcode
& 0x00000010) { /* bit 4 set -> MRC/MCR */
377 if (opcode
& 0x00100000) { /* bit 20 set -> MRC */
378 instruction
->type
= ARM_MRC
;
380 } else {/* bit 20 not set -> MCR */
381 instruction
->type
= ARM_MCR
;
385 opcode_1
= (opcode
& 0x00e00000) >> 21;
387 snprintf(instruction
->text
,
389 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
400 } else {/* bit 4 not set -> CDP */
401 instruction
->type
= ARM_CDP
;
404 opcode_1
= (opcode
& 0x00f00000) >> 20;
406 snprintf(instruction
->text
,
408 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
424 /* Load/store instructions */
425 static int evaluate_load_store(uint32_t opcode
,
426 uint32_t address
, struct arm_instruction
*instruction
)
428 uint8_t I
, P
, U
, B
, W
, L
;
430 char *operation
;/* "LDR" or "STR" */
431 char *suffix
; /* "", "B", "T", "BT" */
435 I
= (opcode
& 0x02000000) >> 25;
436 P
= (opcode
& 0x01000000) >> 24;
437 U
= (opcode
& 0x00800000) >> 23;
438 B
= (opcode
& 0x00400000) >> 22;
439 W
= (opcode
& 0x00200000) >> 21;
440 L
= (opcode
& 0x00100000) >> 20;
442 /* target register */
443 Rd
= (opcode
& 0xf000) >> 12;
446 Rn
= (opcode
& 0xf0000) >> 16;
448 instruction
->info
.load_store
.Rd
= Rd
;
449 instruction
->info
.load_store
.Rn
= Rn
;
450 instruction
->info
.load_store
.U
= U
;
452 /* determine operation */
458 /* determine instruction type and suffix */
460 if ((P
== 0) && (W
== 1)) {
462 instruction
->type
= ARM_LDRBT
;
464 instruction
->type
= ARM_STRBT
;
468 instruction
->type
= ARM_LDRB
;
470 instruction
->type
= ARM_STRB
;
474 if ((P
== 0) && (W
== 1)) {
476 instruction
->type
= ARM_LDRT
;
478 instruction
->type
= ARM_STRT
;
482 instruction
->type
= ARM_LDR
;
484 instruction
->type
= ARM_STR
;
489 if (!I
) { /* #+-<offset_12> */
490 uint32_t offset_12
= (opcode
& 0xfff);
492 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
494 snprintf(offset
, 32, "%s", "");
496 instruction
->info
.load_store
.offset_mode
= 0;
497 instruction
->info
.load_store
.offset
.offset
= offset_12
;
498 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
499 uint8_t shift_imm
, shift
;
502 shift_imm
= (opcode
& 0xf80) >> 7;
503 shift
= (opcode
& 0x60) >> 5;
506 /* LSR encodes a shift by 32 bit as 0x0 */
507 if ((shift
== 0x1) && (shift_imm
== 0x0))
510 /* ASR encodes a shift by 32 bit as 0x0 */
511 if ((shift
== 0x2) && (shift_imm
== 0x0))
514 /* ROR by 32 bit is actually a RRX */
515 if ((shift
== 0x3) && (shift_imm
== 0x0))
518 instruction
->info
.load_store
.offset_mode
= 1;
519 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
520 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
521 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
523 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
524 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
525 else { /* +-<Rm>, <Shift>, #<shift_imm> */
528 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
531 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
534 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
537 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
540 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
547 if (W
== 0) { /* offset */
548 snprintf(instruction
->text
,
550 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
560 instruction
->info
.load_store
.index_mode
= 0;
561 } else {/* pre-indexed */
562 snprintf(instruction
->text
,
564 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
574 instruction
->info
.load_store
.index_mode
= 1;
576 } else {/* post-indexed */
577 snprintf(instruction
->text
,
579 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
589 instruction
->info
.load_store
.index_mode
= 2;
595 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
597 unsigned rm
= (opcode
>> 0) & 0xf;
598 unsigned rd
= (opcode
>> 12) & 0xf;
599 unsigned rn
= (opcode
>> 16) & 0xf;
602 switch ((opcode
>> 24) & 0x3) {
607 sprintf(cp
, "UNDEFINED");
608 return ARM_UNDEFINED_INSTRUCTION
;
617 switch ((opcode
>> 10) & 0x3) {
633 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
634 (opcode
& (1 << 22)) ? 'U' : 'S',
639 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
640 (opcode
& (1 << 22)) ? 'U' : 'S',
647 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
653 switch ((opcode
>> 20) & 0x7) {
676 switch ((opcode
>> 5) & 0x7) {
705 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
706 (int) (opcode
>> 12) & 0xf,
707 (int) (opcode
>> 16) & 0xf,
708 (int) (opcode
>> 0) & 0xf);
712 /* these opcodes might be used someday */
713 sprintf(cp
, "UNDEFINED");
714 return ARM_UNDEFINED_INSTRUCTION
;
717 /* ARMv6 and later support "media" instructions (includes SIMD) */
718 static int evaluate_media(uint32_t opcode
, uint32_t address
,
719 struct arm_instruction
*instruction
)
721 char *cp
= instruction
->text
;
722 char *mnemonic
= NULL
;
725 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
729 /* parallel add/subtract */
730 if ((opcode
& 0x01800000) == 0x00000000) {
731 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
736 if ((opcode
& 0x01f00020) == 0x00800000) {
738 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
740 if (opcode
& (1 << 6)) {
749 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
751 (int) (opcode
>> 12) & 0xf,
752 (int) (opcode
>> 16) & 0xf,
753 (int) (opcode
>> 0) & 0xf,
759 if ((opcode
& 0x01a00020) == 0x00a00000) {
761 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
763 if (opcode
& (1 << 6)) {
770 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
771 (opcode
& (1 << 22)) ? 'U' : 'S',
773 (int) (opcode
>> 12) & 0xf,
774 (int) (opcode
>> 16) & 0x1f,
775 (int) (opcode
>> 0) & 0xf,
781 if ((opcode
& 0x018000f0) == 0x00800070) {
782 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
787 if ((opcode
& 0x01f00080) == 0x01000000) {
788 unsigned rn
= (opcode
>> 12) & 0xf;
791 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
792 (opcode
& (1 << 6)) ? 'S' : 'A',
793 (opcode
& (1 << 5)) ? "X" : "",
795 (int) (opcode
>> 16) & 0xf,
796 (int) (opcode
>> 0) & 0xf,
797 (int) (opcode
>> 8) & 0xf,
800 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
801 (opcode
& (1 << 6)) ? 'S' : 'A',
802 (opcode
& (1 << 5)) ? "X" : "",
804 (int) (opcode
>> 16) & 0xf,
805 (int) (opcode
>> 0) & 0xf,
806 (int) (opcode
>> 8) & 0xf);
809 if ((opcode
& 0x01f00000) == 0x01400000) {
810 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
811 (opcode
& (1 << 6)) ? 'S' : 'A',
812 (opcode
& (1 << 5)) ? "X" : "",
814 (int) (opcode
>> 12) & 0xf,
815 (int) (opcode
>> 16) & 0xf,
816 (int) (opcode
>> 0) & 0xf,
817 (int) (opcode
>> 8) & 0xf);
820 if ((opcode
& 0x01f00000) == 0x01500000) {
821 unsigned rn
= (opcode
>> 12) & 0xf;
823 switch (opcode
& 0xc0) {
835 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
836 (opcode
& (1 << 6)) ? 'S' : 'A',
837 (opcode
& (1 << 5)) ? "R" : "",
839 (int) (opcode
>> 16) & 0xf,
840 (int) (opcode
>> 0) & 0xf,
841 (int) (opcode
>> 8) & 0xf,
844 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
845 (opcode
& (1 << 5)) ? "R" : "",
847 (int) (opcode
>> 16) & 0xf,
848 (int) (opcode
>> 0) & 0xf,
849 (int) (opcode
>> 8) & 0xf);
853 /* simple matches against the remaining decode bits */
854 switch (opcode
& 0x01f000f0) {
857 /* parallel halfword saturate */
858 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
859 (opcode
& (1 << 22)) ? 'U' : 'S',
861 (int) (opcode
>> 12) & 0xf,
862 (int) (opcode
>> 16) & 0xf,
863 (int) (opcode
>> 0) & 0xf);
876 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
877 (int) (opcode
>> 12) & 0xf,
878 (int) (opcode
>> 16) & 0xf,
879 (int) (opcode
>> 0) & 0xf);
882 /* unsigned sum of absolute differences */
883 if (((opcode
>> 12) & 0xf) == 0xf)
884 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
885 (int) (opcode
>> 16) & 0xf,
886 (int) (opcode
>> 0) & 0xf,
887 (int) (opcode
>> 8) & 0xf);
889 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
890 (int) (opcode
>> 16) & 0xf,
891 (int) (opcode
>> 0) & 0xf,
892 (int) (opcode
>> 8) & 0xf,
893 (int) (opcode
>> 12) & 0xf);
897 unsigned rm
= (opcode
>> 0) & 0xf;
898 unsigned rd
= (opcode
>> 12) & 0xf;
900 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
905 /* these opcodes might be used someday */
906 sprintf(cp
, "UNDEFINED");
910 /* Miscellaneous load/store instructions */
911 static int evaluate_misc_load_store(uint32_t opcode
,
912 uint32_t address
, struct arm_instruction
*instruction
)
914 uint8_t P
, U
, I
, W
, L
, S
, H
;
916 char *operation
;/* "LDR" or "STR" */
917 char *suffix
; /* "H", "SB", "SH", "D" */
921 P
= (opcode
& 0x01000000) >> 24;
922 U
= (opcode
& 0x00800000) >> 23;
923 I
= (opcode
& 0x00400000) >> 22;
924 W
= (opcode
& 0x00200000) >> 21;
925 L
= (opcode
& 0x00100000) >> 20;
926 S
= (opcode
& 0x00000040) >> 6;
927 H
= (opcode
& 0x00000020) >> 5;
929 /* target register */
930 Rd
= (opcode
& 0xf000) >> 12;
933 Rn
= (opcode
& 0xf0000) >> 16;
935 instruction
->info
.load_store
.Rd
= Rd
;
936 instruction
->info
.load_store
.Rn
= Rn
;
937 instruction
->info
.load_store
.U
= U
;
939 /* determine instruction type and suffix */
944 instruction
->type
= ARM_LDRSH
;
948 instruction
->type
= ARM_LDRSB
;
951 } else {/* there are no signed stores, so this is used to encode double-register
956 instruction
->type
= ARM_STRD
;
959 instruction
->type
= ARM_LDRD
;
962 } else {/* unsigned */
966 instruction
->type
= ARM_LDRH
;
969 instruction
->type
= ARM_STRH
;
973 if (I
) {/* Immediate offset/index (#+-<offset_8>)*/
974 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
975 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
977 instruction
->info
.load_store
.offset_mode
= 0;
978 instruction
->info
.load_store
.offset
.offset
= offset_8
;
979 } else {/* Register offset/index (+-<Rm>) */
982 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
984 instruction
->info
.load_store
.offset_mode
= 1;
985 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
986 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
987 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
991 if (W
== 0) { /* offset */
992 snprintf(instruction
->text
,
994 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
1004 instruction
->info
.load_store
.index_mode
= 0;
1005 } else {/* pre-indexed */
1006 snprintf(instruction
->text
,
1008 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1018 instruction
->info
.load_store
.index_mode
= 1;
1020 } else {/* post-indexed */
1021 snprintf(instruction
->text
,
1023 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1033 instruction
->info
.load_store
.index_mode
= 2;
1039 /* Load/store multiples instructions */
1040 static int evaluate_ldm_stm(uint32_t opcode
,
1041 uint32_t address
, struct arm_instruction
*instruction
)
1043 uint8_t P
, U
, S
, W
, L
, Rn
;
1044 uint32_t register_list
;
1045 char *addressing_mode
;
1052 P
= (opcode
& 0x01000000) >> 24;
1053 U
= (opcode
& 0x00800000) >> 23;
1054 S
= (opcode
& 0x00400000) >> 22;
1055 W
= (opcode
& 0x00200000) >> 21;
1056 L
= (opcode
& 0x00100000) >> 20;
1057 register_list
= (opcode
& 0xffff);
1058 Rn
= (opcode
& 0xf0000) >> 16;
1060 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1061 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1062 instruction
->info
.load_store_multiple
.S
= S
;
1063 instruction
->info
.load_store_multiple
.W
= W
;
1066 instruction
->type
= ARM_LDM
;
1069 instruction
->type
= ARM_STM
;
1075 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1076 addressing_mode
= "IB";
1078 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1079 addressing_mode
= "DB";
1083 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1084 /* "IA" is the default in UAL syntax */
1085 addressing_mode
= "";
1087 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1088 addressing_mode
= "DA";
1092 reg_list_p
= reg_list
;
1093 for (i
= 0; i
<= 15; i
++) {
1094 if ((register_list
>> i
) & 1) {
1097 reg_list_p
+= snprintf(reg_list_p
,
1098 (reg_list
+ 69 - reg_list_p
),
1102 reg_list_p
+= snprintf(reg_list_p
,
1103 (reg_list
+ 69 - reg_list_p
),
1109 snprintf(instruction
->text
, 128,
1110 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1111 "\t%s%s%s r%i%s, {%s}%s",
1113 mnemonic
, addressing_mode
, COND(opcode
),
1114 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1119 /* Multiplies, extra load/stores */
1120 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1121 uint32_t address
, struct arm_instruction
*instruction
)
1123 /* Multiply (accumulate) (long) and Swap/swap byte */
1124 if ((opcode
& 0x000000f0) == 0x00000090) {
1125 /* Multiply (accumulate) */
1126 if ((opcode
& 0x0f800000) == 0x00000000) {
1127 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1129 Rs
= (opcode
& 0xf00) >> 8;
1130 Rn
= (opcode
& 0xf000) >> 12;
1131 Rd
= (opcode
& 0xf0000) >> 16;
1132 S
= (opcode
& 0x00100000) >> 20;
1134 /* examine A bit (accumulate) */
1135 if (opcode
& 0x00200000) {
1136 instruction
->type
= ARM_MLA
;
1137 snprintf(instruction
->text
,
1139 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1149 instruction
->type
= ARM_MUL
;
1150 snprintf(instruction
->text
,
1152 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1165 /* Multiply (accumulate) long */
1166 if ((opcode
& 0x0f800000) == 0x00800000) {
1167 char *mnemonic
= NULL
;
1168 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1170 Rs
= (opcode
& 0xf00) >> 8;
1171 RdHi
= (opcode
& 0xf000) >> 12;
1172 RdLow
= (opcode
& 0xf0000) >> 16;
1173 S
= (opcode
& 0x00100000) >> 20;
1175 switch ((opcode
& 0x00600000) >> 21) {
1177 instruction
->type
= ARM_UMULL
;
1181 instruction
->type
= ARM_UMLAL
;
1185 instruction
->type
= ARM_SMULL
;
1189 instruction
->type
= ARM_SMLAL
;
1194 snprintf(instruction
->text
,
1196 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1210 /* Swap/swap byte */
1211 if ((opcode
& 0x0f800000) == 0x01000000) {
1214 Rd
= (opcode
& 0xf000) >> 12;
1215 Rn
= (opcode
& 0xf0000) >> 16;
1217 /* examine B flag */
1218 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1220 snprintf(instruction
->text
,
1222 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1225 (opcode
& 0x00400000) ? "SWPB" : "SWP",
1235 return evaluate_misc_load_store(opcode
, address
, instruction
);
1238 static int evaluate_mrs_msr(uint32_t opcode
,
1239 uint32_t address
, struct arm_instruction
*instruction
)
1241 int R
= (opcode
& 0x00400000) >> 22;
1242 char *PSR
= (R
) ? "SPSR" : "CPSR";
1244 /* Move register to status register (MSR) */
1245 if (opcode
& 0x00200000) {
1246 instruction
->type
= ARM_MSR
;
1248 /* immediate variant */
1249 if (opcode
& 0x02000000) {
1250 uint8_t immediate
= (opcode
& 0xff);
1251 uint8_t rotate
= (opcode
& 0xf00);
1253 snprintf(instruction
->text
,
1255 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1260 (opcode
& 0x10000) ? "c" : "",
1261 (opcode
& 0x20000) ? "x" : "",
1262 (opcode
& 0x40000) ? "s" : "",
1263 (opcode
& 0x80000) ? "f" : "",
1264 ror(immediate
, (rotate
* 2))
1266 } else {/* register variant */
1267 uint8_t Rm
= opcode
& 0xf;
1268 snprintf(instruction
->text
,
1270 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1275 (opcode
& 0x10000) ? "c" : "",
1276 (opcode
& 0x20000) ? "x" : "",
1277 (opcode
& 0x40000) ? "s" : "",
1278 (opcode
& 0x80000) ? "f" : "",
1283 } else {/* Move status register to register (MRS) */
1286 instruction
->type
= ARM_MRS
;
1287 Rd
= (opcode
& 0x0000f000) >> 12;
1289 snprintf(instruction
->text
,
1291 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1302 /* Miscellaneous instructions */
1303 static int evaluate_misc_instr(uint32_t opcode
,
1304 uint32_t address
, struct arm_instruction
*instruction
)
1307 if ((opcode
& 0x000000f0) == 0x00000000)
1308 evaluate_mrs_msr(opcode
, address
, instruction
);
1311 if ((opcode
& 0x006000f0) == 0x00200010) {
1313 instruction
->type
= ARM_BX
;
1316 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1317 address
, opcode
, COND(opcode
), Rm
);
1319 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1320 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1323 /* BXJ - "Jazelle" support (ARMv5-J) */
1324 if ((opcode
& 0x006000f0) == 0x00200020) {
1326 instruction
->type
= ARM_BX
;
1329 snprintf(instruction
->text
, 128,
1330 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1331 address
, opcode
, COND(opcode
), Rm
);
1333 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1334 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1338 if ((opcode
& 0x006000f0) == 0x00600010) {
1340 instruction
->type
= ARM_CLZ
;
1342 Rd
= (opcode
& 0xf000) >> 12;
1344 snprintf(instruction
->text
,
1346 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1355 if ((opcode
& 0x006000f0) == 0x00200030) {
1357 instruction
->type
= ARM_BLX
;
1360 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1361 address
, opcode
, COND(opcode
), Rm
);
1363 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1364 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1367 /* Enhanced DSP add/subtracts */
1368 if ((opcode
& 0x0000000f0) == 0x00000050) {
1370 char *mnemonic
= NULL
;
1372 Rd
= (opcode
& 0xf000) >> 12;
1373 Rn
= (opcode
& 0xf0000) >> 16;
1375 switch ((opcode
& 0x00600000) >> 21) {
1377 instruction
->type
= ARM_QADD
;
1381 instruction
->type
= ARM_QSUB
;
1385 instruction
->type
= ARM_QDADD
;
1389 instruction
->type
= ARM_QDSUB
;
1394 snprintf(instruction
->text
,
1396 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1406 /* exception return */
1407 if ((opcode
& 0x0000000f0) == 0x00000060) {
1408 if (((opcode
& 0x600000) >> 21) == 3)
1409 instruction
->type
= ARM_ERET
;
1410 snprintf(instruction
->text
,
1412 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tERET",
1417 /* exception generate instructions */
1418 if ((opcode
& 0x0000000f0) == 0x00000070) {
1419 uint32_t immediate
= 0;
1420 char *mnemonic
= NULL
;
1422 switch ((opcode
& 0x600000) >> 21) {
1424 instruction
->type
= ARM_BKPT
;
1426 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1429 instruction
->type
= ARM_HVC
;
1431 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1434 instruction
->type
= ARM_SMC
;
1436 immediate
= (opcode
& 0xf);
1440 snprintf(instruction
->text
,
1442 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s 0x%4.4" PRIx32
"",
1449 /* Enhanced DSP multiplies */
1450 if ((opcode
& 0x000000090) == 0x00000080) {
1451 int x
= (opcode
& 0x20) >> 5;
1452 int y
= (opcode
& 0x40) >> 6;
1455 if ((opcode
& 0x00600000) == 0x00000000) {
1456 uint8_t Rd
, Rm
, Rs
, Rn
;
1457 instruction
->type
= ARM_SMLAxy
;
1458 Rd
= (opcode
& 0xf0000) >> 16;
1459 Rm
= (opcode
& 0xf);
1460 Rs
= (opcode
& 0xf00) >> 8;
1461 Rn
= (opcode
& 0xf000) >> 12;
1463 snprintf(instruction
->text
,
1465 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1478 if ((opcode
& 0x00600000) == 0x00400000) {
1479 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1480 instruction
->type
= ARM_SMLAxy
;
1481 RdHi
= (opcode
& 0xf0000) >> 16;
1482 RdLow
= (opcode
& 0xf000) >> 12;
1483 Rm
= (opcode
& 0xf);
1484 Rs
= (opcode
& 0xf00) >> 8;
1486 snprintf(instruction
->text
,
1488 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1501 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0)) {
1502 uint8_t Rd
, Rm
, Rs
, Rn
;
1503 instruction
->type
= ARM_SMLAWy
;
1504 Rd
= (opcode
& 0xf0000) >> 16;
1505 Rm
= (opcode
& 0xf);
1506 Rs
= (opcode
& 0xf00) >> 8;
1507 Rn
= (opcode
& 0xf000) >> 12;
1509 snprintf(instruction
->text
,
1511 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1523 if ((opcode
& 0x00600000) == 0x00300000) {
1525 instruction
->type
= ARM_SMULxy
;
1526 Rd
= (opcode
& 0xf0000) >> 16;
1527 Rm
= (opcode
& 0xf);
1528 Rs
= (opcode
& 0xf00) >> 8;
1530 snprintf(instruction
->text
,
1532 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1544 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1)) {
1546 instruction
->type
= ARM_SMULWy
;
1547 Rd
= (opcode
& 0xf0000) >> 16;
1548 Rm
= (opcode
& 0xf);
1549 Rs
= (opcode
& 0xf00) >> 8;
1551 snprintf(instruction
->text
,
1553 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1567 static int evaluate_data_proc(uint32_t opcode
,
1568 uint32_t address
, struct arm_instruction
*instruction
)
1570 uint8_t I
, op
, S
, Rn
, Rd
;
1571 char *mnemonic
= NULL
;
1572 char shifter_operand
[32];
1574 I
= (opcode
& 0x02000000) >> 25;
1575 op
= (opcode
& 0x01e00000) >> 21;
1576 S
= (opcode
& 0x00100000) >> 20;
1578 Rd
= (opcode
& 0xf000) >> 12;
1579 Rn
= (opcode
& 0xf0000) >> 16;
1581 instruction
->info
.data_proc
.Rd
= Rd
;
1582 instruction
->info
.data_proc
.Rn
= Rn
;
1583 instruction
->info
.data_proc
.S
= S
;
1587 instruction
->type
= ARM_AND
;
1591 instruction
->type
= ARM_EOR
;
1595 instruction
->type
= ARM_SUB
;
1599 instruction
->type
= ARM_RSB
;
1603 instruction
->type
= ARM_ADD
;
1607 instruction
->type
= ARM_ADC
;
1611 instruction
->type
= ARM_SBC
;
1615 instruction
->type
= ARM_RSC
;
1619 instruction
->type
= ARM_TST
;
1623 instruction
->type
= ARM_TEQ
;
1627 instruction
->type
= ARM_CMP
;
1631 instruction
->type
= ARM_CMN
;
1635 instruction
->type
= ARM_ORR
;
1639 instruction
->type
= ARM_MOV
;
1643 instruction
->type
= ARM_BIC
;
1647 instruction
->type
= ARM_MVN
;
1652 if (I
) {/* immediate shifter operand (#<immediate>)*/
1653 uint8_t immed_8
= opcode
& 0xff;
1654 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1657 immediate
= ror(immed_8
, rotate_imm
* 2);
1659 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1661 instruction
->info
.data_proc
.variant
= 0;
1662 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1663 } else {/* register-based shifter operand */
1665 shift
= (opcode
& 0x60) >> 5;
1666 Rm
= (opcode
& 0xf);
1668 if ((opcode
& 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1669 *#<shift_immediate>") */
1671 shift_imm
= (opcode
& 0xf80) >> 7;
1673 instruction
->info
.data_proc
.variant
= 1;
1674 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1675 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
=
1677 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1679 /* LSR encodes a shift by 32 bit as 0x0 */
1680 if ((shift
== 0x1) && (shift_imm
== 0x0))
1683 /* ASR encodes a shift by 32 bit as 0x0 */
1684 if ((shift
== 0x2) && (shift_imm
== 0x0))
1687 /* ROR by 32 bit is actually a RRX */
1688 if ((shift
== 0x3) && (shift_imm
== 0x0))
1691 if ((shift_imm
== 0x0) && (shift
== 0x0))
1692 snprintf(shifter_operand
, 32, "r%i", Rm
);
1694 if (shift
== 0x0) /* LSL */
1695 snprintf(shifter_operand
,
1700 else if (shift
== 0x1) /* LSR */
1701 snprintf(shifter_operand
,
1706 else if (shift
== 0x2) /* ASR */
1707 snprintf(shifter_operand
,
1712 else if (shift
== 0x3) /* ROR */
1713 snprintf(shifter_operand
,
1718 else if (shift
== 0x4) /* RRX */
1719 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1721 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1722 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1724 instruction
->info
.data_proc
.variant
= 2;
1725 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1726 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1727 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1729 if (shift
== 0x0) /* LSL */
1730 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1731 else if (shift
== 0x1) /* LSR */
1732 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1733 else if (shift
== 0x2) /* ASR */
1734 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1735 else if (shift
== 0x3) /* ROR */
1736 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1740 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1741 *<shifter_operand> */
1742 snprintf(instruction
->text
,
1744 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1753 } else if ((op
== 0xd) || (op
== 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1754 *<shifter_operand> */
1755 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1756 snprintf(instruction
->text
,
1758 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",
1762 snprintf(instruction
->text
,
1764 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1772 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1773 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1774 address
, opcode
, mnemonic
, COND(opcode
),
1775 Rn
, shifter_operand
);
1781 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1782 struct arm_instruction
*instruction
)
1784 /* clear fields, to avoid confusion */
1785 memset(instruction
, 0, sizeof(struct arm_instruction
));
1786 instruction
->opcode
= opcode
;
1787 instruction
->instruction_size
= 4;
1789 /* catch opcodes with condition field [31:28] = b1111 */
1790 if ((opcode
& 0xf0000000) == 0xf0000000) {
1791 /* Undefined instruction (or ARMv5E cache preload PLD) */
1792 if ((opcode
& 0x08000000) == 0x00000000)
1793 return evaluate_pld(opcode
, address
, instruction
);
1795 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1796 if ((opcode
& 0x0e000000) == 0x08000000)
1797 return evaluate_srs(opcode
, address
, instruction
);
1799 /* Branch and branch with link and change to Thumb */
1800 if ((opcode
& 0x0e000000) == 0x0a000000)
1801 return evaluate_blx_imm(opcode
, address
, instruction
);
1803 /* Extended coprocessor opcode space (ARMv5 and higher)
1804 * Coprocessor load/store and double register transfers */
1805 if ((opcode
& 0x0e000000) == 0x0c000000)
1806 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1808 /* Coprocessor data processing */
1809 if ((opcode
& 0x0f000100) == 0x0c000000)
1810 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1812 /* Coprocessor register transfers */
1813 if ((opcode
& 0x0f000010) == 0x0c000010)
1814 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1816 /* Undefined instruction */
1817 if ((opcode
& 0x0f000000) == 0x0f000000) {
1818 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1819 snprintf(instruction
->text
,
1821 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1828 /* catch opcodes with [27:25] = b000 */
1829 if ((opcode
& 0x0e000000) == 0x00000000) {
1830 /* Multiplies, extra load/stores */
1831 if ((opcode
& 0x00000090) == 0x00000090)
1832 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1834 /* Miscellaneous instructions */
1835 if ((opcode
& 0x0f900000) == 0x01000000)
1836 return evaluate_misc_instr(opcode
, address
, instruction
);
1838 return evaluate_data_proc(opcode
, address
, instruction
);
1841 /* catch opcodes with [27:25] = b001 */
1842 if ((opcode
& 0x0e000000) == 0x02000000) {
1843 /* Undefined instruction */
1844 if ((opcode
& 0x0fb00000) == 0x03000000) {
1845 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1846 snprintf(instruction
->text
,
1848 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1854 /* Move immediate to status register */
1855 if ((opcode
& 0x0fb00000) == 0x03200000)
1856 return evaluate_mrs_msr(opcode
, address
, instruction
);
1858 return evaluate_data_proc(opcode
, address
, instruction
);
1862 /* catch opcodes with [27:25] = b010 */
1863 if ((opcode
& 0x0e000000) == 0x04000000) {
1864 /* Load/store immediate offset */
1865 return evaluate_load_store(opcode
, address
, instruction
);
1868 /* catch opcodes with [27:25] = b011 */
1869 if ((opcode
& 0x0e000000) == 0x06000000) {
1870 /* Load/store register offset */
1871 if ((opcode
& 0x00000010) == 0x00000000)
1872 return evaluate_load_store(opcode
, address
, instruction
);
1874 /* Architecturally Undefined instruction
1875 * ... don't expect these to ever be used
1877 if ((opcode
& 0x07f000f0) == 0x07f000f0) {
1878 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1879 snprintf(instruction
->text
, 128,
1880 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1885 /* "media" instructions */
1886 return evaluate_media(opcode
, address
, instruction
);
1889 /* catch opcodes with [27:25] = b100 */
1890 if ((opcode
& 0x0e000000) == 0x08000000) {
1891 /* Load/store multiple */
1892 return evaluate_ldm_stm(opcode
, address
, instruction
);
1895 /* catch opcodes with [27:25] = b101 */
1896 if ((opcode
& 0x0e000000) == 0x0a000000) {
1897 /* Branch and branch with link */
1898 return evaluate_b_bl(opcode
, address
, instruction
);
1901 /* catch opcodes with [27:25] = b110 */
1902 if ((opcode
& 0x0e000000) == 0x0c000000) {
1903 /* Coprocessor load/store and double register transfers */
1904 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1907 /* catch opcodes with [27:25] = b111 */
1908 if ((opcode
& 0x0e000000) == 0x0e000000) {
1909 /* Software interrupt */
1910 if ((opcode
& 0x0f000000) == 0x0f000000)
1911 return evaluate_swi(opcode
, address
, instruction
);
1913 /* Coprocessor data processing */
1914 if ((opcode
& 0x0f000010) == 0x0e000000)
1915 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1917 /* Coprocessor register transfers */
1918 if ((opcode
& 0x0f000010) == 0x0e000010)
1919 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1922 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1927 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1928 uint32_t address
, struct arm_instruction
*instruction
)
1930 uint32_t offset
= opcode
& 0x7ff;
1931 uint32_t opc
= (opcode
>> 11) & 0x3;
1932 uint32_t target_address
;
1933 char *mnemonic
= NULL
;
1935 /* sign extend 11-bit offset */
1936 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1937 offset
= 0xfffff800 | offset
;
1939 target_address
= address
+ 4 + (offset
<< 1);
1942 /* unconditional branch */
1944 instruction
->type
= ARM_B
;
1949 instruction
->type
= ARM_BLX
;
1951 target_address
&= 0xfffffffc;
1955 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1956 mnemonic
= "prefix";
1957 target_address
= offset
<< 12;
1961 instruction
->type
= ARM_BL
;
1966 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1967 * these are effectively 32-bit instructions even in Thumb1. For
1968 * disassembly, it's simplest to always use the Thumb2 decoder.
1970 * But some cores will evidently handle them as two instructions,
1971 * where exceptions may occur between the two. The ETMv3.2+ ID
1972 * register has a bit which exposes this behavior.
1975 snprintf(instruction
->text
, 128,
1976 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1977 address
, opcode
, mnemonic
, target_address
);
1979 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1980 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1985 static int evaluate_add_sub_thumb(uint16_t opcode
,
1986 uint32_t address
, struct arm_instruction
*instruction
)
1988 uint8_t Rd
= (opcode
>> 0) & 0x7;
1989 uint8_t Rn
= (opcode
>> 3) & 0x7;
1990 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1991 uint32_t opc
= opcode
& (1 << 9);
1992 uint32_t reg_imm
= opcode
& (1 << 10);
1996 instruction
->type
= ARM_SUB
;
1999 /* REVISIT: if reg_imm == 0, display as "MOVS" */
2000 instruction
->type
= ARM_ADD
;
2004 instruction
->info
.data_proc
.Rd
= Rd
;
2005 instruction
->info
.data_proc
.Rn
= Rn
;
2006 instruction
->info
.data_proc
.S
= 1;
2009 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2010 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
2011 snprintf(instruction
->text
, 128,
2012 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
2013 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2015 instruction
->info
.data_proc
.variant
= 1;/*immediate shift*/
2016 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
2017 snprintf(instruction
->text
, 128,
2018 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
2019 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2025 static int evaluate_shift_imm_thumb(uint16_t opcode
,
2026 uint32_t address
, struct arm_instruction
*instruction
)
2028 uint8_t Rd
= (opcode
>> 0) & 0x7;
2029 uint8_t Rm
= (opcode
>> 3) & 0x7;
2030 uint8_t imm
= (opcode
>> 6) & 0x1f;
2031 uint8_t opc
= (opcode
>> 11) & 0x3;
2032 char *mnemonic
= NULL
;
2036 instruction
->type
= ARM_MOV
;
2038 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
2041 instruction
->type
= ARM_MOV
;
2043 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
2046 instruction
->type
= ARM_MOV
;
2048 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
2052 if ((imm
== 0) && (opc
!= 0))
2055 instruction
->info
.data_proc
.Rd
= Rd
;
2056 instruction
->info
.data_proc
.Rn
= -1;
2057 instruction
->info
.data_proc
.S
= 1;
2059 instruction
->info
.data_proc
.variant
= 1;/*immediate_shift*/
2060 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2061 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
2063 snprintf(instruction
->text
, 128,
2064 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2065 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
2070 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
2071 uint32_t address
, struct arm_instruction
*instruction
)
2073 uint8_t imm
= opcode
& 0xff;
2074 uint8_t Rd
= (opcode
>> 8) & 0x7;
2075 uint32_t opc
= (opcode
>> 11) & 0x3;
2076 char *mnemonic
= NULL
;
2078 instruction
->info
.data_proc
.Rd
= Rd
;
2079 instruction
->info
.data_proc
.Rn
= Rd
;
2080 instruction
->info
.data_proc
.S
= 1;
2081 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2082 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
2086 instruction
->type
= ARM_MOV
;
2088 instruction
->info
.data_proc
.Rn
= -1;
2091 instruction
->type
= ARM_CMP
;
2093 instruction
->info
.data_proc
.Rd
= -1;
2096 instruction
->type
= ARM_ADD
;
2100 instruction
->type
= ARM_SUB
;
2105 snprintf(instruction
->text
, 128,
2106 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
2107 address
, opcode
, mnemonic
, Rd
, imm
);
2112 static int evaluate_data_proc_thumb(uint16_t opcode
,
2113 uint32_t address
, struct arm_instruction
*instruction
)
2115 uint8_t high_reg
, op
, Rm
, Rd
, H1
, H2
;
2116 char *mnemonic
= NULL
;
2119 high_reg
= (opcode
& 0x0400) >> 10;
2120 op
= (opcode
& 0x03C0) >> 6;
2122 Rd
= (opcode
& 0x0007);
2123 Rm
= (opcode
& 0x0038) >> 3;
2124 H1
= (opcode
& 0x0080) >> 7;
2125 H2
= (opcode
& 0x0040) >> 6;
2127 instruction
->info
.data_proc
.Rd
= Rd
;
2128 instruction
->info
.data_proc
.Rn
= Rd
;
2129 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2130 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2131 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2140 instruction
->type
= ARM_ADD
;
2144 instruction
->type
= ARM_CMP
;
2148 instruction
->type
= ARM_MOV
;
2154 if ((opcode
& 0x7) == 0x0) {
2155 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2157 instruction
->type
= ARM_BLX
;
2158 snprintf(instruction
->text
, 128,
2160 " 0x%4.4x \tBLX\tr%i",
2161 address
, opcode
, Rm
);
2163 instruction
->type
= ARM_BX
;
2164 snprintf(instruction
->text
, 128,
2166 " 0x%4.4x \tBX\tr%i",
2167 address
, opcode
, Rm
);
2170 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2171 snprintf(instruction
->text
, 128,
2174 "UNDEFINED INSTRUCTION",
2183 instruction
->type
= ARM_AND
;
2187 instruction
->type
= ARM_EOR
;
2191 instruction
->type
= ARM_MOV
;
2193 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2194 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2195 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2196 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2199 instruction
->type
= ARM_MOV
;
2201 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2202 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2203 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2204 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2207 instruction
->type
= ARM_MOV
;
2209 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2210 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2211 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2212 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2215 instruction
->type
= ARM_ADC
;
2219 instruction
->type
= ARM_SBC
;
2223 instruction
->type
= ARM_MOV
;
2225 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2226 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2227 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2228 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2231 instruction
->type
= ARM_TST
;
2235 instruction
->type
= ARM_RSB
;
2237 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2238 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2239 instruction
->info
.data_proc
.Rn
= Rm
;
2242 instruction
->type
= ARM_CMP
;
2246 instruction
->type
= ARM_CMN
;
2250 instruction
->type
= ARM_ORR
;
2254 instruction
->type
= ARM_MUL
;
2258 instruction
->type
= ARM_BIC
;
2262 instruction
->type
= ARM_MVN
;
2269 snprintf(instruction
->text
, 128,
2270 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2272 address
, opcode
, mnemonic
, Rd
, Rm
);
2274 snprintf(instruction
->text
, 128,
2275 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2276 address
, opcode
, mnemonic
, Rd
, Rm
);
2281 /* PC-relative data addressing is word-aligned even with Thumb */
2282 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2284 return (addr
+ 4) & ~3;
2287 static int evaluate_load_literal_thumb(uint16_t opcode
,
2288 uint32_t address
, struct arm_instruction
*instruction
)
2291 uint8_t Rd
= (opcode
>> 8) & 0x7;
2293 instruction
->type
= ARM_LDR
;
2294 immediate
= opcode
& 0x000000ff;
2297 instruction
->info
.load_store
.Rd
= Rd
;
2298 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2299 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2300 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2301 instruction
->info
.load_store
.offset
.offset
= immediate
;
2303 snprintf(instruction
->text
, 128,
2304 "0x%8.8" PRIx32
" 0x%4.4x \t"
2305 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2306 address
, opcode
, Rd
, immediate
,
2307 thumb_alignpc4(address
) + immediate
);
2312 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2313 uint32_t address
, struct arm_instruction
*instruction
)
2315 uint8_t Rd
= (opcode
>> 0) & 0x7;
2316 uint8_t Rn
= (opcode
>> 3) & 0x7;
2317 uint8_t Rm
= (opcode
>> 6) & 0x7;
2318 uint8_t opc
= (opcode
>> 9) & 0x7;
2319 char *mnemonic
= NULL
;
2323 instruction
->type
= ARM_STR
;
2327 instruction
->type
= ARM_STRH
;
2331 instruction
->type
= ARM_STRB
;
2335 instruction
->type
= ARM_LDRSB
;
2339 instruction
->type
= ARM_LDR
;
2343 instruction
->type
= ARM_LDRH
;
2347 instruction
->type
= ARM_LDRB
;
2351 instruction
->type
= ARM_LDRSH
;
2356 snprintf(instruction
->text
, 128,
2357 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2358 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2360 instruction
->info
.load_store
.Rd
= Rd
;
2361 instruction
->info
.load_store
.Rn
= Rn
;
2362 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2363 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2364 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2369 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2370 uint32_t address
, struct arm_instruction
*instruction
)
2372 uint32_t offset
= (opcode
>> 6) & 0x1f;
2373 uint8_t Rd
= (opcode
>> 0) & 0x7;
2374 uint8_t Rn
= (opcode
>> 3) & 0x7;
2375 uint32_t L
= opcode
& (1 << 11);
2376 uint32_t B
= opcode
& (1 << 12);
2382 instruction
->type
= ARM_LDR
;
2385 instruction
->type
= ARM_STR
;
2389 if ((opcode
&0xF000) == 0x8000) {
2397 snprintf(instruction
->text
, 128,
2398 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2399 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2401 instruction
->info
.load_store
.Rd
= Rd
;
2402 instruction
->info
.load_store
.Rn
= Rn
;
2403 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2404 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2405 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2410 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2411 uint32_t address
, struct arm_instruction
*instruction
)
2413 uint32_t offset
= opcode
& 0xff;
2414 uint8_t Rd
= (opcode
>> 8) & 0x7;
2415 uint32_t L
= opcode
& (1 << 11);
2419 instruction
->type
= ARM_LDR
;
2422 instruction
->type
= ARM_STR
;
2426 snprintf(instruction
->text
, 128,
2427 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2428 address
, opcode
, mnemonic
, Rd
, offset
*4);
2430 instruction
->info
.load_store
.Rd
= Rd
;
2431 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2432 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2433 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2434 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2439 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2440 uint32_t address
, struct arm_instruction
*instruction
)
2442 uint32_t imm
= opcode
& 0xff;
2443 uint8_t Rd
= (opcode
>> 8) & 0x7;
2445 uint32_t SP
= opcode
& (1 << 11);
2446 const char *reg_name
;
2448 instruction
->type
= ARM_ADD
;
2458 snprintf(instruction
->text
, 128,
2459 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2460 address
, opcode
, Rd
, reg_name
, imm
* 4);
2462 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2463 instruction
->info
.data_proc
.Rd
= Rd
;
2464 instruction
->info
.data_proc
.Rn
= Rn
;
2465 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2470 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2471 uint32_t address
, struct arm_instruction
*instruction
)
2473 uint32_t imm
= opcode
& 0x7f;
2474 uint8_t opc
= opcode
& (1 << 7);
2479 instruction
->type
= ARM_SUB
;
2482 instruction
->type
= ARM_ADD
;
2486 snprintf(instruction
->text
, 128,
2487 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2488 address
, opcode
, mnemonic
, imm
*4);
2490 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2491 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2492 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2493 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2498 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2499 uint32_t address
, struct arm_instruction
*instruction
)
2501 uint32_t imm
= opcode
& 0xff;
2503 instruction
->type
= ARM_BKPT
;
2505 snprintf(instruction
->text
, 128,
2506 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2507 address
, opcode
, imm
);
2512 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2513 uint32_t address
, struct arm_instruction
*instruction
)
2515 uint32_t reg_list
= opcode
& 0xff;
2516 uint32_t L
= opcode
& (1 << 11);
2517 uint32_t R
= opcode
& (1 << 8);
2518 uint8_t Rn
= (opcode
>> 8) & 7;
2519 uint8_t addr_mode
= 0 /* IA */;
2523 char ptr_name
[7] = "";
2526 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2527 * The STMIA and LDMIA opcodes are used for other instructions.
2530 if ((opcode
& 0xf000) == 0xc000) { /* generic load/store multiple */
2534 instruction
->type
= ARM_LDM
;
2536 if (opcode
& (1 << Rn
))
2539 instruction
->type
= ARM_STM
;
2542 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2543 } else {/* push/pop */
2546 instruction
->type
= ARM_LDM
;
2549 reg_list
|= (1 << 15) /*PC*/;
2551 instruction
->type
= ARM_STM
;
2553 addr_mode
= 3; /*DB*/
2555 reg_list
|= (1 << 14) /*LR*/;
2559 reg_names_p
= reg_names
;
2560 for (i
= 0; i
<= 15; i
++) {
2561 if (reg_list
& (1 << i
))
2562 reg_names_p
+= snprintf(reg_names_p
,
2563 (reg_names
+ 40 - reg_names_p
),
2567 if (reg_names_p
> reg_names
)
2568 reg_names_p
[-2] = '\0';
2569 else /* invalid op : no registers */
2570 reg_names
[0] = '\0';
2572 snprintf(instruction
->text
, 128,
2573 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2574 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2576 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2577 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2578 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2583 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2584 uint32_t address
, struct arm_instruction
*instruction
)
2586 uint32_t offset
= opcode
& 0xff;
2587 uint8_t cond
= (opcode
>> 8) & 0xf;
2588 uint32_t target_address
;
2591 instruction
->type
= ARM_SWI
;
2592 snprintf(instruction
->text
, 128,
2593 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2594 address
, opcode
, offset
);
2596 } else if (cond
== 0xe) {
2597 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2598 snprintf(instruction
->text
, 128,
2599 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2604 /* sign extend 8-bit offset */
2605 if (offset
& 0x00000080)
2606 offset
= 0xffffff00 | offset
;
2608 target_address
= address
+ 4 + (offset
<< 1);
2610 snprintf(instruction
->text
, 128,
2611 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2613 arm_condition_strings
[cond
], target_address
);
2615 instruction
->type
= ARM_B
;
2616 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2617 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2622 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2623 struct arm_instruction
*instruction
)
2627 /* added in Thumb2 */
2628 offset
= (opcode
>> 3) & 0x1f;
2629 offset
|= (opcode
& 0x0200) >> 4;
2631 snprintf(instruction
->text
, 128,
2632 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2634 (opcode
& 0x0800) ? "N" : "",
2635 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2640 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2641 struct arm_instruction
*instruction
)
2643 /* added in ARMv6 */
2644 snprintf(instruction
->text
, 128,
2645 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2647 (opcode
& 0x0080) ? 'U' : 'S',
2648 (opcode
& 0x0040) ? 'B' : 'H',
2649 opcode
& 0x7, (opcode
>> 3) & 0x7);
2654 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2655 struct arm_instruction
*instruction
)
2657 /* added in ARMv6 */
2658 if ((opcode
& 0x0ff0) == 0x0650)
2659 snprintf(instruction
->text
, 128,
2660 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2662 (opcode
& 0x80) ? "BE" : "LE");
2663 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2664 snprintf(instruction
->text
, 128,
2665 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2667 (opcode
& 0x0010) ? 'D' : 'E',
2668 (opcode
& 0x0004) ? "A" : "",
2669 (opcode
& 0x0002) ? "I" : "",
2670 (opcode
& 0x0001) ? "F" : "");
2675 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2676 struct arm_instruction
*instruction
)
2680 /* added in ARMv6 */
2681 switch ((opcode
>> 6) & 3) {
2692 snprintf(instruction
->text
, 128,
2693 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2694 address
, opcode
, suffix
,
2695 opcode
& 0x7, (opcode
>> 3) & 0x7);
2700 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2701 struct arm_instruction
*instruction
)
2705 switch ((opcode
>> 4) & 0x0f) {
2722 hint
= "HINT (UNRECOGNIZED)";
2726 snprintf(instruction
->text
, 128,
2727 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2728 address
, opcode
, hint
);
2733 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2734 struct arm_instruction
*instruction
)
2736 unsigned cond
= (opcode
>> 4) & 0x0f;
2737 char *x
= "", *y
= "", *z
= "";
2740 z
= (opcode
& 0x02) ? "T" : "E";
2742 y
= (opcode
& 0x04) ? "T" : "E";
2744 x
= (opcode
& 0x08) ? "T" : "E";
2746 snprintf(instruction
->text
, 128,
2747 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2749 x
, y
, z
, arm_condition_strings
[cond
]);
2751 /* NOTE: strictly speaking, the next 1-4 instructions should
2752 * now be displayed with the relevant conditional suffix...
2758 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2760 /* clear fields, to avoid confusion */
2761 memset(instruction
, 0, sizeof(struct arm_instruction
));
2762 instruction
->opcode
= opcode
;
2763 instruction
->instruction_size
= 2;
2765 if ((opcode
& 0xe000) == 0x0000) {
2766 /* add/substract register or immediate */
2767 if ((opcode
& 0x1800) == 0x1800)
2768 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2769 /* shift by immediate */
2771 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2774 /* Add/substract/compare/move immediate */
2775 if ((opcode
& 0xe000) == 0x2000)
2776 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2778 /* Data processing instructions */
2779 if ((opcode
& 0xf800) == 0x4000)
2780 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2782 /* Load from literal pool */
2783 if ((opcode
& 0xf800) == 0x4800)
2784 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2786 /* Load/Store register offset */
2787 if ((opcode
& 0xf000) == 0x5000)
2788 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2790 /* Load/Store immediate offset */
2791 if (((opcode
& 0xe000) == 0x6000)
2792 || ((opcode
& 0xf000) == 0x8000))
2793 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2795 /* Load/Store from/to stack */
2796 if ((opcode
& 0xf000) == 0x9000)
2797 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2800 if ((opcode
& 0xf000) == 0xa000)
2801 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2804 if ((opcode
& 0xf000) == 0xb000) {
2805 switch ((opcode
>> 8) & 0x0f) {
2807 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2812 return evaluate_cb_thumb(opcode
, address
, instruction
);
2814 return evaluate_extend_thumb(opcode
, address
, instruction
);
2819 return evaluate_load_store_multiple_thumb(opcode
, address
,
2822 return evaluate_cps_thumb(opcode
, address
, instruction
);
2824 if ((opcode
& 0x00c0) == 0x0080)
2826 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2828 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2830 if (opcode
& 0x000f)
2831 return evaluate_ifthen_thumb(opcode
, address
,
2834 return evaluate_hint_thumb(opcode
, address
,
2838 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2839 snprintf(instruction
->text
, 128,
2840 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2845 /* Load/Store multiple */
2846 if ((opcode
& 0xf000) == 0xc000)
2847 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2849 /* Conditional branch + SWI */
2850 if ((opcode
& 0xf000) == 0xd000)
2851 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2853 if ((opcode
& 0xe000) == 0xe000) {
2854 /* Undefined instructions */
2855 if ((opcode
& 0xf801) == 0xe801) {
2856 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2857 snprintf(instruction
->text
, 128,
2858 "0x%8.8" PRIx32
" 0x%8.8x\t"
2859 "UNDEFINED INSTRUCTION",
2862 } else /* Branch to offset */
2863 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2866 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2870 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2871 struct arm_instruction
*instruction
, char *cp
)
2874 unsigned b21
= 1 << 21;
2875 unsigned b22
= 1 << 22;
2877 /* instead of combining two smaller 16-bit branch instructions,
2878 * Thumb2 uses only one larger 32-bit instruction.
2880 offset
= opcode
& 0x7ff;
2881 offset
|= (opcode
& 0x03ff0000) >> 5;
2882 if (opcode
& (1 << 26)) {
2883 offset
|= 0xff << 23;
2884 if ((opcode
& (1 << 11)) == 0)
2886 if ((opcode
& (1 << 13)) == 0)
2889 if (opcode
& (1 << 11))
2891 if (opcode
& (1 << 13))
2899 address
+= offset
<< 1;
2901 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2902 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2903 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2904 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2905 (opcode
& (1 << 14)) ? "BL" : "B.W",
2911 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2912 struct arm_instruction
*instruction
, char *cp
)
2915 unsigned b17
= 1 << 17;
2916 unsigned b18
= 1 << 18;
2917 unsigned cond
= (opcode
>> 22) & 0x0f;
2919 offset
= opcode
& 0x7ff;
2920 offset
|= (opcode
& 0x003f0000) >> 5;
2921 if (opcode
& (1 << 26)) {
2922 offset
|= 0x1fff << 19;
2923 if ((opcode
& (1 << 11)) == 0)
2925 if ((opcode
& (1 << 13)) == 0)
2928 if (opcode
& (1 << 11))
2930 if (opcode
& (1 << 13))
2937 address
+= offset
<< 1;
2939 instruction
->type
= ARM_B
;
2940 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2941 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2942 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2943 arm_condition_strings
[cond
],
2949 static const char *special_name(int number
)
2951 char *special
= "(RESERVED)";
2982 special
= "primask";
2985 special
= "basepri";
2988 special
= "basepri_max";
2991 special
= "faultmask";
2994 special
= "control";
3000 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
3001 struct arm_instruction
*instruction
, char *cp
)
3003 const char *mnemonic
;
3005 if (opcode
& 0x0700) {
3006 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3007 strcpy(cp
, "UNDEFINED");
3011 if (opcode
& 0x00f0) {
3012 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
3016 switch (opcode
& 0x0f) {
3021 mnemonic
= "YIELD.W";
3033 mnemonic
= "HINT.W (UNRECOGNIZED)";
3036 strcpy(cp
, mnemonic
);
3040 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3041 struct arm_instruction
*instruction
, char *cp
)
3043 const char *mnemonic
;
3045 switch ((opcode
>> 4) & 0x0f) {
3047 mnemonic
= "LEAVEX";
3050 mnemonic
= "ENTERX";
3065 return ERROR_COMMAND_SYNTAX_ERROR
;
3067 strcpy(cp
, mnemonic
);
3071 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3072 struct arm_instruction
*instruction
, char *cp
)
3074 /* permanently undefined */
3075 if ((opcode
& 0x07f07000) == 0x07f02000) {
3076 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3077 strcpy(cp
, "UNDEFINED");
3081 switch ((opcode
>> 12) & 0x5) {
3084 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3088 if (((opcode
>> 23) & 0x07) != 0x07)
3089 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3090 if (opcode
& (1 << 26))
3095 switch ((opcode
>> 20) & 0x7f) {
3098 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3099 (int) (opcode
>> 16) & 0x0f);
3102 return t2ev_hint(opcode
, address
, instruction
, cp
);
3104 return t2ev_misc(opcode
, address
, instruction
, cp
);
3106 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3110 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3111 special_name(opcode
& 0xff));
3116 return ERROR_COMMAND_SYNTAX_ERROR
;
3119 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3120 struct arm_instruction
*instruction
, char *cp
)
3122 char *mnemonic
= NULL
;
3123 int rn
= (opcode
>> 16) & 0xf;
3124 int rd
= (opcode
>> 8) & 0xf;
3125 unsigned immed
= opcode
& 0xff;
3131 /* ARMv7-M: A5.3.2 Modified immediate constants */
3132 func
= (opcode
>> 11) & 0x0e;
3135 if (opcode
& (1 << 26))
3138 /* "Modified" immediates */
3139 switch (func
>> 1) {
3146 immed
+= immed
<< 16;
3149 immed
+= immed
<< 8;
3150 immed
+= immed
<< 16;
3154 immed
= ror(immed
, func
);
3157 if (opcode
& (1 << 20))
3160 switch ((opcode
>> 21) & 0xf) {
3163 instruction
->type
= ARM_TST
;
3169 instruction
->type
= ARM_AND
;
3174 instruction
->type
= ARM_BIC
;
3179 instruction
->type
= ARM_MOV
;
3184 instruction
->type
= ARM_ORR
;
3190 instruction
->type
= ARM_MVN
;
3194 /* instruction->type = ARM_ORN; */
3200 instruction
->type
= ARM_TEQ
;
3206 instruction
->type
= ARM_EOR
;
3212 instruction
->type
= ARM_CMN
;
3218 instruction
->type
= ARM_ADD
;
3224 instruction
->type
= ARM_ADC
;
3229 instruction
->type
= ARM_SBC
;
3234 instruction
->type
= ARM_CMP
;
3240 instruction
->type
= ARM_SUB
;
3246 instruction
->type
= ARM_RSB
;
3251 return ERROR_COMMAND_SYNTAX_ERROR
;
3255 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3256 mnemonic
, suffix2
, rd
, immed
, immed
);
3258 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3259 mnemonic
, suffix
, suffix2
,
3260 rd
, rn
, immed
, immed
);
3265 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3266 struct arm_instruction
*instruction
, char *cp
)
3268 char *mnemonic
= NULL
;
3269 int rn
= (opcode
>> 16) & 0xf;
3270 int rd
= (opcode
>> 8) & 0xf;
3273 bool is_signed
= false;
3275 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3276 if (opcode
& (1 << 26))
3279 switch ((opcode
>> 20) & 0x1f) {
3288 immed
|= (opcode
>> 4) & 0xf000;
3289 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3297 /* move constant to top 16 bits of register */
3298 immed
|= (opcode
>> 4) & 0xf000;
3299 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3306 /* signed/unsigned saturated add */
3307 immed
= (opcode
>> 6) & 0x03;
3308 immed
|= (opcode
>> 10) & 0x1c;
3309 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3310 is_signed
? "S" : "U",
3311 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3312 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3313 immed
? immed
: 32);
3319 /* signed/unsigned bitfield extract */
3320 immed
= (opcode
>> 6) & 0x03;
3321 immed
|= (opcode
>> 10) & 0x1c;
3322 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3323 is_signed
? "S" : "U",
3325 (int) (opcode
& 0x1f) + 1);
3328 immed
= (opcode
>> 6) & 0x03;
3329 immed
|= (opcode
>> 10) & 0x1c;
3330 if (rn
== 0xf) /* bitfield clear */
3331 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3333 (int) (opcode
& 0x1f) + 1 - immed
);
3334 else /* bitfield insert */
3335 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3337 (int) (opcode
& 0x1f) + 1 - immed
);
3340 return ERROR_COMMAND_SYNTAX_ERROR
;
3343 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3344 rd
, rn
, immed
, immed
);
3348 address
= thumb_alignpc4(address
);
3353 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3354 * not hiding the pc-relative stuff will sometimes be useful.
3356 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3360 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3361 struct arm_instruction
*instruction
, char *cp
)
3363 unsigned op
= (opcode
>> 20) & 0xf;
3369 unsigned rn
= (opcode
>> 16) & 0x0f;
3370 unsigned rt
= (opcode
>> 12) & 0x0f;
3373 return ERROR_COMMAND_SYNTAX_ERROR
;
3375 if (opcode
& 0x0800)
3410 return ERROR_COMMAND_SYNTAX_ERROR
;
3413 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3414 size
, rt
, rn
, (int) opcode
& 0x0f,
3415 (int) (opcode
>> 4) & 0x03);
3419 immed
= opcode
& 0x0fff;
3420 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3421 size
, rt
, rn
, immed
, immed
);
3425 immed
= opcode
& 0x00ff;
3427 switch (opcode
& 0x700) {
3433 return ERROR_COMMAND_SYNTAX_ERROR
;
3436 /* two indexed modes will write back rn */
3437 if (opcode
& 0x100) {
3438 if (opcode
& 0x400) /* pre-indexed */
3440 else { /* post-indexed */
3446 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3447 size
, suffix
, rt
, rn
, p1
,
3448 (opcode
& 0x200) ? "" : "-",
3453 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3454 struct arm_instruction
*instruction
, char *cp
)
3456 int ra
= (opcode
>> 12) & 0xf;
3458 switch (opcode
& 0x007000f0) {
3461 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3462 (int) (opcode
>> 8) & 0xf,
3463 (int) (opcode
>> 16) & 0xf,
3464 (int) (opcode
>> 0) & 0xf);
3466 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3467 (int) (opcode
>> 8) & 0xf,
3468 (int) (opcode
>> 16) & 0xf,
3469 (int) (opcode
>> 0) & 0xf, ra
);
3472 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3473 (int) (opcode
>> 8) & 0xf,
3474 (int) (opcode
>> 16) & 0xf,
3475 (int) (opcode
>> 0) & 0xf, ra
);
3478 return ERROR_COMMAND_SYNTAX_ERROR
;
3483 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3484 struct arm_instruction
*instruction
, char *cp
)
3486 int op
= (opcode
>> 4) & 0xf;
3487 char *infix
= "MUL";
3489 op
+= (opcode
>> 16) & 0x70;
3497 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3498 (op
& 0x20) ? 'U' : 'S',
3500 (int) (opcode
>> 12) & 0xf,
3501 (int) (opcode
>> 8) & 0xf,
3502 (int) (opcode
>> 16) & 0xf,
3503 (int) (opcode
>> 0) & 0xf);
3507 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3508 (op
& 0x20) ? 'U' : 'S',
3509 (int) (opcode
>> 8) & 0xf,
3510 (int) (opcode
>> 16) & 0xf,
3511 (int) (opcode
>> 0) & 0xf);
3514 return ERROR_COMMAND_SYNTAX_ERROR
;
3520 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3521 struct arm_instruction
*instruction
, char *cp
)
3523 int rn
= (opcode
>> 16) & 0xf;
3524 int op
= (opcode
>> 22) & 0x6;
3525 int t
= (opcode
>> 21) & 1;
3526 unsigned registers
= opcode
& 0xffff;
3529 if (opcode
& (1 << 20))
3537 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3539 (unsigned) (opcode
& 0x1f));
3545 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3546 (unsigned) ((opcode
>> 16) & 0xf),
3550 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3554 sprintf(cp
, "POP.W\t");
3556 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3560 sprintf(cp
, "PUSH.W\t");
3562 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3565 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3568 return ERROR_COMMAND_SYNTAX_ERROR
;
3573 for (t
= 0; registers
; t
++, registers
>>= 1) {
3574 if ((registers
& 1) == 0)
3577 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3586 /* load/store dual or exclusive, table branch */
3587 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3588 struct arm_instruction
*instruction
, char *cp
)
3590 unsigned op1op2
= (opcode
>> 20) & 0x3;
3591 unsigned op3
= (opcode
>> 4) & 0xf;
3593 unsigned rn
= (opcode
>> 16) & 0xf;
3594 unsigned rt
= (opcode
>> 12) & 0xf;
3595 unsigned rd
= (opcode
>> 8) & 0xf;
3596 unsigned imm
= opcode
& 0xff;
3600 op1op2
|= (opcode
>> 21) & 0xc;
3630 mnemonic
= "STREXB";
3633 mnemonic
= "STREXH";
3636 return ERROR_COMMAND_SYNTAX_ERROR
;
3644 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3647 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3650 mnemonic
= "LDREXB";
3653 mnemonic
= "LDREXH";
3656 return ERROR_COMMAND_SYNTAX_ERROR
;
3661 return ERROR_COMMAND_SYNTAX_ERROR
;
3666 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3667 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3669 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3670 mnemonic
, rd
, rt
, rn
);
3676 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3677 mnemonic
, rt
, rn
, imm
, imm
);
3679 sprintf(cp
, "%s\tr%u, [r%u]",
3684 /* two indexed modes will write back rn */
3685 if (opcode
& (1 << 21)) {
3686 if (opcode
& (1 << 24)) /* pre-indexed */
3688 else { /* post-indexed */
3695 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3696 mnemonic
, rt
, rd
, rn
, p1
,
3697 (opcode
& (1 << 23)) ? "" : "-",
3702 address
= thumb_alignpc4(address
);
3704 if (opcode
& (1 << 23))
3708 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3709 mnemonic
, rt
, rd
, address
);
3713 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3714 struct arm_instruction
*instruction
, char *cp
)
3716 int op
= (opcode
>> 21) & 0xf;
3717 int rd
= (opcode
>> 8) & 0xf;
3718 int rn
= (opcode
>> 16) & 0xf;
3719 int type
= (opcode
>> 4) & 0x3;
3720 int immed
= (opcode
>> 6) & 0x3;
3724 immed
|= (opcode
>> 10) & 0x1c;
3725 if (opcode
& (1 << 20))
3731 if (!(opcode
& (1 << 20)))
3732 return ERROR_COMMAND_SYNTAX_ERROR
;
3733 instruction
->type
= ARM_TST
;
3738 instruction
->type
= ARM_AND
;
3742 instruction
->type
= ARM_BIC
;
3747 instruction
->type
= ARM_MOV
;
3751 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3753 (int) (opcode
& 0xf));
3766 sprintf(cp
, "RRX%s\tr%d, r%d",
3768 (int) (opcode
& 0xf));
3776 instruction
->type
= ARM_ORR
;
3782 instruction
->type
= ARM_MVN
;
3787 /* instruction->type = ARM_ORN; */
3793 if (!(opcode
& (1 << 20)))
3794 return ERROR_COMMAND_SYNTAX_ERROR
;
3795 instruction
->type
= ARM_TEQ
;
3800 instruction
->type
= ARM_EOR
;
3805 if (!(opcode
& (1 << 20)))
3806 return ERROR_COMMAND_SYNTAX_ERROR
;
3807 instruction
->type
= ARM_CMN
;
3812 instruction
->type
= ARM_ADD
;
3816 instruction
->type
= ARM_ADC
;
3820 instruction
->type
= ARM_SBC
;
3825 if (!(opcode
& (1 << 21)))
3826 return ERROR_COMMAND_SYNTAX_ERROR
;
3827 instruction
->type
= ARM_CMP
;
3832 instruction
->type
= ARM_SUB
;
3836 instruction
->type
= ARM_RSB
;
3840 return ERROR_COMMAND_SYNTAX_ERROR
;
3843 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3844 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3867 strcpy(cp
, ", RRX");
3873 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3877 sprintf(cp
, "%s%s.W\tr%d, r%d",
3878 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3882 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3883 mnemonic
, suffix
, rd
,
3884 (int) (opcode
& 0xf), immed
? immed
: 32);
3888 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3889 struct arm_instruction
*instruction
, char *cp
)
3894 if (((opcode
>> 4) & 0xf) == 0) {
3895 switch ((opcode
>> 21) & 0x7) {
3909 return ERROR_COMMAND_SYNTAX_ERROR
;
3912 instruction
->type
= ARM_MOV
;
3913 if (opcode
& (1 << 20))
3915 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3917 (int) (opcode
>> 8) & 0xf,
3918 (int) (opcode
>> 16) & 0xf,
3919 (int) (opcode
>> 0) & 0xf);
3921 } else if (opcode
& (1 << 7)) {
3922 switch ((opcode
>> 20) & 0xf) {
3927 switch ((opcode
>> 4) & 0x3) {
3929 suffix
= ", ROR #8";
3932 suffix
= ", ROR #16";
3935 suffix
= ", ROR #24";
3938 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3939 (opcode
& (1 << 24)) ? 'U' : 'S',
3940 (opcode
& (1 << 26)) ? 'B' : 'H',
3941 (int) (opcode
>> 8) & 0xf,
3942 (int) (opcode
>> 0) & 0xf,
3949 if (opcode
& (1 << 6))
3950 return ERROR_COMMAND_SYNTAX_ERROR
;
3951 if (((opcode
>> 12) & 0xf) != 0xf)
3952 return ERROR_COMMAND_SYNTAX_ERROR
;
3953 if (!(opcode
& (1 << 20)))
3954 return ERROR_COMMAND_SYNTAX_ERROR
;
3956 switch (((opcode
>> 19) & 0x04)
3957 | ((opcode
>> 4) & 0x3)) {
3962 mnemonic
= "REV16.W";
3968 mnemonic
= "REVSH.W";
3974 return ERROR_COMMAND_SYNTAX_ERROR
;
3976 sprintf(cp
, "%s\tr%d, r%d",
3978 (int) (opcode
>> 8) & 0xf,
3979 (int) (opcode
>> 0) & 0xf);
3982 return ERROR_COMMAND_SYNTAX_ERROR
;
3989 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3990 struct arm_instruction
*instruction
, char *cp
)
3992 int rn
= (opcode
>> 16) & 0xf;
3995 instruction
->type
= ARM_LDR
;
3998 immed
= opcode
& 0x0fff;
3999 if ((opcode
& (1 << 23)) == 0)
4001 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4002 (int) (opcode
>> 12) & 0xf,
4003 thumb_alignpc4(address
) + immed
);
4007 if (opcode
& (1 << 23)) {
4008 immed
= opcode
& 0x0fff;
4009 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4010 (int) (opcode
>> 12) & 0xf,
4015 if (!(opcode
& (0x3f << 6))) {
4016 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4017 (int) (opcode
>> 12) & 0xf,
4019 (int) (opcode
>> 0) & 0xf,
4020 (int) (opcode
>> 4) & 0x3);
4025 if (((opcode
>> 8) & 0xf) == 0xe) {
4026 immed
= opcode
& 0x00ff;
4028 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4029 (int) (opcode
>> 12) & 0xf,
4034 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4035 char *p1
= "]", *p2
= "";
4037 if (!(opcode
& 0x0500))
4038 return ERROR_COMMAND_SYNTAX_ERROR
;
4040 immed
= opcode
& 0x00ff;
4042 /* two indexed modes will write back rn */
4043 if (opcode
& 0x100) {
4044 if (opcode
& 0x400) /* pre-indexed */
4046 else { /* post-indexed */
4052 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4053 (int) (opcode
>> 12) & 0xf,
4055 (opcode
& 0x200) ? "" : "-",
4060 return ERROR_COMMAND_SYNTAX_ERROR
;
4063 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4064 struct arm_instruction
*instruction
, char *cp
)
4066 int rn
= (opcode
>> 16) & 0xf;
4067 int rt
= (opcode
>> 12) & 0xf;
4068 int op2
= (opcode
>> 6) & 0x3f;
4070 char *p1
= "", *p2
= "]";
4073 switch ((opcode
>> 23) & 0x3) {
4075 if ((rn
& rt
) == 0xf) {
4077 immed
= opcode
& 0xfff;
4078 address
= thumb_alignpc4(address
);
4079 if (opcode
& (1 << 23))
4083 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4087 if (rn
== 0x0f && rt
!= 0x0f) {
4089 immed
= opcode
& 0xfff;
4090 address
= thumb_alignpc4(address
);
4091 if (opcode
& (1 << 23))
4095 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4101 if ((op2
& 0x3c) == 0x38) {
4102 immed
= opcode
& 0xff;
4103 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4104 rt
, rn
, immed
, immed
);
4107 if ((op2
& 0x3c) == 0x30) {
4109 immed
= opcode
& 0xff;
4112 p1
= (opcode
& (1 << 21)) ? "W" : "";
4113 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4114 p1
, rn
, immed
, immed
);
4119 immed
= opcode
& 0xff;
4120 if (!(opcode
& 0x200))
4123 /* two indexed modes will write back rn */
4124 if (opcode
& 0x100) {
4125 if (opcode
& 0x400) /* pre-indexed */
4127 else { /* post-indexed */
4133 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4134 mnemonic
, rt
, rn
, p1
,
4138 if ((op2
& 0x24) == 0x24) {
4140 goto ldrxb_immediate_t3
;
4143 int rm
= opcode
& 0xf;
4146 sprintf(cp
, "PLD\t");
4148 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4149 immed
= (opcode
>> 4) & 0x3;
4151 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4156 if ((rn
& rt
) == 0xf)
4159 immed
= opcode
& 0xfff;
4160 goto preload_immediate
;
4164 mnemonic
= "LDRB.W";
4165 immed
= opcode
& 0xfff;
4166 goto ldrxb_immediate_t2
;
4168 if ((rn
& rt
) == 0xf) {
4169 immed
= opcode
& 0xfff;
4170 address
= thumb_alignpc4(address
);
4171 if (opcode
& (1 << 23))
4175 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4178 if (rn
== 0xf && rt
!= 0xf) {
4180 immed
= opcode
& 0xfff;
4181 address
= thumb_alignpc4(address
);
4182 if (opcode
& (1 << 23))
4186 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4191 if ((op2
& 0x3c) == 0x38) {
4192 immed
= opcode
& 0xff;
4193 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4194 rt
, rn
, immed
, immed
);
4197 if ((op2
& 0x3c) == 0x30) {
4199 immed
= opcode
& 0xff;
4200 immed
= -immed
; /* pli */
4201 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4206 goto ldrxb_immediate_t3
;
4208 if ((op2
& 0x24) == 0x24) {
4210 goto ldrxb_immediate_t3
;
4213 int rm
= opcode
& 0xf;
4216 sprintf(cp
, "PLI\t");
4218 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4219 immed
= (opcode
>> 4) & 0x3;
4221 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4227 immed
= opcode
& 0xfff;
4228 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4234 immed
= opcode
& 0xfff;
4236 goto ldrxb_immediate_t2
;
4239 return ERROR_COMMAND_SYNTAX_ERROR
;
4242 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4243 struct arm_instruction
*instruction
, char *cp
)
4245 int rn
= (opcode
>> 16) & 0xf;
4246 int rt
= (opcode
>> 12) & 0xf;
4247 int op2
= (opcode
>> 6) & 0x3f;
4252 sprintf(cp
, "HINT (UNALLOCATED)");
4256 if (opcode
& (1 << 24))
4259 if ((opcode
& (1 << 23)) == 0) {
4262 immed
= opcode
& 0xfff;
4263 address
= thumb_alignpc4(address
);
4264 if (opcode
& (1 << 23))
4268 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4273 int rm
= opcode
& 0xf;
4275 immed
= (opcode
>> 4) & 0x3;
4276 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4277 sign
, rt
, rn
, rm
, immed
);
4280 if ((op2
& 0x3c) == 0x38) {
4281 immed
= opcode
& 0xff;
4282 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4283 sign
, rt
, rn
, immed
, immed
);
4286 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4287 char *p1
= "", *p2
= "]";
4289 immed
= opcode
& 0xff;
4290 if (!(opcode
& 0x200))
4293 /* two indexed modes will write back rn */
4294 if (opcode
& 0x100) {
4295 if (opcode
& 0x400) /* pre-indexed */
4297 else { /* post-indexed */
4302 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4303 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4310 immed
= opcode
& 0xfff;
4311 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4312 sign
, *sign
? "" : ".W",
4313 rt
, rn
, immed
, immed
);
4317 return ERROR_COMMAND_SYNTAX_ERROR
;
4321 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4322 * always set. That means eventual arm_simulate_step() support for Thumb2
4323 * will need work in this area.
4325 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4332 /* clear low bit ... it's set on function pointers */
4335 /* clear fields, to avoid confusion */
4336 memset(instruction
, 0, sizeof(struct arm_instruction
));
4338 /* read first halfword, see if this is the only one */
4339 retval
= target_read_u16(target
, address
, &op
);
4340 if (retval
!= ERROR_OK
)
4343 switch (op
& 0xf800) {
4347 /* 32-bit instructions */
4348 instruction
->instruction_size
= 4;
4350 retval
= target_read_u16(target
, address
+ 2, &op
);
4351 if (retval
!= ERROR_OK
)
4354 instruction
->opcode
= opcode
;
4357 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4358 return thumb_evaluate_opcode(op
, address
, instruction
);
4361 snprintf(instruction
->text
, 128,
4362 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4364 cp
= strchr(instruction
->text
, 0);
4365 retval
= ERROR_FAIL
;
4367 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4368 if ((opcode
& 0x1a008000) == 0x10000000)
4369 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4371 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4372 else if ((opcode
& 0x1a008000) == 0x12000000)
4373 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4375 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4376 else if ((opcode
& 0x18008000) == 0x10008000)
4377 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4379 /* ARMv7-M: A5.3.5 Load/store multiple */
4380 else if ((opcode
& 0x1e400000) == 0x08000000)
4381 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4383 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4384 else if ((opcode
& 0x1e400000) == 0x08400000)
4385 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4387 /* ARMv7-M: A5.3.7 Load word */
4388 else if ((opcode
& 0x1f700000) == 0x18500000)
4389 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4391 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4392 else if ((opcode
& 0x1e700000) == 0x18300000)
4393 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4395 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4396 else if ((opcode
& 0x1e700000) == 0x18100000)
4397 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4399 /* ARMv7-M: A5.3.10 Store single data item */
4400 else if ((opcode
& 0x1f100000) == 0x18000000)
4401 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4403 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4404 else if ((opcode
& 0x1e000000) == 0x0a000000)
4405 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4407 /* ARMv7-M: A5.3.12 Data processing (register)
4408 * and A5.3.13 Miscellaneous operations
4410 else if ((opcode
& 0x1f000000) == 0x1a000000)
4411 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4413 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4414 else if ((opcode
& 0x1f800000) == 0x1b000000)
4415 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4417 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4418 else if ((opcode
& 0x1f800000) == 0x1b800000)
4419 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4421 if (retval
== ERROR_OK
)
4425 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4426 * instructions; not yet handled here.
4429 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4430 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4431 strcpy(cp
, "UNDEFINED OPCODE");
4435 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4438 strcpy(cp
, "(32-bit Thumb2 ...)");
4442 int arm_access_size(struct arm_instruction
*instruction
)
4444 if ((instruction
->type
== ARM_LDRB
)
4445 || (instruction
->type
== ARM_LDRBT
)
4446 || (instruction
->type
== ARM_LDRSB
)
4447 || (instruction
->type
== ARM_STRB
)
4448 || (instruction
->type
== ARM_STRBT
))
4450 else if ((instruction
->type
== ARM_LDRH
)
4451 || (instruction
->type
== ARM_LDRSH
)
4452 || (instruction
->type
== ARM_STRH
))
4454 else if ((instruction
->type
== ARM_LDR
)
4455 || (instruction
->type
== ARM_LDRT
)
4456 || (instruction
->type
== ARM_STR
)
4457 || (instruction
->type
== ARM_STRT
))
4459 else if ((instruction
->type
== ARM_LDRD
)
4460 || (instruction
->type
== ARM_STRD
))
4463 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction",
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)