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, see <http://www.gnu.org/licenses/>. *
19 ***************************************************************************/
26 #include "arm_disassembler.h"
27 #include <helper/log.h>
30 * This disassembler supports two main functions for OpenOCD:
32 * - Various "disassemble" commands. OpenOCD can serve as a
33 * machine-language debugger, without help from GDB.
35 * - Single stepping. Not all ARM cores support hardware single
36 * stepping. To work without that support, the debugger must
37 * be able to decode instructions to find out where to put a
38 * "next instruction" breakpoint.
40 * In addition, interpretation of ETM trace data needs some of the
41 * decoding mechanisms.
43 * At this writing (September 2009) neither function is complete.
46 * * Old-style syntax (not UAL) is generally used
47 * * VFP instructions are not understood (ARMv5 and later)
48 * except as coprocessor 10/11 operations
49 * * Most ARM instructions through ARMv6 are decoded, but some
50 * of the post-ARMv4 opcodes may not be handled yet
51 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
52 * * NEON instructions are not understood (ARMv7-A)
54 * - Thumb/Thumb2 decoding
55 * * UAL syntax should be consistently used
56 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
57 * be handled properly. Accordingly, so should the subset
58 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
60 * * Conditional effects of Thumb2 "IT" (if-then) instructions
61 * are not handled: the affected instructions are not shown
62 * with their now-conditional suffixes.
63 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
64 * handled (minimally for coprocessor access).
65 * * SIMD instructions, and some other Thumb2 instructions
66 * from ARMv7-A, are not understood.
69 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
70 * * Opcodes changed by ThumbEE mode are not handled; these
71 * instructions wrongly decode as LDM and STM.
73 * - Jazelle decoding ... no support whatsoever for Jazelle mode
74 * or decoding. ARM encourages use of the more generic ThumbEE
75 * mode, instead of Jazelle mode, in current chips.
77 * - Single-step/emulation ... spotty support, which is only weakly
78 * tested. Thumb2 is not supported. (Arguably a full simulator
79 * is not needed to support just single stepping. Recognizing
80 * branch vs non-branch instructions suffices, except when the
81 * instruction faults and triggers a synchronous exception which
82 * can be intercepted using other means.)
84 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
85 * ARM v7-R edition" gives the most complete coverage of the various
86 * generations of ARM instructions. At this writing it is publicly
87 * accessible to anyone willing to create an account at the ARM
88 * web site; see http://www.arm.com/documentation/ for information.
90 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
91 * more details relevant to the Thumb2-only processors (such as
92 * the Cortex-M implementations).
95 /* textual represenation of the condition field
96 * ALways (default) is ommitted (empty string) */
97 static const char *arm_condition_strings
[] = {
98 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
101 /* make up for C's missing ROR */
102 static uint32_t ror(uint32_t value
, int places
)
104 return (value
>> places
) | (value
<< (32 - places
));
107 static int evaluate_unknown(uint32_t opcode
,
108 uint32_t address
, struct arm_instruction
*instruction
)
110 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
111 snprintf(instruction
->text
, 128,
112 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
113 "\tUNDEFINED INSTRUCTION", address
, opcode
);
117 static int evaluate_pld(uint32_t opcode
,
118 uint32_t address
, struct arm_instruction
*instruction
)
121 if ((opcode
& 0x0d70f000) == 0x0550f000) {
122 instruction
->type
= ARM_PLD
;
124 snprintf(instruction
->text
,
126 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...",
132 return evaluate_unknown(opcode
, address
, instruction
);
135 static int evaluate_srs(uint32_t opcode
,
136 uint32_t address
, struct arm_instruction
*instruction
)
138 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
139 const char *mode
= "";
141 switch ((opcode
>> 23) & 0x3) {
146 /* "IA" is default */
156 switch (opcode
& 0x0e500000) {
158 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
160 "\tSRS%s\tSP%s, #%d",
163 (unsigned)(opcode
& 0x1f));
166 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
171 (unsigned)((opcode
>> 16) & 0xf), wback
);
174 return evaluate_unknown(opcode
, address
, instruction
);
179 static int evaluate_swi(uint32_t opcode
,
180 uint32_t address
, struct arm_instruction
*instruction
)
182 instruction
->type
= ARM_SWI
;
184 snprintf(instruction
->text
, 128,
185 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
186 address
, opcode
, (opcode
& 0xffffff));
191 static int evaluate_blx_imm(uint32_t opcode
,
192 uint32_t address
, struct arm_instruction
*instruction
)
196 uint32_t target_address
;
198 instruction
->type
= ARM_BLX
;
199 immediate
= opcode
& 0x00ffffff;
201 /* sign extend 24-bit immediate */
202 if (immediate
& 0x00800000)
203 offset
= 0xff000000 | immediate
;
207 /* shift two bits left */
210 /* odd/event halfword */
211 if (opcode
& 0x01000000)
214 target_address
= address
+ 8 + offset
;
216 snprintf(instruction
->text
,
218 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"",
223 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
224 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
229 static int evaluate_b_bl(uint32_t opcode
,
230 uint32_t address
, struct arm_instruction
*instruction
)
235 uint32_t target_address
;
237 immediate
= opcode
& 0x00ffffff;
238 L
= (opcode
& 0x01000000) >> 24;
240 /* sign extend 24-bit immediate */
241 if (immediate
& 0x00800000)
242 offset
= 0xff000000 | immediate
;
246 /* shift two bits left */
249 target_address
= address
+ 8 + offset
;
252 instruction
->type
= ARM_BL
;
254 instruction
->type
= ARM_B
;
256 snprintf(instruction
->text
,
258 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
,
265 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
266 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
271 /* Coprocessor load/store and double register transfers
272 * both normal and extended instruction space (condition field b1111) */
273 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
274 uint32_t address
, struct arm_instruction
*instruction
)
276 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
279 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c500000)) {
280 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
283 cp_opcode
= (opcode
& 0xf0) >> 4;
284 Rd
= (opcode
& 0xf000) >> 12;
285 Rn
= (opcode
& 0xf0000) >> 16;
286 CRm
= (opcode
& 0xf);
289 if ((opcode
& 0x0ff00000) == 0x0c400000) {
290 instruction
->type
= ARM_MCRR
;
292 } else if ((opcode
& 0x0ff00000) == 0x0c500000) {
294 instruction
->type
= ARM_MRRC
;
297 LOG_ERROR("Unknown instruction");
301 snprintf(instruction
->text
, 128,
302 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
303 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
304 address
, opcode
, mnemonic
,
305 ((opcode
& 0xf0000000) == 0xf0000000)
306 ? "2" : COND(opcode
),
307 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
308 } else {/* LDC or STC */
309 uint8_t CRd
, Rn
, offset
;
312 char addressing_mode
[32];
314 CRd
= (opcode
& 0xf000) >> 12;
315 Rn
= (opcode
& 0xf0000) >> 16;
316 offset
= (opcode
& 0xff) << 2;
319 if (opcode
& 0x00100000) {
320 instruction
->type
= ARM_LDC
;
323 instruction
->type
= ARM_STC
;
327 U
= (opcode
& 0x00800000) >> 23;
329 /* addressing modes */
330 if ((opcode
& 0x01200000) == 0x01000000)/* offset */
331 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
332 Rn
, U
? "" : "-", offset
);
333 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
334 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
335 Rn
, U
? "" : "-", offset
);
336 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
337 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
338 Rn
, U
? "" : "-", offset
);
339 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
340 snprintf(addressing_mode
, 32, "[r%i], {%d}",
343 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
345 "\t%s%s%s p%i, c%i, %s",
346 address
, opcode
, mnemonic
,
347 ((opcode
& 0xf0000000) == 0xf0000000)
348 ? "2" : COND(opcode
),
349 (opcode
& (1 << 22)) ? "L" : "",
350 cp_num
, CRd
, addressing_mode
);
356 /* Coprocessor data processing instructions
357 * Coprocessor register transfer instructions
358 * both normal and extended instruction space (condition field b1111) */
359 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
360 uint32_t address
, struct arm_instruction
*instruction
)
364 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
366 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
367 cp_num
= (opcode
& 0xf00) >> 8;
368 CRd_Rd
= (opcode
& 0xf000) >> 12;
369 CRn
= (opcode
& 0xf0000) >> 16;
370 CRm
= (opcode
& 0xf);
371 opcode_2
= (opcode
& 0xe0) >> 5;
374 if (opcode
& 0x00000010) { /* bit 4 set -> MRC/MCR */
375 if (opcode
& 0x00100000) { /* bit 20 set -> MRC */
376 instruction
->type
= ARM_MRC
;
378 } else {/* bit 20 not set -> MCR */
379 instruction
->type
= ARM_MCR
;
383 opcode_1
= (opcode
& 0x00e00000) >> 21;
385 snprintf(instruction
->text
,
387 "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",
398 } else {/* bit 4 not set -> CDP */
399 instruction
->type
= ARM_CDP
;
402 opcode_1
= (opcode
& 0x00f00000) >> 20;
404 snprintf(instruction
->text
,
406 "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",
422 /* Load/store instructions */
423 static int evaluate_load_store(uint32_t opcode
,
424 uint32_t address
, struct arm_instruction
*instruction
)
426 uint8_t I
, P
, U
, B
, W
, L
;
428 char *operation
;/* "LDR" or "STR" */
429 char *suffix
; /* "", "B", "T", "BT" */
433 I
= (opcode
& 0x02000000) >> 25;
434 P
= (opcode
& 0x01000000) >> 24;
435 U
= (opcode
& 0x00800000) >> 23;
436 B
= (opcode
& 0x00400000) >> 22;
437 W
= (opcode
& 0x00200000) >> 21;
438 L
= (opcode
& 0x00100000) >> 20;
440 /* target register */
441 Rd
= (opcode
& 0xf000) >> 12;
444 Rn
= (opcode
& 0xf0000) >> 16;
446 instruction
->info
.load_store
.Rd
= Rd
;
447 instruction
->info
.load_store
.Rn
= Rn
;
448 instruction
->info
.load_store
.U
= U
;
450 /* determine operation */
456 /* determine instruction type and suffix */
458 if ((P
== 0) && (W
== 1)) {
460 instruction
->type
= ARM_LDRBT
;
462 instruction
->type
= ARM_STRBT
;
466 instruction
->type
= ARM_LDRB
;
468 instruction
->type
= ARM_STRB
;
472 if ((P
== 0) && (W
== 1)) {
474 instruction
->type
= ARM_LDRT
;
476 instruction
->type
= ARM_STRT
;
480 instruction
->type
= ARM_LDR
;
482 instruction
->type
= ARM_STR
;
487 if (!I
) { /* #+-<offset_12> */
488 uint32_t offset_12
= (opcode
& 0xfff);
490 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
492 snprintf(offset
, 32, "%s", "");
494 instruction
->info
.load_store
.offset_mode
= 0;
495 instruction
->info
.load_store
.offset
.offset
= offset_12
;
496 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
497 uint8_t shift_imm
, shift
;
500 shift_imm
= (opcode
& 0xf80) >> 7;
501 shift
= (opcode
& 0x60) >> 5;
504 /* LSR encodes a shift by 32 bit as 0x0 */
505 if ((shift
== 0x1) && (shift_imm
== 0x0))
508 /* ASR encodes a shift by 32 bit as 0x0 */
509 if ((shift
== 0x2) && (shift_imm
== 0x0))
512 /* ROR by 32 bit is actually a RRX */
513 if ((shift
== 0x3) && (shift_imm
== 0x0))
516 instruction
->info
.load_store
.offset_mode
= 1;
517 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
518 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
519 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
521 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
522 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
523 else { /* +-<Rm>, <Shift>, #<shift_imm> */
526 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
529 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
532 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
535 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
538 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
545 if (W
== 0) { /* offset */
546 snprintf(instruction
->text
,
548 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
558 instruction
->info
.load_store
.index_mode
= 0;
559 } else {/* pre-indexed */
560 snprintf(instruction
->text
,
562 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
572 instruction
->info
.load_store
.index_mode
= 1;
574 } else {/* post-indexed */
575 snprintf(instruction
->text
,
577 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
587 instruction
->info
.load_store
.index_mode
= 2;
593 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
595 unsigned rm
= (opcode
>> 0) & 0xf;
596 unsigned rd
= (opcode
>> 12) & 0xf;
597 unsigned rn
= (opcode
>> 16) & 0xf;
600 switch ((opcode
>> 24) & 0x3) {
605 sprintf(cp
, "UNDEFINED");
606 return ARM_UNDEFINED_INSTRUCTION
;
615 switch ((opcode
>> 10) & 0x3) {
631 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
632 (opcode
& (1 << 22)) ? 'U' : 'S',
637 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
638 (opcode
& (1 << 22)) ? 'U' : 'S',
645 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
651 switch ((opcode
>> 20) & 0x7) {
674 switch ((opcode
>> 5) & 0x7) {
703 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
704 (int) (opcode
>> 12) & 0xf,
705 (int) (opcode
>> 16) & 0xf,
706 (int) (opcode
>> 0) & 0xf);
710 /* these opcodes might be used someday */
711 sprintf(cp
, "UNDEFINED");
712 return ARM_UNDEFINED_INSTRUCTION
;
715 /* ARMv6 and later support "media" instructions (includes SIMD) */
716 static int evaluate_media(uint32_t opcode
, uint32_t address
,
717 struct arm_instruction
*instruction
)
719 char *cp
= instruction
->text
;
720 char *mnemonic
= NULL
;
723 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
727 /* parallel add/subtract */
728 if ((opcode
& 0x01800000) == 0x00000000) {
729 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
734 if ((opcode
& 0x01f00020) == 0x00800000) {
736 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
738 if (opcode
& (1 << 6)) {
747 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
749 (int) (opcode
>> 12) & 0xf,
750 (int) (opcode
>> 16) & 0xf,
751 (int) (opcode
>> 0) & 0xf,
757 if ((opcode
& 0x01a00020) == 0x00a00000) {
759 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
761 if (opcode
& (1 << 6)) {
768 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
769 (opcode
& (1 << 22)) ? 'U' : 'S',
771 (int) (opcode
>> 12) & 0xf,
772 (int) (opcode
>> 16) & 0x1f,
773 (int) (opcode
>> 0) & 0xf,
779 if ((opcode
& 0x018000f0) == 0x00800070) {
780 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
785 if ((opcode
& 0x01f00080) == 0x01000000) {
786 unsigned rn
= (opcode
>> 12) & 0xf;
789 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
790 (opcode
& (1 << 6)) ? 'S' : 'A',
791 (opcode
& (1 << 5)) ? "X" : "",
793 (int) (opcode
>> 16) & 0xf,
794 (int) (opcode
>> 0) & 0xf,
795 (int) (opcode
>> 8) & 0xf,
798 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
799 (opcode
& (1 << 6)) ? 'S' : 'A',
800 (opcode
& (1 << 5)) ? "X" : "",
802 (int) (opcode
>> 16) & 0xf,
803 (int) (opcode
>> 0) & 0xf,
804 (int) (opcode
>> 8) & 0xf);
807 if ((opcode
& 0x01f00000) == 0x01400000) {
808 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
809 (opcode
& (1 << 6)) ? 'S' : 'A',
810 (opcode
& (1 << 5)) ? "X" : "",
812 (int) (opcode
>> 12) & 0xf,
813 (int) (opcode
>> 16) & 0xf,
814 (int) (opcode
>> 0) & 0xf,
815 (int) (opcode
>> 8) & 0xf);
818 if ((opcode
& 0x01f00000) == 0x01500000) {
819 unsigned rn
= (opcode
>> 12) & 0xf;
821 switch (opcode
& 0xc0) {
833 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
834 (opcode
& (1 << 6)) ? 'S' : 'A',
835 (opcode
& (1 << 5)) ? "R" : "",
837 (int) (opcode
>> 16) & 0xf,
838 (int) (opcode
>> 0) & 0xf,
839 (int) (opcode
>> 8) & 0xf,
842 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
843 (opcode
& (1 << 5)) ? "R" : "",
845 (int) (opcode
>> 16) & 0xf,
846 (int) (opcode
>> 0) & 0xf,
847 (int) (opcode
>> 8) & 0xf);
851 /* simple matches against the remaining decode bits */
852 switch (opcode
& 0x01f000f0) {
855 /* parallel halfword saturate */
856 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
857 (opcode
& (1 << 22)) ? 'U' : 'S',
859 (int) (opcode
>> 12) & 0xf,
860 (int) (opcode
>> 16) & 0xf,
861 (int) (opcode
>> 0) & 0xf);
874 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
875 (int) (opcode
>> 12) & 0xf,
876 (int) (opcode
>> 16) & 0xf,
877 (int) (opcode
>> 0) & 0xf);
880 /* unsigned sum of absolute differences */
881 if (((opcode
>> 12) & 0xf) == 0xf)
882 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
883 (int) (opcode
>> 16) & 0xf,
884 (int) (opcode
>> 0) & 0xf,
885 (int) (opcode
>> 8) & 0xf);
887 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
888 (int) (opcode
>> 16) & 0xf,
889 (int) (opcode
>> 0) & 0xf,
890 (int) (opcode
>> 8) & 0xf,
891 (int) (opcode
>> 12) & 0xf);
895 unsigned rm
= (opcode
>> 0) & 0xf;
896 unsigned rd
= (opcode
>> 12) & 0xf;
898 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
903 /* these opcodes might be used someday */
904 sprintf(cp
, "UNDEFINED");
908 /* Miscellaneous load/store instructions */
909 static int evaluate_misc_load_store(uint32_t opcode
,
910 uint32_t address
, struct arm_instruction
*instruction
)
912 uint8_t P
, U
, I
, W
, L
, S
, H
;
914 char *operation
;/* "LDR" or "STR" */
915 char *suffix
; /* "H", "SB", "SH", "D" */
919 P
= (opcode
& 0x01000000) >> 24;
920 U
= (opcode
& 0x00800000) >> 23;
921 I
= (opcode
& 0x00400000) >> 22;
922 W
= (opcode
& 0x00200000) >> 21;
923 L
= (opcode
& 0x00100000) >> 20;
924 S
= (opcode
& 0x00000040) >> 6;
925 H
= (opcode
& 0x00000020) >> 5;
927 /* target register */
928 Rd
= (opcode
& 0xf000) >> 12;
931 Rn
= (opcode
& 0xf0000) >> 16;
933 instruction
->info
.load_store
.Rd
= Rd
;
934 instruction
->info
.load_store
.Rn
= Rn
;
935 instruction
->info
.load_store
.U
= U
;
937 /* determine instruction type and suffix */
942 instruction
->type
= ARM_LDRSH
;
946 instruction
->type
= ARM_LDRSB
;
949 } else {/* there are no signed stores, so this is used to encode double-register
954 instruction
->type
= ARM_STRD
;
957 instruction
->type
= ARM_LDRD
;
960 } else {/* unsigned */
964 instruction
->type
= ARM_LDRH
;
967 instruction
->type
= ARM_STRH
;
971 if (I
) {/* Immediate offset/index (#+-<offset_8>)*/
972 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
973 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
975 instruction
->info
.load_store
.offset_mode
= 0;
976 instruction
->info
.load_store
.offset
.offset
= offset_8
;
977 } else {/* Register offset/index (+-<Rm>) */
980 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
982 instruction
->info
.load_store
.offset_mode
= 1;
983 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
984 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
985 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
989 if (W
== 0) { /* offset */
990 snprintf(instruction
->text
,
992 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
1002 instruction
->info
.load_store
.index_mode
= 0;
1003 } else {/* pre-indexed */
1004 snprintf(instruction
->text
,
1006 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1016 instruction
->info
.load_store
.index_mode
= 1;
1018 } else {/* post-indexed */
1019 snprintf(instruction
->text
,
1021 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1031 instruction
->info
.load_store
.index_mode
= 2;
1037 /* Load/store multiples instructions */
1038 static int evaluate_ldm_stm(uint32_t opcode
,
1039 uint32_t address
, struct arm_instruction
*instruction
)
1041 uint8_t P
, U
, S
, W
, L
, Rn
;
1042 uint32_t register_list
;
1043 char *addressing_mode
;
1050 P
= (opcode
& 0x01000000) >> 24;
1051 U
= (opcode
& 0x00800000) >> 23;
1052 S
= (opcode
& 0x00400000) >> 22;
1053 W
= (opcode
& 0x00200000) >> 21;
1054 L
= (opcode
& 0x00100000) >> 20;
1055 register_list
= (opcode
& 0xffff);
1056 Rn
= (opcode
& 0xf0000) >> 16;
1058 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1059 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1060 instruction
->info
.load_store_multiple
.S
= S
;
1061 instruction
->info
.load_store_multiple
.W
= W
;
1064 instruction
->type
= ARM_LDM
;
1067 instruction
->type
= ARM_STM
;
1073 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1074 addressing_mode
= "IB";
1076 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1077 addressing_mode
= "DB";
1081 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1082 /* "IA" is the default in UAL syntax */
1083 addressing_mode
= "";
1085 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1086 addressing_mode
= "DA";
1090 reg_list_p
= reg_list
;
1091 for (i
= 0; i
<= 15; i
++) {
1092 if ((register_list
>> i
) & 1) {
1095 reg_list_p
+= snprintf(reg_list_p
,
1096 (reg_list
+ 69 - reg_list_p
),
1100 reg_list_p
+= snprintf(reg_list_p
,
1101 (reg_list
+ 69 - reg_list_p
),
1107 snprintf(instruction
->text
, 128,
1108 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1109 "\t%s%s%s r%i%s, {%s}%s",
1111 mnemonic
, addressing_mode
, COND(opcode
),
1112 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1117 /* Multiplies, extra load/stores */
1118 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1119 uint32_t address
, struct arm_instruction
*instruction
)
1121 /* Multiply (accumulate) (long) and Swap/swap byte */
1122 if ((opcode
& 0x000000f0) == 0x00000090) {
1123 /* Multiply (accumulate) */
1124 if ((opcode
& 0x0f800000) == 0x00000000) {
1125 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1127 Rs
= (opcode
& 0xf00) >> 8;
1128 Rn
= (opcode
& 0xf000) >> 12;
1129 Rd
= (opcode
& 0xf0000) >> 16;
1130 S
= (opcode
& 0x00100000) >> 20;
1132 /* examine A bit (accumulate) */
1133 if (opcode
& 0x00200000) {
1134 instruction
->type
= ARM_MLA
;
1135 snprintf(instruction
->text
,
1137 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1147 instruction
->type
= ARM_MUL
;
1148 snprintf(instruction
->text
,
1150 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1163 /* Multiply (accumulate) long */
1164 if ((opcode
& 0x0f800000) == 0x00800000) {
1165 char *mnemonic
= NULL
;
1166 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1168 Rs
= (opcode
& 0xf00) >> 8;
1169 RdHi
= (opcode
& 0xf000) >> 12;
1170 RdLow
= (opcode
& 0xf0000) >> 16;
1171 S
= (opcode
& 0x00100000) >> 20;
1173 switch ((opcode
& 0x00600000) >> 21) {
1175 instruction
->type
= ARM_UMULL
;
1179 instruction
->type
= ARM_UMLAL
;
1183 instruction
->type
= ARM_SMULL
;
1187 instruction
->type
= ARM_SMLAL
;
1192 snprintf(instruction
->text
,
1194 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1208 /* Swap/swap byte */
1209 if ((opcode
& 0x0f800000) == 0x01000000) {
1212 Rd
= (opcode
& 0xf000) >> 12;
1213 Rn
= (opcode
& 0xf0000) >> 16;
1215 /* examine B flag */
1216 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1218 snprintf(instruction
->text
,
1220 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1223 (opcode
& 0x00400000) ? "SWPB" : "SWP",
1233 return evaluate_misc_load_store(opcode
, address
, instruction
);
1236 static int evaluate_mrs_msr(uint32_t opcode
,
1237 uint32_t address
, struct arm_instruction
*instruction
)
1239 int R
= (opcode
& 0x00400000) >> 22;
1240 char *PSR
= (R
) ? "SPSR" : "CPSR";
1242 /* Move register to status register (MSR) */
1243 if (opcode
& 0x00200000) {
1244 instruction
->type
= ARM_MSR
;
1246 /* immediate variant */
1247 if (opcode
& 0x02000000) {
1248 uint8_t immediate
= (opcode
& 0xff);
1249 uint8_t rotate
= (opcode
& 0xf00);
1251 snprintf(instruction
->text
,
1253 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1258 (opcode
& 0x10000) ? "c" : "",
1259 (opcode
& 0x20000) ? "x" : "",
1260 (opcode
& 0x40000) ? "s" : "",
1261 (opcode
& 0x80000) ? "f" : "",
1262 ror(immediate
, (rotate
* 2))
1264 } else {/* register variant */
1265 uint8_t Rm
= opcode
& 0xf;
1266 snprintf(instruction
->text
,
1268 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1273 (opcode
& 0x10000) ? "c" : "",
1274 (opcode
& 0x20000) ? "x" : "",
1275 (opcode
& 0x40000) ? "s" : "",
1276 (opcode
& 0x80000) ? "f" : "",
1281 } else {/* Move status register to register (MRS) */
1284 instruction
->type
= ARM_MRS
;
1285 Rd
= (opcode
& 0x0000f000) >> 12;
1287 snprintf(instruction
->text
,
1289 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1300 /* Miscellaneous instructions */
1301 static int evaluate_misc_instr(uint32_t opcode
,
1302 uint32_t address
, struct arm_instruction
*instruction
)
1305 if ((opcode
& 0x000000f0) == 0x00000000)
1306 evaluate_mrs_msr(opcode
, address
, instruction
);
1309 if ((opcode
& 0x006000f0) == 0x00200010) {
1311 instruction
->type
= ARM_BX
;
1314 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1315 address
, opcode
, COND(opcode
), Rm
);
1317 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1318 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1321 /* BXJ - "Jazelle" support (ARMv5-J) */
1322 if ((opcode
& 0x006000f0) == 0x00200020) {
1324 instruction
->type
= ARM_BX
;
1327 snprintf(instruction
->text
, 128,
1328 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1329 address
, opcode
, COND(opcode
), Rm
);
1331 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1332 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1336 if ((opcode
& 0x006000f0) == 0x00600010) {
1338 instruction
->type
= ARM_CLZ
;
1340 Rd
= (opcode
& 0xf000) >> 12;
1342 snprintf(instruction
->text
,
1344 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1353 if ((opcode
& 0x006000f0) == 0x00200030) {
1355 instruction
->type
= ARM_BLX
;
1358 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1359 address
, opcode
, COND(opcode
), Rm
);
1361 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1362 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1365 /* Enhanced DSP add/subtracts */
1366 if ((opcode
& 0x0000000f0) == 0x00000050) {
1368 char *mnemonic
= NULL
;
1370 Rd
= (opcode
& 0xf000) >> 12;
1371 Rn
= (opcode
& 0xf0000) >> 16;
1373 switch ((opcode
& 0x00600000) >> 21) {
1375 instruction
->type
= ARM_QADD
;
1379 instruction
->type
= ARM_QSUB
;
1383 instruction
->type
= ARM_QDADD
;
1387 instruction
->type
= ARM_QDSUB
;
1392 snprintf(instruction
->text
,
1394 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1404 /* exception return */
1405 if ((opcode
& 0x0000000f0) == 0x00000060) {
1406 if (((opcode
& 0x600000) >> 21) == 3)
1407 instruction
->type
= ARM_ERET
;
1408 snprintf(instruction
->text
,
1410 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tERET",
1415 /* exception generate instructions */
1416 if ((opcode
& 0x0000000f0) == 0x00000070) {
1417 uint32_t immediate
= 0;
1418 char *mnemonic
= NULL
;
1420 switch ((opcode
& 0x600000) >> 21) {
1422 instruction
->type
= ARM_BKPT
;
1424 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1427 instruction
->type
= ARM_HVC
;
1429 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1432 instruction
->type
= ARM_SMC
;
1434 immediate
= (opcode
& 0xf);
1438 snprintf(instruction
->text
,
1440 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s 0x%4.4" PRIx32
"",
1447 /* Enhanced DSP multiplies */
1448 if ((opcode
& 0x000000090) == 0x00000080) {
1449 int x
= (opcode
& 0x20) >> 5;
1450 int y
= (opcode
& 0x40) >> 6;
1453 if ((opcode
& 0x00600000) == 0x00000000) {
1454 uint8_t Rd
, Rm
, Rs
, Rn
;
1455 instruction
->type
= ARM_SMLAxy
;
1456 Rd
= (opcode
& 0xf0000) >> 16;
1457 Rm
= (opcode
& 0xf);
1458 Rs
= (opcode
& 0xf00) >> 8;
1459 Rn
= (opcode
& 0xf000) >> 12;
1461 snprintf(instruction
->text
,
1463 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1476 if ((opcode
& 0x00600000) == 0x00400000) {
1477 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1478 instruction
->type
= ARM_SMLAxy
;
1479 RdHi
= (opcode
& 0xf0000) >> 16;
1480 RdLow
= (opcode
& 0xf000) >> 12;
1481 Rm
= (opcode
& 0xf);
1482 Rs
= (opcode
& 0xf00) >> 8;
1484 snprintf(instruction
->text
,
1486 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1499 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0)) {
1500 uint8_t Rd
, Rm
, Rs
, Rn
;
1501 instruction
->type
= ARM_SMLAWy
;
1502 Rd
= (opcode
& 0xf0000) >> 16;
1503 Rm
= (opcode
& 0xf);
1504 Rs
= (opcode
& 0xf00) >> 8;
1505 Rn
= (opcode
& 0xf000) >> 12;
1507 snprintf(instruction
->text
,
1509 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1521 if ((opcode
& 0x00600000) == 0x00300000) {
1523 instruction
->type
= ARM_SMULxy
;
1524 Rd
= (opcode
& 0xf0000) >> 16;
1525 Rm
= (opcode
& 0xf);
1526 Rs
= (opcode
& 0xf00) >> 8;
1528 snprintf(instruction
->text
,
1530 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1542 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1)) {
1544 instruction
->type
= ARM_SMULWy
;
1545 Rd
= (opcode
& 0xf0000) >> 16;
1546 Rm
= (opcode
& 0xf);
1547 Rs
= (opcode
& 0xf00) >> 8;
1549 snprintf(instruction
->text
,
1551 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1565 static int evaluate_data_proc(uint32_t opcode
,
1566 uint32_t address
, struct arm_instruction
*instruction
)
1568 uint8_t I
, op
, S
, Rn
, Rd
;
1569 char *mnemonic
= NULL
;
1570 char shifter_operand
[32];
1572 I
= (opcode
& 0x02000000) >> 25;
1573 op
= (opcode
& 0x01e00000) >> 21;
1574 S
= (opcode
& 0x00100000) >> 20;
1576 Rd
= (opcode
& 0xf000) >> 12;
1577 Rn
= (opcode
& 0xf0000) >> 16;
1579 instruction
->info
.data_proc
.Rd
= Rd
;
1580 instruction
->info
.data_proc
.Rn
= Rn
;
1581 instruction
->info
.data_proc
.S
= S
;
1585 instruction
->type
= ARM_AND
;
1589 instruction
->type
= ARM_EOR
;
1593 instruction
->type
= ARM_SUB
;
1597 instruction
->type
= ARM_RSB
;
1601 instruction
->type
= ARM_ADD
;
1605 instruction
->type
= ARM_ADC
;
1609 instruction
->type
= ARM_SBC
;
1613 instruction
->type
= ARM_RSC
;
1617 instruction
->type
= ARM_TST
;
1621 instruction
->type
= ARM_TEQ
;
1625 instruction
->type
= ARM_CMP
;
1629 instruction
->type
= ARM_CMN
;
1633 instruction
->type
= ARM_ORR
;
1637 instruction
->type
= ARM_MOV
;
1641 instruction
->type
= ARM_BIC
;
1645 instruction
->type
= ARM_MVN
;
1650 if (I
) {/* immediate shifter operand (#<immediate>)*/
1651 uint8_t immed_8
= opcode
& 0xff;
1652 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1655 immediate
= ror(immed_8
, rotate_imm
* 2);
1657 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1659 instruction
->info
.data_proc
.variant
= 0;
1660 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1661 } else {/* register-based shifter operand */
1663 shift
= (opcode
& 0x60) >> 5;
1664 Rm
= (opcode
& 0xf);
1666 if ((opcode
& 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1667 *#<shift_immediate>") */
1669 shift_imm
= (opcode
& 0xf80) >> 7;
1671 instruction
->info
.data_proc
.variant
= 1;
1672 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1673 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
=
1675 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1677 /* LSR encodes a shift by 32 bit as 0x0 */
1678 if ((shift
== 0x1) && (shift_imm
== 0x0))
1681 /* ASR encodes a shift by 32 bit as 0x0 */
1682 if ((shift
== 0x2) && (shift_imm
== 0x0))
1685 /* ROR by 32 bit is actually a RRX */
1686 if ((shift
== 0x3) && (shift_imm
== 0x0))
1689 if ((shift_imm
== 0x0) && (shift
== 0x0))
1690 snprintf(shifter_operand
, 32, "r%i", Rm
);
1692 if (shift
== 0x0) /* LSL */
1693 snprintf(shifter_operand
,
1698 else if (shift
== 0x1) /* LSR */
1699 snprintf(shifter_operand
,
1704 else if (shift
== 0x2) /* ASR */
1705 snprintf(shifter_operand
,
1710 else if (shift
== 0x3) /* ROR */
1711 snprintf(shifter_operand
,
1716 else if (shift
== 0x4) /* RRX */
1717 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1719 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1720 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1722 instruction
->info
.data_proc
.variant
= 2;
1723 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1724 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1725 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1727 if (shift
== 0x0) /* LSL */
1728 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1729 else if (shift
== 0x1) /* LSR */
1730 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1731 else if (shift
== 0x2) /* ASR */
1732 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1733 else if (shift
== 0x3) /* ROR */
1734 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1738 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1739 *<shifter_operand> */
1740 snprintf(instruction
->text
,
1742 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1751 } else if ((op
== 0xd) || (op
== 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1752 *<shifter_operand> */
1753 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1754 snprintf(instruction
->text
,
1756 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",
1760 snprintf(instruction
->text
,
1762 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1770 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1771 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1772 address
, opcode
, mnemonic
, COND(opcode
),
1773 Rn
, shifter_operand
);
1779 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1780 struct arm_instruction
*instruction
)
1782 /* clear fields, to avoid confusion */
1783 memset(instruction
, 0, sizeof(struct arm_instruction
));
1784 instruction
->opcode
= opcode
;
1785 instruction
->instruction_size
= 4;
1787 /* catch opcodes with condition field [31:28] = b1111 */
1788 if ((opcode
& 0xf0000000) == 0xf0000000) {
1789 /* Undefined instruction (or ARMv5E cache preload PLD) */
1790 if ((opcode
& 0x08000000) == 0x00000000)
1791 return evaluate_pld(opcode
, address
, instruction
);
1793 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1794 if ((opcode
& 0x0e000000) == 0x08000000)
1795 return evaluate_srs(opcode
, address
, instruction
);
1797 /* Branch and branch with link and change to Thumb */
1798 if ((opcode
& 0x0e000000) == 0x0a000000)
1799 return evaluate_blx_imm(opcode
, address
, instruction
);
1801 /* Extended coprocessor opcode space (ARMv5 and higher)
1802 * Coprocessor load/store and double register transfers */
1803 if ((opcode
& 0x0e000000) == 0x0c000000)
1804 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1806 /* Coprocessor data processing */
1807 if ((opcode
& 0x0f000100) == 0x0c000000)
1808 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1810 /* Coprocessor register transfers */
1811 if ((opcode
& 0x0f000010) == 0x0c000010)
1812 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1814 /* Undefined instruction */
1815 if ((opcode
& 0x0f000000) == 0x0f000000) {
1816 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1817 snprintf(instruction
->text
,
1819 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1826 /* catch opcodes with [27:25] = b000 */
1827 if ((opcode
& 0x0e000000) == 0x00000000) {
1828 /* Multiplies, extra load/stores */
1829 if ((opcode
& 0x00000090) == 0x00000090)
1830 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1832 /* Miscellaneous instructions */
1833 if ((opcode
& 0x0f900000) == 0x01000000)
1834 return evaluate_misc_instr(opcode
, address
, instruction
);
1836 return evaluate_data_proc(opcode
, address
, instruction
);
1839 /* catch opcodes with [27:25] = b001 */
1840 if ((opcode
& 0x0e000000) == 0x02000000) {
1841 /* Undefined instruction */
1842 if ((opcode
& 0x0fb00000) == 0x03000000) {
1843 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1844 snprintf(instruction
->text
,
1846 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1852 /* Move immediate to status register */
1853 if ((opcode
& 0x0fb00000) == 0x03200000)
1854 return evaluate_mrs_msr(opcode
, address
, instruction
);
1856 return evaluate_data_proc(opcode
, address
, instruction
);
1860 /* catch opcodes with [27:25] = b010 */
1861 if ((opcode
& 0x0e000000) == 0x04000000) {
1862 /* Load/store immediate offset */
1863 return evaluate_load_store(opcode
, address
, instruction
);
1866 /* catch opcodes with [27:25] = b011 */
1867 if ((opcode
& 0x0e000000) == 0x06000000) {
1868 /* Load/store register offset */
1869 if ((opcode
& 0x00000010) == 0x00000000)
1870 return evaluate_load_store(opcode
, address
, instruction
);
1872 /* Architecturally Undefined instruction
1873 * ... don't expect these to ever be used
1875 if ((opcode
& 0x07f000f0) == 0x07f000f0) {
1876 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1877 snprintf(instruction
->text
, 128,
1878 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1883 /* "media" instructions */
1884 return evaluate_media(opcode
, address
, instruction
);
1887 /* catch opcodes with [27:25] = b100 */
1888 if ((opcode
& 0x0e000000) == 0x08000000) {
1889 /* Load/store multiple */
1890 return evaluate_ldm_stm(opcode
, address
, instruction
);
1893 /* catch opcodes with [27:25] = b101 */
1894 if ((opcode
& 0x0e000000) == 0x0a000000) {
1895 /* Branch and branch with link */
1896 return evaluate_b_bl(opcode
, address
, instruction
);
1899 /* catch opcodes with [27:25] = b110 */
1900 if ((opcode
& 0x0e000000) == 0x0c000000) {
1901 /* Coprocessor load/store and double register transfers */
1902 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1905 /* catch opcodes with [27:25] = b111 */
1906 if ((opcode
& 0x0e000000) == 0x0e000000) {
1907 /* Software interrupt */
1908 if ((opcode
& 0x0f000000) == 0x0f000000)
1909 return evaluate_swi(opcode
, address
, instruction
);
1911 /* Coprocessor data processing */
1912 if ((opcode
& 0x0f000010) == 0x0e000000)
1913 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1915 /* Coprocessor register transfers */
1916 if ((opcode
& 0x0f000010) == 0x0e000010)
1917 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1920 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1925 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1926 uint32_t address
, struct arm_instruction
*instruction
)
1928 uint32_t offset
= opcode
& 0x7ff;
1929 uint32_t opc
= (opcode
>> 11) & 0x3;
1930 uint32_t target_address
;
1931 char *mnemonic
= NULL
;
1933 /* sign extend 11-bit offset */
1934 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1935 offset
= 0xfffff800 | offset
;
1937 target_address
= address
+ 4 + (offset
<< 1);
1940 /* unconditional branch */
1942 instruction
->type
= ARM_B
;
1947 instruction
->type
= ARM_BLX
;
1949 target_address
&= 0xfffffffc;
1953 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1954 mnemonic
= "prefix";
1955 target_address
= offset
<< 12;
1959 instruction
->type
= ARM_BL
;
1964 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1965 * these are effectively 32-bit instructions even in Thumb1. For
1966 * disassembly, it's simplest to always use the Thumb2 decoder.
1968 * But some cores will evidently handle them as two instructions,
1969 * where exceptions may occur between the two. The ETMv3.2+ ID
1970 * register has a bit which exposes this behavior.
1973 snprintf(instruction
->text
, 128,
1974 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1975 address
, opcode
, mnemonic
, target_address
);
1977 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1978 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1983 static int evaluate_add_sub_thumb(uint16_t opcode
,
1984 uint32_t address
, struct arm_instruction
*instruction
)
1986 uint8_t Rd
= (opcode
>> 0) & 0x7;
1987 uint8_t Rn
= (opcode
>> 3) & 0x7;
1988 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1989 uint32_t opc
= opcode
& (1 << 9);
1990 uint32_t reg_imm
= opcode
& (1 << 10);
1994 instruction
->type
= ARM_SUB
;
1997 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1998 instruction
->type
= ARM_ADD
;
2002 instruction
->info
.data_proc
.Rd
= Rd
;
2003 instruction
->info
.data_proc
.Rn
= Rn
;
2004 instruction
->info
.data_proc
.S
= 1;
2007 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2008 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
2009 snprintf(instruction
->text
, 128,
2010 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
2011 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2013 instruction
->info
.data_proc
.variant
= 1;/*immediate shift*/
2014 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
2015 snprintf(instruction
->text
, 128,
2016 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
2017 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2023 static int evaluate_shift_imm_thumb(uint16_t opcode
,
2024 uint32_t address
, struct arm_instruction
*instruction
)
2026 uint8_t Rd
= (opcode
>> 0) & 0x7;
2027 uint8_t Rm
= (opcode
>> 3) & 0x7;
2028 uint8_t imm
= (opcode
>> 6) & 0x1f;
2029 uint8_t opc
= (opcode
>> 11) & 0x3;
2030 char *mnemonic
= NULL
;
2034 instruction
->type
= ARM_MOV
;
2036 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
2039 instruction
->type
= ARM_MOV
;
2041 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
2044 instruction
->type
= ARM_MOV
;
2046 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
2050 if ((imm
== 0) && (opc
!= 0))
2053 instruction
->info
.data_proc
.Rd
= Rd
;
2054 instruction
->info
.data_proc
.Rn
= -1;
2055 instruction
->info
.data_proc
.S
= 1;
2057 instruction
->info
.data_proc
.variant
= 1;/*immediate_shift*/
2058 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2059 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
2061 snprintf(instruction
->text
, 128,
2062 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2063 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
2068 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
2069 uint32_t address
, struct arm_instruction
*instruction
)
2071 uint8_t imm
= opcode
& 0xff;
2072 uint8_t Rd
= (opcode
>> 8) & 0x7;
2073 uint32_t opc
= (opcode
>> 11) & 0x3;
2074 char *mnemonic
= NULL
;
2076 instruction
->info
.data_proc
.Rd
= Rd
;
2077 instruction
->info
.data_proc
.Rn
= Rd
;
2078 instruction
->info
.data_proc
.S
= 1;
2079 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2080 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
2084 instruction
->type
= ARM_MOV
;
2086 instruction
->info
.data_proc
.Rn
= -1;
2089 instruction
->type
= ARM_CMP
;
2091 instruction
->info
.data_proc
.Rd
= -1;
2094 instruction
->type
= ARM_ADD
;
2098 instruction
->type
= ARM_SUB
;
2103 snprintf(instruction
->text
, 128,
2104 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
2105 address
, opcode
, mnemonic
, Rd
, imm
);
2110 static int evaluate_data_proc_thumb(uint16_t opcode
,
2111 uint32_t address
, struct arm_instruction
*instruction
)
2113 uint8_t high_reg
, op
, Rm
, Rd
, H1
, H2
;
2114 char *mnemonic
= NULL
;
2117 high_reg
= (opcode
& 0x0400) >> 10;
2118 op
= (opcode
& 0x03C0) >> 6;
2120 Rd
= (opcode
& 0x0007);
2121 Rm
= (opcode
& 0x0038) >> 3;
2122 H1
= (opcode
& 0x0080) >> 7;
2123 H2
= (opcode
& 0x0040) >> 6;
2125 instruction
->info
.data_proc
.Rd
= Rd
;
2126 instruction
->info
.data_proc
.Rn
= Rd
;
2127 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2128 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2129 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2138 instruction
->type
= ARM_ADD
;
2142 instruction
->type
= ARM_CMP
;
2146 instruction
->type
= ARM_MOV
;
2152 if ((opcode
& 0x7) == 0x0) {
2153 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2155 instruction
->type
= ARM_BLX
;
2156 snprintf(instruction
->text
, 128,
2158 " 0x%4.4x \tBLX\tr%i",
2159 address
, opcode
, Rm
);
2161 instruction
->type
= ARM_BX
;
2162 snprintf(instruction
->text
, 128,
2164 " 0x%4.4x \tBX\tr%i",
2165 address
, opcode
, Rm
);
2168 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2169 snprintf(instruction
->text
, 128,
2172 "UNDEFINED INSTRUCTION",
2181 instruction
->type
= ARM_AND
;
2185 instruction
->type
= ARM_EOR
;
2189 instruction
->type
= ARM_MOV
;
2191 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2192 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2193 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2194 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2197 instruction
->type
= ARM_MOV
;
2199 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2200 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2201 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2202 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2205 instruction
->type
= ARM_MOV
;
2207 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2208 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2209 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2210 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2213 instruction
->type
= ARM_ADC
;
2217 instruction
->type
= ARM_SBC
;
2221 instruction
->type
= ARM_MOV
;
2223 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2224 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2225 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2226 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2229 instruction
->type
= ARM_TST
;
2233 instruction
->type
= ARM_RSB
;
2235 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2236 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2237 instruction
->info
.data_proc
.Rn
= Rm
;
2240 instruction
->type
= ARM_CMP
;
2244 instruction
->type
= ARM_CMN
;
2248 instruction
->type
= ARM_ORR
;
2252 instruction
->type
= ARM_MUL
;
2256 instruction
->type
= ARM_BIC
;
2260 instruction
->type
= ARM_MVN
;
2267 snprintf(instruction
->text
, 128,
2268 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2270 address
, opcode
, mnemonic
, Rd
, Rm
);
2272 snprintf(instruction
->text
, 128,
2273 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2274 address
, opcode
, mnemonic
, Rd
, Rm
);
2279 /* PC-relative data addressing is word-aligned even with Thumb */
2280 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2282 return (addr
+ 4) & ~3;
2285 static int evaluate_load_literal_thumb(uint16_t opcode
,
2286 uint32_t address
, struct arm_instruction
*instruction
)
2289 uint8_t Rd
= (opcode
>> 8) & 0x7;
2291 instruction
->type
= ARM_LDR
;
2292 immediate
= opcode
& 0x000000ff;
2295 instruction
->info
.load_store
.Rd
= Rd
;
2296 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2297 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2298 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2299 instruction
->info
.load_store
.offset
.offset
= immediate
;
2301 snprintf(instruction
->text
, 128,
2302 "0x%8.8" PRIx32
" 0x%4.4x \t"
2303 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2304 address
, opcode
, Rd
, immediate
,
2305 thumb_alignpc4(address
) + immediate
);
2310 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2311 uint32_t address
, struct arm_instruction
*instruction
)
2313 uint8_t Rd
= (opcode
>> 0) & 0x7;
2314 uint8_t Rn
= (opcode
>> 3) & 0x7;
2315 uint8_t Rm
= (opcode
>> 6) & 0x7;
2316 uint8_t opc
= (opcode
>> 9) & 0x7;
2317 char *mnemonic
= NULL
;
2321 instruction
->type
= ARM_STR
;
2325 instruction
->type
= ARM_STRH
;
2329 instruction
->type
= ARM_STRB
;
2333 instruction
->type
= ARM_LDRSB
;
2337 instruction
->type
= ARM_LDR
;
2341 instruction
->type
= ARM_LDRH
;
2345 instruction
->type
= ARM_LDRB
;
2349 instruction
->type
= ARM_LDRSH
;
2354 snprintf(instruction
->text
, 128,
2355 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2356 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2358 instruction
->info
.load_store
.Rd
= Rd
;
2359 instruction
->info
.load_store
.Rn
= Rn
;
2360 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2361 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2362 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2367 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2368 uint32_t address
, struct arm_instruction
*instruction
)
2370 uint32_t offset
= (opcode
>> 6) & 0x1f;
2371 uint8_t Rd
= (opcode
>> 0) & 0x7;
2372 uint8_t Rn
= (opcode
>> 3) & 0x7;
2373 uint32_t L
= opcode
& (1 << 11);
2374 uint32_t B
= opcode
& (1 << 12);
2380 instruction
->type
= ARM_LDR
;
2383 instruction
->type
= ARM_STR
;
2387 if ((opcode
&0xF000) == 0x8000) {
2395 snprintf(instruction
->text
, 128,
2396 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2397 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2399 instruction
->info
.load_store
.Rd
= Rd
;
2400 instruction
->info
.load_store
.Rn
= Rn
;
2401 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2402 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2403 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2408 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2409 uint32_t address
, struct arm_instruction
*instruction
)
2411 uint32_t offset
= opcode
& 0xff;
2412 uint8_t Rd
= (opcode
>> 8) & 0x7;
2413 uint32_t L
= opcode
& (1 << 11);
2417 instruction
->type
= ARM_LDR
;
2420 instruction
->type
= ARM_STR
;
2424 snprintf(instruction
->text
, 128,
2425 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2426 address
, opcode
, mnemonic
, Rd
, offset
*4);
2428 instruction
->info
.load_store
.Rd
= Rd
;
2429 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2430 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2431 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2432 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2437 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2438 uint32_t address
, struct arm_instruction
*instruction
)
2440 uint32_t imm
= opcode
& 0xff;
2441 uint8_t Rd
= (opcode
>> 8) & 0x7;
2443 uint32_t SP
= opcode
& (1 << 11);
2444 const char *reg_name
;
2446 instruction
->type
= ARM_ADD
;
2456 snprintf(instruction
->text
, 128,
2457 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2458 address
, opcode
, Rd
, reg_name
, imm
* 4);
2460 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2461 instruction
->info
.data_proc
.Rd
= Rd
;
2462 instruction
->info
.data_proc
.Rn
= Rn
;
2463 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2468 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2469 uint32_t address
, struct arm_instruction
*instruction
)
2471 uint32_t imm
= opcode
& 0x7f;
2472 uint8_t opc
= opcode
& (1 << 7);
2477 instruction
->type
= ARM_SUB
;
2480 instruction
->type
= ARM_ADD
;
2484 snprintf(instruction
->text
, 128,
2485 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2486 address
, opcode
, mnemonic
, imm
*4);
2488 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2489 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2490 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2491 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2496 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2497 uint32_t address
, struct arm_instruction
*instruction
)
2499 uint32_t imm
= opcode
& 0xff;
2501 instruction
->type
= ARM_BKPT
;
2503 snprintf(instruction
->text
, 128,
2504 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2505 address
, opcode
, imm
);
2510 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2511 uint32_t address
, struct arm_instruction
*instruction
)
2513 uint32_t reg_list
= opcode
& 0xff;
2514 uint32_t L
= opcode
& (1 << 11);
2515 uint32_t R
= opcode
& (1 << 8);
2516 uint8_t Rn
= (opcode
>> 8) & 7;
2517 uint8_t addr_mode
= 0 /* IA */;
2521 char ptr_name
[7] = "";
2524 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2525 * The STMIA and LDMIA opcodes are used for other instructions.
2528 if ((opcode
& 0xf000) == 0xc000) { /* generic load/store multiple */
2532 instruction
->type
= ARM_LDM
;
2534 if (opcode
& (1 << Rn
))
2537 instruction
->type
= ARM_STM
;
2540 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2541 } else {/* push/pop */
2544 instruction
->type
= ARM_LDM
;
2547 reg_list
|= (1 << 15) /*PC*/;
2549 instruction
->type
= ARM_STM
;
2551 addr_mode
= 3; /*DB*/
2553 reg_list
|= (1 << 14) /*LR*/;
2557 reg_names_p
= reg_names
;
2558 for (i
= 0; i
<= 15; i
++) {
2559 if (reg_list
& (1 << i
))
2560 reg_names_p
+= snprintf(reg_names_p
,
2561 (reg_names
+ 40 - reg_names_p
),
2565 if (reg_names_p
> reg_names
)
2566 reg_names_p
[-2] = '\0';
2567 else /* invalid op : no registers */
2568 reg_names
[0] = '\0';
2570 snprintf(instruction
->text
, 128,
2571 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2572 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2574 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2575 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2576 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2581 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2582 uint32_t address
, struct arm_instruction
*instruction
)
2584 uint32_t offset
= opcode
& 0xff;
2585 uint8_t cond
= (opcode
>> 8) & 0xf;
2586 uint32_t target_address
;
2589 instruction
->type
= ARM_SWI
;
2590 snprintf(instruction
->text
, 128,
2591 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2592 address
, opcode
, offset
);
2594 } else if (cond
== 0xe) {
2595 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2596 snprintf(instruction
->text
, 128,
2597 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2602 /* sign extend 8-bit offset */
2603 if (offset
& 0x00000080)
2604 offset
= 0xffffff00 | offset
;
2606 target_address
= address
+ 4 + (offset
<< 1);
2608 snprintf(instruction
->text
, 128,
2609 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2611 arm_condition_strings
[cond
], target_address
);
2613 instruction
->type
= ARM_B
;
2614 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2615 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2620 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2621 struct arm_instruction
*instruction
)
2625 /* added in Thumb2 */
2626 offset
= (opcode
>> 3) & 0x1f;
2627 offset
|= (opcode
& 0x0200) >> 4;
2629 snprintf(instruction
->text
, 128,
2630 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2632 (opcode
& 0x0800) ? "N" : "",
2633 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2638 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2639 struct arm_instruction
*instruction
)
2641 /* added in ARMv6 */
2642 snprintf(instruction
->text
, 128,
2643 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2645 (opcode
& 0x0080) ? 'U' : 'S',
2646 (opcode
& 0x0040) ? 'B' : 'H',
2647 opcode
& 0x7, (opcode
>> 3) & 0x7);
2652 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2653 struct arm_instruction
*instruction
)
2655 /* added in ARMv6 */
2656 if ((opcode
& 0x0ff0) == 0x0650)
2657 snprintf(instruction
->text
, 128,
2658 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2660 (opcode
& 0x80) ? "BE" : "LE");
2661 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2662 snprintf(instruction
->text
, 128,
2663 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2665 (opcode
& 0x0010) ? 'D' : 'E',
2666 (opcode
& 0x0004) ? "A" : "",
2667 (opcode
& 0x0002) ? "I" : "",
2668 (opcode
& 0x0001) ? "F" : "");
2673 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2674 struct arm_instruction
*instruction
)
2678 /* added in ARMv6 */
2679 switch ((opcode
>> 6) & 3) {
2690 snprintf(instruction
->text
, 128,
2691 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2692 address
, opcode
, suffix
,
2693 opcode
& 0x7, (opcode
>> 3) & 0x7);
2698 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2699 struct arm_instruction
*instruction
)
2703 switch ((opcode
>> 4) & 0x0f) {
2720 hint
= "HINT (UNRECOGNIZED)";
2724 snprintf(instruction
->text
, 128,
2725 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2726 address
, opcode
, hint
);
2731 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2732 struct arm_instruction
*instruction
)
2734 unsigned cond
= (opcode
>> 4) & 0x0f;
2735 char *x
= "", *y
= "", *z
= "";
2738 z
= (opcode
& 0x02) ? "T" : "E";
2740 y
= (opcode
& 0x04) ? "T" : "E";
2742 x
= (opcode
& 0x08) ? "T" : "E";
2744 snprintf(instruction
->text
, 128,
2745 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2747 x
, y
, z
, arm_condition_strings
[cond
]);
2749 /* NOTE: strictly speaking, the next 1-4 instructions should
2750 * now be displayed with the relevant conditional suffix...
2756 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2758 /* clear fields, to avoid confusion */
2759 memset(instruction
, 0, sizeof(struct arm_instruction
));
2760 instruction
->opcode
= opcode
;
2761 instruction
->instruction_size
= 2;
2763 if ((opcode
& 0xe000) == 0x0000) {
2764 /* add/substract register or immediate */
2765 if ((opcode
& 0x1800) == 0x1800)
2766 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2767 /* shift by immediate */
2769 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2772 /* Add/substract/compare/move immediate */
2773 if ((opcode
& 0xe000) == 0x2000)
2774 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2776 /* Data processing instructions */
2777 if ((opcode
& 0xf800) == 0x4000)
2778 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2780 /* Load from literal pool */
2781 if ((opcode
& 0xf800) == 0x4800)
2782 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2784 /* Load/Store register offset */
2785 if ((opcode
& 0xf000) == 0x5000)
2786 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2788 /* Load/Store immediate offset */
2789 if (((opcode
& 0xe000) == 0x6000)
2790 || ((opcode
& 0xf000) == 0x8000))
2791 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2793 /* Load/Store from/to stack */
2794 if ((opcode
& 0xf000) == 0x9000)
2795 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2798 if ((opcode
& 0xf000) == 0xa000)
2799 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2802 if ((opcode
& 0xf000) == 0xb000) {
2803 switch ((opcode
>> 8) & 0x0f) {
2805 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2810 return evaluate_cb_thumb(opcode
, address
, instruction
);
2812 return evaluate_extend_thumb(opcode
, address
, instruction
);
2817 return evaluate_load_store_multiple_thumb(opcode
, address
,
2820 return evaluate_cps_thumb(opcode
, address
, instruction
);
2822 if ((opcode
& 0x00c0) == 0x0080)
2824 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2826 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2828 if (opcode
& 0x000f)
2829 return evaluate_ifthen_thumb(opcode
, address
,
2832 return evaluate_hint_thumb(opcode
, address
,
2836 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2837 snprintf(instruction
->text
, 128,
2838 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2843 /* Load/Store multiple */
2844 if ((opcode
& 0xf000) == 0xc000)
2845 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2847 /* Conditional branch + SWI */
2848 if ((opcode
& 0xf000) == 0xd000)
2849 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2851 if ((opcode
& 0xe000) == 0xe000) {
2852 /* Undefined instructions */
2853 if ((opcode
& 0xf801) == 0xe801) {
2854 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2855 snprintf(instruction
->text
, 128,
2856 "0x%8.8" PRIx32
" 0x%8.8x\t"
2857 "UNDEFINED INSTRUCTION",
2860 } else /* Branch to offset */
2861 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2864 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2868 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2869 struct arm_instruction
*instruction
, char *cp
)
2872 unsigned b21
= 1 << 21;
2873 unsigned b22
= 1 << 22;
2875 /* instead of combining two smaller 16-bit branch instructions,
2876 * Thumb2 uses only one larger 32-bit instruction.
2878 offset
= opcode
& 0x7ff;
2879 offset
|= (opcode
& 0x03ff0000) >> 5;
2880 if (opcode
& (1 << 26)) {
2881 offset
|= 0xff << 23;
2882 if ((opcode
& (1 << 11)) == 0)
2884 if ((opcode
& (1 << 13)) == 0)
2887 if (opcode
& (1 << 11))
2889 if (opcode
& (1 << 13))
2897 address
+= offset
<< 1;
2900 switch ((opcode
>> 12) & 0x5) {
2903 instruction
->type
= ARM_B
;
2907 instruction
->type
= ARM_BLX
;
2911 instruction
->type
= ARM_BL
;
2914 return ERROR_COMMAND_SYNTAX_ERROR
;
2916 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2917 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2918 sprintf(cp
, "%s\t%#8.8" PRIx32
, inst
, address
);
2923 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2924 struct arm_instruction
*instruction
, char *cp
)
2927 unsigned b17
= 1 << 17;
2928 unsigned b18
= 1 << 18;
2929 unsigned cond
= (opcode
>> 22) & 0x0f;
2931 offset
= opcode
& 0x7ff;
2932 offset
|= (opcode
& 0x003f0000) >> 5;
2933 if (opcode
& (1 << 26)) {
2934 offset
|= 0x1fff << 19;
2935 if ((opcode
& (1 << 11)) == 0)
2937 if ((opcode
& (1 << 13)) == 0)
2940 if (opcode
& (1 << 11))
2942 if (opcode
& (1 << 13))
2949 address
+= offset
<< 1;
2951 instruction
->type
= ARM_B
;
2952 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2953 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2954 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2955 arm_condition_strings
[cond
],
2961 static const char *special_name(int number
)
2963 char *special
= "(RESERVED)";
2994 special
= "primask";
2997 special
= "basepri";
3000 special
= "basepri_max";
3003 special
= "faultmask";
3006 special
= "control";
3012 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
3013 struct arm_instruction
*instruction
, char *cp
)
3015 const char *mnemonic
;
3017 if (opcode
& 0x0700) {
3018 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3019 strcpy(cp
, "UNDEFINED");
3023 if (opcode
& 0x00f0) {
3024 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
3028 switch (opcode
& 0x0f) {
3033 mnemonic
= "YIELD.W";
3045 mnemonic
= "HINT.W (UNRECOGNIZED)";
3048 strcpy(cp
, mnemonic
);
3052 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3053 struct arm_instruction
*instruction
, char *cp
)
3055 const char *mnemonic
;
3057 switch ((opcode
>> 4) & 0x0f) {
3059 mnemonic
= "LEAVEX";
3062 mnemonic
= "ENTERX";
3077 return ERROR_COMMAND_SYNTAX_ERROR
;
3079 strcpy(cp
, mnemonic
);
3083 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3084 struct arm_instruction
*instruction
, char *cp
)
3086 /* permanently undefined */
3087 if ((opcode
& 0x07f07000) == 0x07f02000) {
3088 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3089 strcpy(cp
, "UNDEFINED");
3093 switch ((opcode
>> 12) & 0x5) {
3097 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3099 if (((opcode
>> 23) & 0x07) != 0x07)
3100 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3101 if (opcode
& (1 << 26))
3106 switch ((opcode
>> 20) & 0x7f) {
3109 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3110 (int) (opcode
>> 16) & 0x0f);
3113 return t2ev_hint(opcode
, address
, instruction
, cp
);
3115 return t2ev_misc(opcode
, address
, instruction
, cp
);
3117 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3121 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3122 special_name(opcode
& 0xff));
3127 return ERROR_COMMAND_SYNTAX_ERROR
;
3130 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3131 struct arm_instruction
*instruction
, char *cp
)
3133 char *mnemonic
= NULL
;
3134 int rn
= (opcode
>> 16) & 0xf;
3135 int rd
= (opcode
>> 8) & 0xf;
3136 unsigned immed
= opcode
& 0xff;
3142 /* ARMv7-M: A5.3.2 Modified immediate constants */
3143 func
= (opcode
>> 11) & 0x0e;
3146 if (opcode
& (1 << 26))
3149 /* "Modified" immediates */
3150 switch (func
>> 1) {
3157 immed
+= immed
<< 16;
3160 immed
+= immed
<< 8;
3161 immed
+= immed
<< 16;
3165 immed
= ror(immed
, func
);
3168 if (opcode
& (1 << 20))
3171 switch ((opcode
>> 21) & 0xf) {
3174 instruction
->type
= ARM_TST
;
3180 instruction
->type
= ARM_AND
;
3185 instruction
->type
= ARM_BIC
;
3190 instruction
->type
= ARM_MOV
;
3195 instruction
->type
= ARM_ORR
;
3201 instruction
->type
= ARM_MVN
;
3205 /* instruction->type = ARM_ORN; */
3211 instruction
->type
= ARM_TEQ
;
3217 instruction
->type
= ARM_EOR
;
3223 instruction
->type
= ARM_CMN
;
3229 instruction
->type
= ARM_ADD
;
3235 instruction
->type
= ARM_ADC
;
3240 instruction
->type
= ARM_SBC
;
3245 instruction
->type
= ARM_CMP
;
3251 instruction
->type
= ARM_SUB
;
3257 instruction
->type
= ARM_RSB
;
3262 return ERROR_COMMAND_SYNTAX_ERROR
;
3266 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3267 mnemonic
, suffix2
, rd
, immed
, immed
);
3269 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3270 mnemonic
, suffix
, suffix2
,
3271 rd
, rn
, immed
, immed
);
3276 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3277 struct arm_instruction
*instruction
, char *cp
)
3279 char *mnemonic
= NULL
;
3280 int rn
= (opcode
>> 16) & 0xf;
3281 int rd
= (opcode
>> 8) & 0xf;
3284 bool is_signed
= false;
3286 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3287 if (opcode
& (1 << 26))
3290 switch ((opcode
>> 20) & 0x1f) {
3299 immed
|= (opcode
>> 4) & 0xf000;
3300 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3308 /* move constant to top 16 bits of register */
3309 immed
|= (opcode
>> 4) & 0xf000;
3310 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3318 /* signed/unsigned saturated add */
3319 immed
= (opcode
>> 6) & 0x03;
3320 immed
|= (opcode
>> 10) & 0x1c;
3321 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3322 is_signed
? "S" : "U",
3323 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3324 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3325 immed
? immed
: 32);
3331 /* signed/unsigned bitfield extract */
3332 immed
= (opcode
>> 6) & 0x03;
3333 immed
|= (opcode
>> 10) & 0x1c;
3334 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3335 is_signed
? "S" : "U",
3337 (int) (opcode
& 0x1f) + 1);
3340 immed
= (opcode
>> 6) & 0x03;
3341 immed
|= (opcode
>> 10) & 0x1c;
3342 if (rn
== 0xf) /* bitfield clear */
3343 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3345 (int) (opcode
& 0x1f) + 1 - immed
);
3346 else /* bitfield insert */
3347 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3349 (int) (opcode
& 0x1f) + 1 - immed
);
3352 return ERROR_COMMAND_SYNTAX_ERROR
;
3355 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3356 rd
, rn
, immed
, immed
);
3360 address
= thumb_alignpc4(address
);
3365 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3366 * not hiding the pc-relative stuff will sometimes be useful.
3368 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3372 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3373 struct arm_instruction
*instruction
, char *cp
)
3375 unsigned op
= (opcode
>> 20) & 0xf;
3381 unsigned rn
= (opcode
>> 16) & 0x0f;
3382 unsigned rt
= (opcode
>> 12) & 0x0f;
3385 return ERROR_COMMAND_SYNTAX_ERROR
;
3387 if (opcode
& 0x0800)
3422 return ERROR_COMMAND_SYNTAX_ERROR
;
3425 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3426 size
, rt
, rn
, (int) opcode
& 0x0f,
3427 (int) (opcode
>> 4) & 0x03);
3431 immed
= opcode
& 0x0fff;
3432 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3433 size
, rt
, rn
, immed
, immed
);
3437 immed
= opcode
& 0x00ff;
3439 switch (opcode
& 0x700) {
3445 return ERROR_COMMAND_SYNTAX_ERROR
;
3448 /* two indexed modes will write back rn */
3449 if (opcode
& 0x100) {
3450 if (opcode
& 0x400) /* pre-indexed */
3452 else { /* post-indexed */
3458 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3459 size
, suffix
, rt
, rn
, p1
,
3460 (opcode
& 0x200) ? "" : "-",
3465 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3466 struct arm_instruction
*instruction
, char *cp
)
3468 int ra
= (opcode
>> 12) & 0xf;
3470 switch (opcode
& 0x007000f0) {
3473 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3474 (int) (opcode
>> 8) & 0xf,
3475 (int) (opcode
>> 16) & 0xf,
3476 (int) (opcode
>> 0) & 0xf);
3478 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3479 (int) (opcode
>> 8) & 0xf,
3480 (int) (opcode
>> 16) & 0xf,
3481 (int) (opcode
>> 0) & 0xf, ra
);
3484 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3485 (int) (opcode
>> 8) & 0xf,
3486 (int) (opcode
>> 16) & 0xf,
3487 (int) (opcode
>> 0) & 0xf, ra
);
3490 return ERROR_COMMAND_SYNTAX_ERROR
;
3495 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3496 struct arm_instruction
*instruction
, char *cp
)
3498 int op
= (opcode
>> 4) & 0xf;
3499 char *infix
= "MUL";
3501 op
+= (opcode
>> 16) & 0x70;
3509 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3510 (op
& 0x20) ? 'U' : 'S',
3512 (int) (opcode
>> 12) & 0xf,
3513 (int) (opcode
>> 8) & 0xf,
3514 (int) (opcode
>> 16) & 0xf,
3515 (int) (opcode
>> 0) & 0xf);
3519 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3520 (op
& 0x20) ? 'U' : 'S',
3521 (int) (opcode
>> 8) & 0xf,
3522 (int) (opcode
>> 16) & 0xf,
3523 (int) (opcode
>> 0) & 0xf);
3526 return ERROR_COMMAND_SYNTAX_ERROR
;
3532 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3533 struct arm_instruction
*instruction
, char *cp
)
3535 int rn
= (opcode
>> 16) & 0xf;
3536 int op
= (opcode
>> 22) & 0x6;
3537 int t
= (opcode
>> 21) & 1;
3538 unsigned registers
= opcode
& 0xffff;
3541 if (opcode
& (1 << 20))
3549 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3551 (unsigned) (opcode
& 0x1f));
3557 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3558 (unsigned) ((opcode
>> 16) & 0xf),
3562 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3566 sprintf(cp
, "POP.W\t");
3568 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3572 sprintf(cp
, "PUSH.W\t");
3574 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3577 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3580 return ERROR_COMMAND_SYNTAX_ERROR
;
3585 for (t
= 0; registers
; t
++, registers
>>= 1) {
3586 if ((registers
& 1) == 0)
3589 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3598 /* load/store dual or exclusive, table branch */
3599 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3600 struct arm_instruction
*instruction
, char *cp
)
3602 unsigned op1op2
= (opcode
>> 20) & 0x3;
3603 unsigned op3
= (opcode
>> 4) & 0xf;
3605 unsigned rn
= (opcode
>> 16) & 0xf;
3606 unsigned rt
= (opcode
>> 12) & 0xf;
3607 unsigned rd
= (opcode
>> 8) & 0xf;
3608 unsigned imm
= opcode
& 0xff;
3612 op1op2
|= (opcode
>> 21) & 0xc;
3642 mnemonic
= "STREXB";
3645 mnemonic
= "STREXH";
3648 return ERROR_COMMAND_SYNTAX_ERROR
;
3656 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3659 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3662 mnemonic
= "LDREXB";
3665 mnemonic
= "LDREXH";
3668 return ERROR_COMMAND_SYNTAX_ERROR
;
3673 return ERROR_COMMAND_SYNTAX_ERROR
;
3678 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3679 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3681 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3682 mnemonic
, rd
, rt
, rn
);
3688 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3689 mnemonic
, rt
, rn
, imm
, imm
);
3691 sprintf(cp
, "%s\tr%u, [r%u]",
3696 /* two indexed modes will write back rn */
3697 if (opcode
& (1 << 21)) {
3698 if (opcode
& (1 << 24)) /* pre-indexed */
3700 else { /* post-indexed */
3707 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3708 mnemonic
, rt
, rd
, rn
, p1
,
3709 (opcode
& (1 << 23)) ? "" : "-",
3714 address
= thumb_alignpc4(address
);
3716 if (opcode
& (1 << 23))
3720 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3721 mnemonic
, rt
, rd
, address
);
3725 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3726 struct arm_instruction
*instruction
, char *cp
)
3728 int op
= (opcode
>> 21) & 0xf;
3729 int rd
= (opcode
>> 8) & 0xf;
3730 int rn
= (opcode
>> 16) & 0xf;
3731 int type
= (opcode
>> 4) & 0x3;
3732 int immed
= (opcode
>> 6) & 0x3;
3736 immed
|= (opcode
>> 10) & 0x1c;
3737 if (opcode
& (1 << 20))
3743 if (!(opcode
& (1 << 20)))
3744 return ERROR_COMMAND_SYNTAX_ERROR
;
3745 instruction
->type
= ARM_TST
;
3750 instruction
->type
= ARM_AND
;
3754 instruction
->type
= ARM_BIC
;
3759 instruction
->type
= ARM_MOV
;
3763 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3765 (int) (opcode
& 0xf));
3778 sprintf(cp
, "RRX%s\tr%d, r%d",
3780 (int) (opcode
& 0xf));
3788 instruction
->type
= ARM_ORR
;
3794 instruction
->type
= ARM_MVN
;
3799 /* instruction->type = ARM_ORN; */
3805 if (!(opcode
& (1 << 20)))
3806 return ERROR_COMMAND_SYNTAX_ERROR
;
3807 instruction
->type
= ARM_TEQ
;
3812 instruction
->type
= ARM_EOR
;
3817 if (!(opcode
& (1 << 20)))
3818 return ERROR_COMMAND_SYNTAX_ERROR
;
3819 instruction
->type
= ARM_CMN
;
3824 instruction
->type
= ARM_ADD
;
3828 instruction
->type
= ARM_ADC
;
3832 instruction
->type
= ARM_SBC
;
3837 if (!(opcode
& (1 << 21)))
3838 return ERROR_COMMAND_SYNTAX_ERROR
;
3839 instruction
->type
= ARM_CMP
;
3844 instruction
->type
= ARM_SUB
;
3848 instruction
->type
= ARM_RSB
;
3852 return ERROR_COMMAND_SYNTAX_ERROR
;
3855 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3856 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3879 strcpy(cp
, ", RRX");
3885 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3889 sprintf(cp
, "%s%s.W\tr%d, r%d",
3890 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3894 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3895 mnemonic
, suffix
, rd
,
3896 (int) (opcode
& 0xf), immed
? immed
: 32);
3900 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3901 struct arm_instruction
*instruction
, char *cp
)
3906 if (((opcode
>> 4) & 0xf) == 0) {
3907 switch ((opcode
>> 21) & 0x7) {
3921 return ERROR_COMMAND_SYNTAX_ERROR
;
3924 instruction
->type
= ARM_MOV
;
3925 if (opcode
& (1 << 20))
3927 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3929 (int) (opcode
>> 8) & 0xf,
3930 (int) (opcode
>> 16) & 0xf,
3931 (int) (opcode
>> 0) & 0xf);
3933 } else if (opcode
& (1 << 7)) {
3934 switch ((opcode
>> 20) & 0xf) {
3939 switch ((opcode
>> 4) & 0x3) {
3941 suffix
= ", ROR #8";
3944 suffix
= ", ROR #16";
3947 suffix
= ", ROR #24";
3950 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3951 (opcode
& (1 << 24)) ? 'U' : 'S',
3952 (opcode
& (1 << 26)) ? 'B' : 'H',
3953 (int) (opcode
>> 8) & 0xf,
3954 (int) (opcode
>> 0) & 0xf,
3961 if (opcode
& (1 << 6))
3962 return ERROR_COMMAND_SYNTAX_ERROR
;
3963 if (((opcode
>> 12) & 0xf) != 0xf)
3964 return ERROR_COMMAND_SYNTAX_ERROR
;
3965 if (!(opcode
& (1 << 20)))
3966 return ERROR_COMMAND_SYNTAX_ERROR
;
3968 switch (((opcode
>> 19) & 0x04)
3969 | ((opcode
>> 4) & 0x3)) {
3974 mnemonic
= "REV16.W";
3980 mnemonic
= "REVSH.W";
3986 return ERROR_COMMAND_SYNTAX_ERROR
;
3988 sprintf(cp
, "%s\tr%d, r%d",
3990 (int) (opcode
>> 8) & 0xf,
3991 (int) (opcode
>> 0) & 0xf);
3994 return ERROR_COMMAND_SYNTAX_ERROR
;
4001 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
4002 struct arm_instruction
*instruction
, char *cp
)
4004 int rn
= (opcode
>> 16) & 0xf;
4007 instruction
->type
= ARM_LDR
;
4010 immed
= opcode
& 0x0fff;
4011 if ((opcode
& (1 << 23)) == 0)
4013 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4014 (int) (opcode
>> 12) & 0xf,
4015 thumb_alignpc4(address
) + immed
);
4019 if (opcode
& (1 << 23)) {
4020 immed
= opcode
& 0x0fff;
4021 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4022 (int) (opcode
>> 12) & 0xf,
4027 if (!(opcode
& (0x3f << 6))) {
4028 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4029 (int) (opcode
>> 12) & 0xf,
4031 (int) (opcode
>> 0) & 0xf,
4032 (int) (opcode
>> 4) & 0x3);
4037 if (((opcode
>> 8) & 0xf) == 0xe) {
4038 immed
= opcode
& 0x00ff;
4040 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4041 (int) (opcode
>> 12) & 0xf,
4046 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4047 char *p1
= "]", *p2
= "";
4049 if (!(opcode
& 0x0500))
4050 return ERROR_COMMAND_SYNTAX_ERROR
;
4052 immed
= opcode
& 0x00ff;
4054 /* two indexed modes will write back rn */
4055 if (opcode
& 0x100) {
4056 if (opcode
& 0x400) /* pre-indexed */
4058 else { /* post-indexed */
4064 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4065 (int) (opcode
>> 12) & 0xf,
4067 (opcode
& 0x200) ? "" : "-",
4072 return ERROR_COMMAND_SYNTAX_ERROR
;
4075 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4076 struct arm_instruction
*instruction
, char *cp
)
4078 int rn
= (opcode
>> 16) & 0xf;
4079 int rt
= (opcode
>> 12) & 0xf;
4080 int op2
= (opcode
>> 6) & 0x3f;
4082 char *p1
= "", *p2
= "]";
4085 switch ((opcode
>> 23) & 0x3) {
4087 if ((rn
& rt
) == 0xf) {
4089 immed
= opcode
& 0xfff;
4090 address
= thumb_alignpc4(address
);
4091 if (opcode
& (1 << 23))
4095 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4099 if (rn
== 0x0f && rt
!= 0x0f) {
4101 immed
= opcode
& 0xfff;
4102 address
= thumb_alignpc4(address
);
4103 if (opcode
& (1 << 23))
4107 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4113 if ((op2
& 0x3c) == 0x38) {
4114 immed
= opcode
& 0xff;
4115 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4116 rt
, rn
, immed
, immed
);
4119 if ((op2
& 0x3c) == 0x30) {
4121 immed
= opcode
& 0xff;
4124 p1
= (opcode
& (1 << 21)) ? "W" : "";
4125 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4126 p1
, rn
, immed
, immed
);
4131 immed
= opcode
& 0xff;
4132 if (!(opcode
& 0x200))
4135 /* two indexed modes will write back rn */
4136 if (opcode
& 0x100) {
4137 if (opcode
& 0x400) /* pre-indexed */
4139 else { /* post-indexed */
4145 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4146 mnemonic
, rt
, rn
, p1
,
4150 if ((op2
& 0x24) == 0x24) {
4152 goto ldrxb_immediate_t3
;
4155 int rm
= opcode
& 0xf;
4158 sprintf(cp
, "PLD\t");
4160 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4161 immed
= (opcode
>> 4) & 0x3;
4163 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4168 if ((rn
& rt
) == 0xf)
4171 immed
= opcode
& 0xfff;
4172 goto preload_immediate
;
4176 mnemonic
= "LDRB.W";
4177 immed
= opcode
& 0xfff;
4178 goto ldrxb_immediate_t2
;
4180 if ((rn
& rt
) == 0xf) {
4181 immed
= opcode
& 0xfff;
4182 address
= thumb_alignpc4(address
);
4183 if (opcode
& (1 << 23))
4187 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4190 if (rn
== 0xf && rt
!= 0xf) {
4192 immed
= opcode
& 0xfff;
4193 address
= thumb_alignpc4(address
);
4194 if (opcode
& (1 << 23))
4198 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4203 if ((op2
& 0x3c) == 0x38) {
4204 immed
= opcode
& 0xff;
4205 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4206 rt
, rn
, immed
, immed
);
4209 if ((op2
& 0x3c) == 0x30) {
4211 immed
= opcode
& 0xff;
4212 immed
= -immed
; /* pli */
4213 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4218 goto ldrxb_immediate_t3
;
4220 if ((op2
& 0x24) == 0x24) {
4222 goto ldrxb_immediate_t3
;
4225 int rm
= opcode
& 0xf;
4228 sprintf(cp
, "PLI\t");
4230 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4231 immed
= (opcode
>> 4) & 0x3;
4233 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4239 immed
= opcode
& 0xfff;
4240 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4246 immed
= opcode
& 0xfff;
4248 goto ldrxb_immediate_t2
;
4251 return ERROR_COMMAND_SYNTAX_ERROR
;
4254 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4255 struct arm_instruction
*instruction
, char *cp
)
4257 int rn
= (opcode
>> 16) & 0xf;
4258 int rt
= (opcode
>> 12) & 0xf;
4259 int op2
= (opcode
>> 6) & 0x3f;
4264 sprintf(cp
, "HINT (UNALLOCATED)");
4268 if (opcode
& (1 << 24))
4271 if ((opcode
& (1 << 23)) == 0) {
4274 immed
= opcode
& 0xfff;
4275 address
= thumb_alignpc4(address
);
4276 if (opcode
& (1 << 23))
4280 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4285 int rm
= opcode
& 0xf;
4287 immed
= (opcode
>> 4) & 0x3;
4288 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4289 sign
, rt
, rn
, rm
, immed
);
4292 if ((op2
& 0x3c) == 0x38) {
4293 immed
= opcode
& 0xff;
4294 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4295 sign
, rt
, rn
, immed
, immed
);
4298 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4299 char *p1
= "", *p2
= "]";
4301 immed
= opcode
& 0xff;
4302 if (!(opcode
& 0x200))
4305 /* two indexed modes will write back rn */
4306 if (opcode
& 0x100) {
4307 if (opcode
& 0x400) /* pre-indexed */
4309 else { /* post-indexed */
4314 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4315 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4322 immed
= opcode
& 0xfff;
4323 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4324 sign
, *sign
? "" : ".W",
4325 rt
, rn
, immed
, immed
);
4329 return ERROR_COMMAND_SYNTAX_ERROR
;
4333 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4334 * always set. That means eventual arm_simulate_step() support for Thumb2
4335 * will need work in this area.
4337 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4344 /* clear low bit ... it's set on function pointers */
4347 /* clear fields, to avoid confusion */
4348 memset(instruction
, 0, sizeof(struct arm_instruction
));
4350 /* read first halfword, see if this is the only one */
4351 retval
= target_read_u16(target
, address
, &op
);
4352 if (retval
!= ERROR_OK
)
4355 switch (op
& 0xf800) {
4359 /* 32-bit instructions */
4360 instruction
->instruction_size
= 4;
4362 retval
= target_read_u16(target
, address
+ 2, &op
);
4363 if (retval
!= ERROR_OK
)
4366 instruction
->opcode
= opcode
;
4369 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4370 return thumb_evaluate_opcode(op
, address
, instruction
);
4373 snprintf(instruction
->text
, 128,
4374 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4376 cp
= strchr(instruction
->text
, 0);
4377 retval
= ERROR_FAIL
;
4379 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4380 if ((opcode
& 0x1a008000) == 0x10000000)
4381 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4383 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4384 else if ((opcode
& 0x1a008000) == 0x12000000)
4385 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4387 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4388 else if ((opcode
& 0x18008000) == 0x10008000)
4389 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4391 /* ARMv7-M: A5.3.5 Load/store multiple */
4392 else if ((opcode
& 0x1e400000) == 0x08000000)
4393 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4395 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4396 else if ((opcode
& 0x1e400000) == 0x08400000)
4397 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4399 /* ARMv7-M: A5.3.7 Load word */
4400 else if ((opcode
& 0x1f700000) == 0x18500000)
4401 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4403 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4404 else if ((opcode
& 0x1e700000) == 0x18300000)
4405 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4407 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4408 else if ((opcode
& 0x1e700000) == 0x18100000)
4409 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4411 /* ARMv7-M: A5.3.10 Store single data item */
4412 else if ((opcode
& 0x1f100000) == 0x18000000)
4413 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4415 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4416 else if ((opcode
& 0x1e000000) == 0x0a000000)
4417 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4419 /* ARMv7-M: A5.3.12 Data processing (register)
4420 * and A5.3.13 Miscellaneous operations
4422 else if ((opcode
& 0x1f000000) == 0x1a000000)
4423 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4425 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4426 else if ((opcode
& 0x1f800000) == 0x1b000000)
4427 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4429 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4430 else if ((opcode
& 0x1f800000) == 0x1b800000)
4431 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4433 if (retval
== ERROR_OK
)
4437 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4438 * instructions; not yet handled here.
4441 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4442 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4443 strcpy(cp
, "UNDEFINED OPCODE");
4447 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4450 strcpy(cp
, "(32-bit Thumb2 ...)");
4454 int arm_access_size(struct arm_instruction
*instruction
)
4456 if ((instruction
->type
== ARM_LDRB
)
4457 || (instruction
->type
== ARM_LDRBT
)
4458 || (instruction
->type
== ARM_LDRSB
)
4459 || (instruction
->type
== ARM_STRB
)
4460 || (instruction
->type
== ARM_STRBT
))
4462 else if ((instruction
->type
== ARM_LDRH
)
4463 || (instruction
->type
== ARM_LDRSH
)
4464 || (instruction
->type
== ARM_STRH
))
4466 else if ((instruction
->type
== ARM_LDR
)
4467 || (instruction
->type
== ARM_LDRT
)
4468 || (instruction
->type
== ARM_STR
)
4469 || (instruction
->type
== ARM_STRT
))
4471 else if ((instruction
->type
== ARM_LDRD
)
4472 || (instruction
->type
== ARM_STRD
))
4475 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)