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;
2899 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2900 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2901 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2902 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2903 (opcode
& (1 << 14)) ? "BL" : "B.W",
2909 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2910 struct arm_instruction
*instruction
, char *cp
)
2913 unsigned b17
= 1 << 17;
2914 unsigned b18
= 1 << 18;
2915 unsigned cond
= (opcode
>> 22) & 0x0f;
2917 offset
= opcode
& 0x7ff;
2918 offset
|= (opcode
& 0x003f0000) >> 5;
2919 if (opcode
& (1 << 26)) {
2920 offset
|= 0x1fff << 19;
2921 if ((opcode
& (1 << 11)) == 0)
2923 if ((opcode
& (1 << 13)) == 0)
2926 if (opcode
& (1 << 11))
2928 if (opcode
& (1 << 13))
2935 address
+= offset
<< 1;
2937 instruction
->type
= ARM_B
;
2938 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2939 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2940 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2941 arm_condition_strings
[cond
],
2947 static const char *special_name(int number
)
2949 char *special
= "(RESERVED)";
2980 special
= "primask";
2983 special
= "basepri";
2986 special
= "basepri_max";
2989 special
= "faultmask";
2992 special
= "control";
2998 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2999 struct arm_instruction
*instruction
, char *cp
)
3001 const char *mnemonic
;
3003 if (opcode
& 0x0700) {
3004 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3005 strcpy(cp
, "UNDEFINED");
3009 if (opcode
& 0x00f0) {
3010 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
3014 switch (opcode
& 0x0f) {
3019 mnemonic
= "YIELD.W";
3031 mnemonic
= "HINT.W (UNRECOGNIZED)";
3034 strcpy(cp
, mnemonic
);
3038 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3039 struct arm_instruction
*instruction
, char *cp
)
3041 const char *mnemonic
;
3043 switch ((opcode
>> 4) & 0x0f) {
3045 mnemonic
= "LEAVEX";
3048 mnemonic
= "ENTERX";
3063 return ERROR_COMMAND_SYNTAX_ERROR
;
3065 strcpy(cp
, mnemonic
);
3069 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3070 struct arm_instruction
*instruction
, char *cp
)
3072 /* permanently undefined */
3073 if ((opcode
& 0x07f07000) == 0x07f02000) {
3074 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3075 strcpy(cp
, "UNDEFINED");
3079 switch ((opcode
>> 12) & 0x5) {
3082 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3086 if (((opcode
>> 23) & 0x07) != 0x07)
3087 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3088 if (opcode
& (1 << 26))
3093 switch ((opcode
>> 20) & 0x7f) {
3096 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3097 (int) (opcode
>> 16) & 0x0f);
3100 return t2ev_hint(opcode
, address
, instruction
, cp
);
3102 return t2ev_misc(opcode
, address
, instruction
, cp
);
3104 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3108 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3109 special_name(opcode
& 0xff));
3114 return ERROR_COMMAND_SYNTAX_ERROR
;
3117 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3118 struct arm_instruction
*instruction
, char *cp
)
3120 char *mnemonic
= NULL
;
3121 int rn
= (opcode
>> 16) & 0xf;
3122 int rd
= (opcode
>> 8) & 0xf;
3123 unsigned immed
= opcode
& 0xff;
3129 /* ARMv7-M: A5.3.2 Modified immediate constants */
3130 func
= (opcode
>> 11) & 0x0e;
3133 if (opcode
& (1 << 26))
3136 /* "Modified" immediates */
3137 switch (func
>> 1) {
3144 immed
+= immed
<< 16;
3147 immed
+= immed
<< 8;
3148 immed
+= immed
<< 16;
3152 immed
= ror(immed
, func
);
3155 if (opcode
& (1 << 20))
3158 switch ((opcode
>> 21) & 0xf) {
3161 instruction
->type
= ARM_TST
;
3167 instruction
->type
= ARM_AND
;
3172 instruction
->type
= ARM_BIC
;
3177 instruction
->type
= ARM_MOV
;
3182 instruction
->type
= ARM_ORR
;
3188 instruction
->type
= ARM_MVN
;
3192 /* instruction->type = ARM_ORN; */
3198 instruction
->type
= ARM_TEQ
;
3204 instruction
->type
= ARM_EOR
;
3210 instruction
->type
= ARM_CMN
;
3216 instruction
->type
= ARM_ADD
;
3222 instruction
->type
= ARM_ADC
;
3227 instruction
->type
= ARM_SBC
;
3232 instruction
->type
= ARM_CMP
;
3238 instruction
->type
= ARM_SUB
;
3244 instruction
->type
= ARM_RSB
;
3249 return ERROR_COMMAND_SYNTAX_ERROR
;
3253 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3254 mnemonic
, suffix2
, rd
, immed
, immed
);
3256 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3257 mnemonic
, suffix
, suffix2
,
3258 rd
, rn
, immed
, immed
);
3263 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3264 struct arm_instruction
*instruction
, char *cp
)
3266 char *mnemonic
= NULL
;
3267 int rn
= (opcode
>> 16) & 0xf;
3268 int rd
= (opcode
>> 8) & 0xf;
3271 bool is_signed
= false;
3273 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3274 if (opcode
& (1 << 26))
3277 switch ((opcode
>> 20) & 0x1f) {
3286 immed
|= (opcode
>> 4) & 0xf000;
3287 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3295 /* move constant to top 16 bits of register */
3296 immed
|= (opcode
>> 4) & 0xf000;
3297 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3305 /* signed/unsigned saturated add */
3306 immed
= (opcode
>> 6) & 0x03;
3307 immed
|= (opcode
>> 10) & 0x1c;
3308 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3309 is_signed
? "S" : "U",
3310 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3311 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3312 immed
? immed
: 32);
3318 /* signed/unsigned bitfield extract */
3319 immed
= (opcode
>> 6) & 0x03;
3320 immed
|= (opcode
>> 10) & 0x1c;
3321 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3322 is_signed
? "S" : "U",
3324 (int) (opcode
& 0x1f) + 1);
3327 immed
= (opcode
>> 6) & 0x03;
3328 immed
|= (opcode
>> 10) & 0x1c;
3329 if (rn
== 0xf) /* bitfield clear */
3330 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3332 (int) (opcode
& 0x1f) + 1 - immed
);
3333 else /* bitfield insert */
3334 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3336 (int) (opcode
& 0x1f) + 1 - immed
);
3339 return ERROR_COMMAND_SYNTAX_ERROR
;
3342 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3343 rd
, rn
, immed
, immed
);
3347 address
= thumb_alignpc4(address
);
3352 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3353 * not hiding the pc-relative stuff will sometimes be useful.
3355 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3359 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3360 struct arm_instruction
*instruction
, char *cp
)
3362 unsigned op
= (opcode
>> 20) & 0xf;
3368 unsigned rn
= (opcode
>> 16) & 0x0f;
3369 unsigned rt
= (opcode
>> 12) & 0x0f;
3372 return ERROR_COMMAND_SYNTAX_ERROR
;
3374 if (opcode
& 0x0800)
3409 return ERROR_COMMAND_SYNTAX_ERROR
;
3412 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3413 size
, rt
, rn
, (int) opcode
& 0x0f,
3414 (int) (opcode
>> 4) & 0x03);
3418 immed
= opcode
& 0x0fff;
3419 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3420 size
, rt
, rn
, immed
, immed
);
3424 immed
= opcode
& 0x00ff;
3426 switch (opcode
& 0x700) {
3432 return ERROR_COMMAND_SYNTAX_ERROR
;
3435 /* two indexed modes will write back rn */
3436 if (opcode
& 0x100) {
3437 if (opcode
& 0x400) /* pre-indexed */
3439 else { /* post-indexed */
3445 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3446 size
, suffix
, rt
, rn
, p1
,
3447 (opcode
& 0x200) ? "" : "-",
3452 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3453 struct arm_instruction
*instruction
, char *cp
)
3455 int ra
= (opcode
>> 12) & 0xf;
3457 switch (opcode
& 0x007000f0) {
3460 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3461 (int) (opcode
>> 8) & 0xf,
3462 (int) (opcode
>> 16) & 0xf,
3463 (int) (opcode
>> 0) & 0xf);
3465 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3466 (int) (opcode
>> 8) & 0xf,
3467 (int) (opcode
>> 16) & 0xf,
3468 (int) (opcode
>> 0) & 0xf, ra
);
3471 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3472 (int) (opcode
>> 8) & 0xf,
3473 (int) (opcode
>> 16) & 0xf,
3474 (int) (opcode
>> 0) & 0xf, ra
);
3477 return ERROR_COMMAND_SYNTAX_ERROR
;
3482 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3483 struct arm_instruction
*instruction
, char *cp
)
3485 int op
= (opcode
>> 4) & 0xf;
3486 char *infix
= "MUL";
3488 op
+= (opcode
>> 16) & 0x70;
3496 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3497 (op
& 0x20) ? 'U' : 'S',
3499 (int) (opcode
>> 12) & 0xf,
3500 (int) (opcode
>> 8) & 0xf,
3501 (int) (opcode
>> 16) & 0xf,
3502 (int) (opcode
>> 0) & 0xf);
3506 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3507 (op
& 0x20) ? 'U' : 'S',
3508 (int) (opcode
>> 8) & 0xf,
3509 (int) (opcode
>> 16) & 0xf,
3510 (int) (opcode
>> 0) & 0xf);
3513 return ERROR_COMMAND_SYNTAX_ERROR
;
3519 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3520 struct arm_instruction
*instruction
, char *cp
)
3522 int rn
= (opcode
>> 16) & 0xf;
3523 int op
= (opcode
>> 22) & 0x6;
3524 int t
= (opcode
>> 21) & 1;
3525 unsigned registers
= opcode
& 0xffff;
3528 if (opcode
& (1 << 20))
3536 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3538 (unsigned) (opcode
& 0x1f));
3544 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3545 (unsigned) ((opcode
>> 16) & 0xf),
3549 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3553 sprintf(cp
, "POP.W\t");
3555 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3559 sprintf(cp
, "PUSH.W\t");
3561 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3564 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3567 return ERROR_COMMAND_SYNTAX_ERROR
;
3572 for (t
= 0; registers
; t
++, registers
>>= 1) {
3573 if ((registers
& 1) == 0)
3576 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3585 /* load/store dual or exclusive, table branch */
3586 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3587 struct arm_instruction
*instruction
, char *cp
)
3589 unsigned op1op2
= (opcode
>> 20) & 0x3;
3590 unsigned op3
= (opcode
>> 4) & 0xf;
3592 unsigned rn
= (opcode
>> 16) & 0xf;
3593 unsigned rt
= (opcode
>> 12) & 0xf;
3594 unsigned rd
= (opcode
>> 8) & 0xf;
3595 unsigned imm
= opcode
& 0xff;
3599 op1op2
|= (opcode
>> 21) & 0xc;
3629 mnemonic
= "STREXB";
3632 mnemonic
= "STREXH";
3635 return ERROR_COMMAND_SYNTAX_ERROR
;
3643 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3646 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3649 mnemonic
= "LDREXB";
3652 mnemonic
= "LDREXH";
3655 return ERROR_COMMAND_SYNTAX_ERROR
;
3660 return ERROR_COMMAND_SYNTAX_ERROR
;
3665 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3666 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3668 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3669 mnemonic
, rd
, rt
, rn
);
3675 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3676 mnemonic
, rt
, rn
, imm
, imm
);
3678 sprintf(cp
, "%s\tr%u, [r%u]",
3683 /* two indexed modes will write back rn */
3684 if (opcode
& (1 << 21)) {
3685 if (opcode
& (1 << 24)) /* pre-indexed */
3687 else { /* post-indexed */
3694 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3695 mnemonic
, rt
, rd
, rn
, p1
,
3696 (opcode
& (1 << 23)) ? "" : "-",
3701 address
= thumb_alignpc4(address
);
3703 if (opcode
& (1 << 23))
3707 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3708 mnemonic
, rt
, rd
, address
);
3712 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3713 struct arm_instruction
*instruction
, char *cp
)
3715 int op
= (opcode
>> 21) & 0xf;
3716 int rd
= (opcode
>> 8) & 0xf;
3717 int rn
= (opcode
>> 16) & 0xf;
3718 int type
= (opcode
>> 4) & 0x3;
3719 int immed
= (opcode
>> 6) & 0x3;
3723 immed
|= (opcode
>> 10) & 0x1c;
3724 if (opcode
& (1 << 20))
3730 if (!(opcode
& (1 << 20)))
3731 return ERROR_COMMAND_SYNTAX_ERROR
;
3732 instruction
->type
= ARM_TST
;
3737 instruction
->type
= ARM_AND
;
3741 instruction
->type
= ARM_BIC
;
3746 instruction
->type
= ARM_MOV
;
3750 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3752 (int) (opcode
& 0xf));
3765 sprintf(cp
, "RRX%s\tr%d, r%d",
3767 (int) (opcode
& 0xf));
3775 instruction
->type
= ARM_ORR
;
3781 instruction
->type
= ARM_MVN
;
3786 /* instruction->type = ARM_ORN; */
3792 if (!(opcode
& (1 << 20)))
3793 return ERROR_COMMAND_SYNTAX_ERROR
;
3794 instruction
->type
= ARM_TEQ
;
3799 instruction
->type
= ARM_EOR
;
3804 if (!(opcode
& (1 << 20)))
3805 return ERROR_COMMAND_SYNTAX_ERROR
;
3806 instruction
->type
= ARM_CMN
;
3811 instruction
->type
= ARM_ADD
;
3815 instruction
->type
= ARM_ADC
;
3819 instruction
->type
= ARM_SBC
;
3824 if (!(opcode
& (1 << 21)))
3825 return ERROR_COMMAND_SYNTAX_ERROR
;
3826 instruction
->type
= ARM_CMP
;
3831 instruction
->type
= ARM_SUB
;
3835 instruction
->type
= ARM_RSB
;
3839 return ERROR_COMMAND_SYNTAX_ERROR
;
3842 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3843 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3866 strcpy(cp
, ", RRX");
3872 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3876 sprintf(cp
, "%s%s.W\tr%d, r%d",
3877 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3881 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3882 mnemonic
, suffix
, rd
,
3883 (int) (opcode
& 0xf), immed
? immed
: 32);
3887 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3888 struct arm_instruction
*instruction
, char *cp
)
3893 if (((opcode
>> 4) & 0xf) == 0) {
3894 switch ((opcode
>> 21) & 0x7) {
3908 return ERROR_COMMAND_SYNTAX_ERROR
;
3911 instruction
->type
= ARM_MOV
;
3912 if (opcode
& (1 << 20))
3914 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3916 (int) (opcode
>> 8) & 0xf,
3917 (int) (opcode
>> 16) & 0xf,
3918 (int) (opcode
>> 0) & 0xf);
3920 } else if (opcode
& (1 << 7)) {
3921 switch ((opcode
>> 20) & 0xf) {
3926 switch ((opcode
>> 4) & 0x3) {
3928 suffix
= ", ROR #8";
3931 suffix
= ", ROR #16";
3934 suffix
= ", ROR #24";
3937 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3938 (opcode
& (1 << 24)) ? 'U' : 'S',
3939 (opcode
& (1 << 26)) ? 'B' : 'H',
3940 (int) (opcode
>> 8) & 0xf,
3941 (int) (opcode
>> 0) & 0xf,
3948 if (opcode
& (1 << 6))
3949 return ERROR_COMMAND_SYNTAX_ERROR
;
3950 if (((opcode
>> 12) & 0xf) != 0xf)
3951 return ERROR_COMMAND_SYNTAX_ERROR
;
3952 if (!(opcode
& (1 << 20)))
3953 return ERROR_COMMAND_SYNTAX_ERROR
;
3955 switch (((opcode
>> 19) & 0x04)
3956 | ((opcode
>> 4) & 0x3)) {
3961 mnemonic
= "REV16.W";
3967 mnemonic
= "REVSH.W";
3973 return ERROR_COMMAND_SYNTAX_ERROR
;
3975 sprintf(cp
, "%s\tr%d, r%d",
3977 (int) (opcode
>> 8) & 0xf,
3978 (int) (opcode
>> 0) & 0xf);
3981 return ERROR_COMMAND_SYNTAX_ERROR
;
3988 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3989 struct arm_instruction
*instruction
, char *cp
)
3991 int rn
= (opcode
>> 16) & 0xf;
3994 instruction
->type
= ARM_LDR
;
3997 immed
= opcode
& 0x0fff;
3998 if ((opcode
& (1 << 23)) == 0)
4000 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4001 (int) (opcode
>> 12) & 0xf,
4002 thumb_alignpc4(address
) + immed
);
4006 if (opcode
& (1 << 23)) {
4007 immed
= opcode
& 0x0fff;
4008 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4009 (int) (opcode
>> 12) & 0xf,
4014 if (!(opcode
& (0x3f << 6))) {
4015 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4016 (int) (opcode
>> 12) & 0xf,
4018 (int) (opcode
>> 0) & 0xf,
4019 (int) (opcode
>> 4) & 0x3);
4024 if (((opcode
>> 8) & 0xf) == 0xe) {
4025 immed
= opcode
& 0x00ff;
4027 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4028 (int) (opcode
>> 12) & 0xf,
4033 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4034 char *p1
= "]", *p2
= "";
4036 if (!(opcode
& 0x0500))
4037 return ERROR_COMMAND_SYNTAX_ERROR
;
4039 immed
= opcode
& 0x00ff;
4041 /* two indexed modes will write back rn */
4042 if (opcode
& 0x100) {
4043 if (opcode
& 0x400) /* pre-indexed */
4045 else { /* post-indexed */
4051 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4052 (int) (opcode
>> 12) & 0xf,
4054 (opcode
& 0x200) ? "" : "-",
4059 return ERROR_COMMAND_SYNTAX_ERROR
;
4062 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4063 struct arm_instruction
*instruction
, char *cp
)
4065 int rn
= (opcode
>> 16) & 0xf;
4066 int rt
= (opcode
>> 12) & 0xf;
4067 int op2
= (opcode
>> 6) & 0x3f;
4069 char *p1
= "", *p2
= "]";
4072 switch ((opcode
>> 23) & 0x3) {
4074 if ((rn
& rt
) == 0xf) {
4076 immed
= opcode
& 0xfff;
4077 address
= thumb_alignpc4(address
);
4078 if (opcode
& (1 << 23))
4082 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4086 if (rn
== 0x0f && rt
!= 0x0f) {
4088 immed
= opcode
& 0xfff;
4089 address
= thumb_alignpc4(address
);
4090 if (opcode
& (1 << 23))
4094 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4100 if ((op2
& 0x3c) == 0x38) {
4101 immed
= opcode
& 0xff;
4102 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4103 rt
, rn
, immed
, immed
);
4106 if ((op2
& 0x3c) == 0x30) {
4108 immed
= opcode
& 0xff;
4111 p1
= (opcode
& (1 << 21)) ? "W" : "";
4112 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4113 p1
, rn
, immed
, immed
);
4118 immed
= opcode
& 0xff;
4119 if (!(opcode
& 0x200))
4122 /* two indexed modes will write back rn */
4123 if (opcode
& 0x100) {
4124 if (opcode
& 0x400) /* pre-indexed */
4126 else { /* post-indexed */
4132 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4133 mnemonic
, rt
, rn
, p1
,
4137 if ((op2
& 0x24) == 0x24) {
4139 goto ldrxb_immediate_t3
;
4142 int rm
= opcode
& 0xf;
4145 sprintf(cp
, "PLD\t");
4147 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4148 immed
= (opcode
>> 4) & 0x3;
4150 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4155 if ((rn
& rt
) == 0xf)
4158 immed
= opcode
& 0xfff;
4159 goto preload_immediate
;
4163 mnemonic
= "LDRB.W";
4164 immed
= opcode
& 0xfff;
4165 goto ldrxb_immediate_t2
;
4167 if ((rn
& rt
) == 0xf) {
4168 immed
= opcode
& 0xfff;
4169 address
= thumb_alignpc4(address
);
4170 if (opcode
& (1 << 23))
4174 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4177 if (rn
== 0xf && rt
!= 0xf) {
4179 immed
= opcode
& 0xfff;
4180 address
= thumb_alignpc4(address
);
4181 if (opcode
& (1 << 23))
4185 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4190 if ((op2
& 0x3c) == 0x38) {
4191 immed
= opcode
& 0xff;
4192 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4193 rt
, rn
, immed
, immed
);
4196 if ((op2
& 0x3c) == 0x30) {
4198 immed
= opcode
& 0xff;
4199 immed
= -immed
; /* pli */
4200 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4205 goto ldrxb_immediate_t3
;
4207 if ((op2
& 0x24) == 0x24) {
4209 goto ldrxb_immediate_t3
;
4212 int rm
= opcode
& 0xf;
4215 sprintf(cp
, "PLI\t");
4217 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4218 immed
= (opcode
>> 4) & 0x3;
4220 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4226 immed
= opcode
& 0xfff;
4227 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4233 immed
= opcode
& 0xfff;
4235 goto ldrxb_immediate_t2
;
4238 return ERROR_COMMAND_SYNTAX_ERROR
;
4241 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4242 struct arm_instruction
*instruction
, char *cp
)
4244 int rn
= (opcode
>> 16) & 0xf;
4245 int rt
= (opcode
>> 12) & 0xf;
4246 int op2
= (opcode
>> 6) & 0x3f;
4251 sprintf(cp
, "HINT (UNALLOCATED)");
4255 if (opcode
& (1 << 24))
4258 if ((opcode
& (1 << 23)) == 0) {
4261 immed
= opcode
& 0xfff;
4262 address
= thumb_alignpc4(address
);
4263 if (opcode
& (1 << 23))
4267 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4272 int rm
= opcode
& 0xf;
4274 immed
= (opcode
>> 4) & 0x3;
4275 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4276 sign
, rt
, rn
, rm
, immed
);
4279 if ((op2
& 0x3c) == 0x38) {
4280 immed
= opcode
& 0xff;
4281 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4282 sign
, rt
, rn
, immed
, immed
);
4285 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4286 char *p1
= "", *p2
= "]";
4288 immed
= opcode
& 0xff;
4289 if (!(opcode
& 0x200))
4292 /* two indexed modes will write back rn */
4293 if (opcode
& 0x100) {
4294 if (opcode
& 0x400) /* pre-indexed */
4296 else { /* post-indexed */
4301 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4302 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4309 immed
= opcode
& 0xfff;
4310 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4311 sign
, *sign
? "" : ".W",
4312 rt
, rn
, immed
, immed
);
4316 return ERROR_COMMAND_SYNTAX_ERROR
;
4320 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4321 * always set. That means eventual arm_simulate_step() support for Thumb2
4322 * will need work in this area.
4324 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4331 /* clear low bit ... it's set on function pointers */
4334 /* clear fields, to avoid confusion */
4335 memset(instruction
, 0, sizeof(struct arm_instruction
));
4337 /* read first halfword, see if this is the only one */
4338 retval
= target_read_u16(target
, address
, &op
);
4339 if (retval
!= ERROR_OK
)
4342 switch (op
& 0xf800) {
4346 /* 32-bit instructions */
4347 instruction
->instruction_size
= 4;
4349 retval
= target_read_u16(target
, address
+ 2, &op
);
4350 if (retval
!= ERROR_OK
)
4353 instruction
->opcode
= opcode
;
4356 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4357 return thumb_evaluate_opcode(op
, address
, instruction
);
4360 snprintf(instruction
->text
, 128,
4361 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4363 cp
= strchr(instruction
->text
, 0);
4364 retval
= ERROR_FAIL
;
4366 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4367 if ((opcode
& 0x1a008000) == 0x10000000)
4368 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4370 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4371 else if ((opcode
& 0x1a008000) == 0x12000000)
4372 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4374 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4375 else if ((opcode
& 0x18008000) == 0x10008000)
4376 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4378 /* ARMv7-M: A5.3.5 Load/store multiple */
4379 else if ((opcode
& 0x1e400000) == 0x08000000)
4380 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4382 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4383 else if ((opcode
& 0x1e400000) == 0x08400000)
4384 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4386 /* ARMv7-M: A5.3.7 Load word */
4387 else if ((opcode
& 0x1f700000) == 0x18500000)
4388 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4390 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4391 else if ((opcode
& 0x1e700000) == 0x18300000)
4392 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4394 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4395 else if ((opcode
& 0x1e700000) == 0x18100000)
4396 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4398 /* ARMv7-M: A5.3.10 Store single data item */
4399 else if ((opcode
& 0x1f100000) == 0x18000000)
4400 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4402 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4403 else if ((opcode
& 0x1e000000) == 0x0a000000)
4404 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4406 /* ARMv7-M: A5.3.12 Data processing (register)
4407 * and A5.3.13 Miscellaneous operations
4409 else if ((opcode
& 0x1f000000) == 0x1a000000)
4410 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4412 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4413 else if ((opcode
& 0x1f800000) == 0x1b000000)
4414 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4416 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4417 else if ((opcode
& 0x1f800000) == 0x1b800000)
4418 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4420 if (retval
== ERROR_OK
)
4424 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4425 * instructions; not yet handled here.
4428 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4429 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4430 strcpy(cp
, "UNDEFINED OPCODE");
4434 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4437 strcpy(cp
, "(32-bit Thumb2 ...)");
4441 int arm_access_size(struct arm_instruction
*instruction
)
4443 if ((instruction
->type
== ARM_LDRB
)
4444 || (instruction
->type
== ARM_LDRBT
)
4445 || (instruction
->type
== ARM_LDRSB
)
4446 || (instruction
->type
== ARM_STRB
)
4447 || (instruction
->type
== ARM_STRBT
))
4449 else if ((instruction
->type
== ARM_LDRH
)
4450 || (instruction
->type
== ARM_LDRSH
)
4451 || (instruction
->type
== ARM_STRH
))
4453 else if ((instruction
->type
== ARM_LDR
)
4454 || (instruction
->type
== ARM_LDRT
)
4455 || (instruction
->type
== ARM_STR
)
4456 || (instruction
->type
== ARM_STRT
))
4458 else if ((instruction
->type
== ARM_LDRD
)
4459 || (instruction
->type
== ARM_STRD
))
4462 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)