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
);
3304 /* signed/unsigned saturated add */
3305 immed
= (opcode
>> 6) & 0x03;
3306 immed
|= (opcode
>> 10) & 0x1c;
3307 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3308 is_signed
? "S" : "U",
3309 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3310 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3311 immed
? immed
: 32);
3317 /* signed/unsigned bitfield extract */
3318 immed
= (opcode
>> 6) & 0x03;
3319 immed
|= (opcode
>> 10) & 0x1c;
3320 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3321 is_signed
? "S" : "U",
3323 (int) (opcode
& 0x1f) + 1);
3326 immed
= (opcode
>> 6) & 0x03;
3327 immed
|= (opcode
>> 10) & 0x1c;
3328 if (rn
== 0xf) /* bitfield clear */
3329 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3331 (int) (opcode
& 0x1f) + 1 - immed
);
3332 else /* bitfield insert */
3333 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3335 (int) (opcode
& 0x1f) + 1 - immed
);
3338 return ERROR_COMMAND_SYNTAX_ERROR
;
3341 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3342 rd
, rn
, immed
, immed
);
3346 address
= thumb_alignpc4(address
);
3351 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3352 * not hiding the pc-relative stuff will sometimes be useful.
3354 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3358 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3359 struct arm_instruction
*instruction
, char *cp
)
3361 unsigned op
= (opcode
>> 20) & 0xf;
3367 unsigned rn
= (opcode
>> 16) & 0x0f;
3368 unsigned rt
= (opcode
>> 12) & 0x0f;
3371 return ERROR_COMMAND_SYNTAX_ERROR
;
3373 if (opcode
& 0x0800)
3408 return ERROR_COMMAND_SYNTAX_ERROR
;
3411 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3412 size
, rt
, rn
, (int) opcode
& 0x0f,
3413 (int) (opcode
>> 4) & 0x03);
3417 immed
= opcode
& 0x0fff;
3418 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3419 size
, rt
, rn
, immed
, immed
);
3423 immed
= opcode
& 0x00ff;
3425 switch (opcode
& 0x700) {
3431 return ERROR_COMMAND_SYNTAX_ERROR
;
3434 /* two indexed modes will write back rn */
3435 if (opcode
& 0x100) {
3436 if (opcode
& 0x400) /* pre-indexed */
3438 else { /* post-indexed */
3444 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3445 size
, suffix
, rt
, rn
, p1
,
3446 (opcode
& 0x200) ? "" : "-",
3451 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3452 struct arm_instruction
*instruction
, char *cp
)
3454 int ra
= (opcode
>> 12) & 0xf;
3456 switch (opcode
& 0x007000f0) {
3459 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3460 (int) (opcode
>> 8) & 0xf,
3461 (int) (opcode
>> 16) & 0xf,
3462 (int) (opcode
>> 0) & 0xf);
3464 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3465 (int) (opcode
>> 8) & 0xf,
3466 (int) (opcode
>> 16) & 0xf,
3467 (int) (opcode
>> 0) & 0xf, ra
);
3470 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3471 (int) (opcode
>> 8) & 0xf,
3472 (int) (opcode
>> 16) & 0xf,
3473 (int) (opcode
>> 0) & 0xf, ra
);
3476 return ERROR_COMMAND_SYNTAX_ERROR
;
3481 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3482 struct arm_instruction
*instruction
, char *cp
)
3484 int op
= (opcode
>> 4) & 0xf;
3485 char *infix
= "MUL";
3487 op
+= (opcode
>> 16) & 0x70;
3495 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3496 (op
& 0x20) ? 'U' : 'S',
3498 (int) (opcode
>> 12) & 0xf,
3499 (int) (opcode
>> 8) & 0xf,
3500 (int) (opcode
>> 16) & 0xf,
3501 (int) (opcode
>> 0) & 0xf);
3505 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3506 (op
& 0x20) ? 'U' : 'S',
3507 (int) (opcode
>> 8) & 0xf,
3508 (int) (opcode
>> 16) & 0xf,
3509 (int) (opcode
>> 0) & 0xf);
3512 return ERROR_COMMAND_SYNTAX_ERROR
;
3518 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3519 struct arm_instruction
*instruction
, char *cp
)
3521 int rn
= (opcode
>> 16) & 0xf;
3522 int op
= (opcode
>> 22) & 0x6;
3523 int t
= (opcode
>> 21) & 1;
3524 unsigned registers
= opcode
& 0xffff;
3527 if (opcode
& (1 << 20))
3535 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3537 (unsigned) (opcode
& 0x1f));
3543 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3544 (unsigned) ((opcode
>> 16) & 0xf),
3548 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3552 sprintf(cp
, "POP.W\t");
3554 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3558 sprintf(cp
, "PUSH.W\t");
3560 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3563 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3566 return ERROR_COMMAND_SYNTAX_ERROR
;
3571 for (t
= 0; registers
; t
++, registers
>>= 1) {
3572 if ((registers
& 1) == 0)
3575 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3584 /* load/store dual or exclusive, table branch */
3585 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3586 struct arm_instruction
*instruction
, char *cp
)
3588 unsigned op1op2
= (opcode
>> 20) & 0x3;
3589 unsigned op3
= (opcode
>> 4) & 0xf;
3591 unsigned rn
= (opcode
>> 16) & 0xf;
3592 unsigned rt
= (opcode
>> 12) & 0xf;
3593 unsigned rd
= (opcode
>> 8) & 0xf;
3594 unsigned imm
= opcode
& 0xff;
3598 op1op2
|= (opcode
>> 21) & 0xc;
3628 mnemonic
= "STREXB";
3631 mnemonic
= "STREXH";
3634 return ERROR_COMMAND_SYNTAX_ERROR
;
3642 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3645 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3648 mnemonic
= "LDREXB";
3651 mnemonic
= "LDREXH";
3654 return ERROR_COMMAND_SYNTAX_ERROR
;
3659 return ERROR_COMMAND_SYNTAX_ERROR
;
3664 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3665 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3667 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3668 mnemonic
, rd
, rt
, rn
);
3674 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3675 mnemonic
, rt
, rn
, imm
, imm
);
3677 sprintf(cp
, "%s\tr%u, [r%u]",
3682 /* two indexed modes will write back rn */
3683 if (opcode
& (1 << 21)) {
3684 if (opcode
& (1 << 24)) /* pre-indexed */
3686 else { /* post-indexed */
3693 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3694 mnemonic
, rt
, rd
, rn
, p1
,
3695 (opcode
& (1 << 23)) ? "" : "-",
3700 address
= thumb_alignpc4(address
);
3702 if (opcode
& (1 << 23))
3706 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3707 mnemonic
, rt
, rd
, address
);
3711 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3712 struct arm_instruction
*instruction
, char *cp
)
3714 int op
= (opcode
>> 21) & 0xf;
3715 int rd
= (opcode
>> 8) & 0xf;
3716 int rn
= (opcode
>> 16) & 0xf;
3717 int type
= (opcode
>> 4) & 0x3;
3718 int immed
= (opcode
>> 6) & 0x3;
3722 immed
|= (opcode
>> 10) & 0x1c;
3723 if (opcode
& (1 << 20))
3729 if (!(opcode
& (1 << 20)))
3730 return ERROR_COMMAND_SYNTAX_ERROR
;
3731 instruction
->type
= ARM_TST
;
3736 instruction
->type
= ARM_AND
;
3740 instruction
->type
= ARM_BIC
;
3745 instruction
->type
= ARM_MOV
;
3749 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3751 (int) (opcode
& 0xf));
3764 sprintf(cp
, "RRX%s\tr%d, r%d",
3766 (int) (opcode
& 0xf));
3774 instruction
->type
= ARM_ORR
;
3780 instruction
->type
= ARM_MVN
;
3785 /* instruction->type = ARM_ORN; */
3791 if (!(opcode
& (1 << 20)))
3792 return ERROR_COMMAND_SYNTAX_ERROR
;
3793 instruction
->type
= ARM_TEQ
;
3798 instruction
->type
= ARM_EOR
;
3803 if (!(opcode
& (1 << 20)))
3804 return ERROR_COMMAND_SYNTAX_ERROR
;
3805 instruction
->type
= ARM_CMN
;
3810 instruction
->type
= ARM_ADD
;
3814 instruction
->type
= ARM_ADC
;
3818 instruction
->type
= ARM_SBC
;
3823 if (!(opcode
& (1 << 21)))
3824 return ERROR_COMMAND_SYNTAX_ERROR
;
3825 instruction
->type
= ARM_CMP
;
3830 instruction
->type
= ARM_SUB
;
3834 instruction
->type
= ARM_RSB
;
3838 return ERROR_COMMAND_SYNTAX_ERROR
;
3841 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3842 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3865 strcpy(cp
, ", RRX");
3871 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3875 sprintf(cp
, "%s%s.W\tr%d, r%d",
3876 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3880 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3881 mnemonic
, suffix
, rd
,
3882 (int) (opcode
& 0xf), immed
? immed
: 32);
3886 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3887 struct arm_instruction
*instruction
, char *cp
)
3892 if (((opcode
>> 4) & 0xf) == 0) {
3893 switch ((opcode
>> 21) & 0x7) {
3907 return ERROR_COMMAND_SYNTAX_ERROR
;
3910 instruction
->type
= ARM_MOV
;
3911 if (opcode
& (1 << 20))
3913 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3915 (int) (opcode
>> 8) & 0xf,
3916 (int) (opcode
>> 16) & 0xf,
3917 (int) (opcode
>> 0) & 0xf);
3919 } else if (opcode
& (1 << 7)) {
3920 switch ((opcode
>> 20) & 0xf) {
3925 switch ((opcode
>> 4) & 0x3) {
3927 suffix
= ", ROR #8";
3930 suffix
= ", ROR #16";
3933 suffix
= ", ROR #24";
3936 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3937 (opcode
& (1 << 24)) ? 'U' : 'S',
3938 (opcode
& (1 << 26)) ? 'B' : 'H',
3939 (int) (opcode
>> 8) & 0xf,
3940 (int) (opcode
>> 0) & 0xf,
3947 if (opcode
& (1 << 6))
3948 return ERROR_COMMAND_SYNTAX_ERROR
;
3949 if (((opcode
>> 12) & 0xf) != 0xf)
3950 return ERROR_COMMAND_SYNTAX_ERROR
;
3951 if (!(opcode
& (1 << 20)))
3952 return ERROR_COMMAND_SYNTAX_ERROR
;
3954 switch (((opcode
>> 19) & 0x04)
3955 | ((opcode
>> 4) & 0x3)) {
3960 mnemonic
= "REV16.W";
3966 mnemonic
= "REVSH.W";
3972 return ERROR_COMMAND_SYNTAX_ERROR
;
3974 sprintf(cp
, "%s\tr%d, r%d",
3976 (int) (opcode
>> 8) & 0xf,
3977 (int) (opcode
>> 0) & 0xf);
3980 return ERROR_COMMAND_SYNTAX_ERROR
;
3987 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3988 struct arm_instruction
*instruction
, char *cp
)
3990 int rn
= (opcode
>> 16) & 0xf;
3993 instruction
->type
= ARM_LDR
;
3996 immed
= opcode
& 0x0fff;
3997 if ((opcode
& (1 << 23)) == 0)
3999 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4000 (int) (opcode
>> 12) & 0xf,
4001 thumb_alignpc4(address
) + immed
);
4005 if (opcode
& (1 << 23)) {
4006 immed
= opcode
& 0x0fff;
4007 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4008 (int) (opcode
>> 12) & 0xf,
4013 if (!(opcode
& (0x3f << 6))) {
4014 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4015 (int) (opcode
>> 12) & 0xf,
4017 (int) (opcode
>> 0) & 0xf,
4018 (int) (opcode
>> 4) & 0x3);
4023 if (((opcode
>> 8) & 0xf) == 0xe) {
4024 immed
= opcode
& 0x00ff;
4026 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4027 (int) (opcode
>> 12) & 0xf,
4032 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4033 char *p1
= "]", *p2
= "";
4035 if (!(opcode
& 0x0500))
4036 return ERROR_COMMAND_SYNTAX_ERROR
;
4038 immed
= opcode
& 0x00ff;
4040 /* two indexed modes will write back rn */
4041 if (opcode
& 0x100) {
4042 if (opcode
& 0x400) /* pre-indexed */
4044 else { /* post-indexed */
4050 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4051 (int) (opcode
>> 12) & 0xf,
4053 (opcode
& 0x200) ? "" : "-",
4058 return ERROR_COMMAND_SYNTAX_ERROR
;
4061 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4062 struct arm_instruction
*instruction
, char *cp
)
4064 int rn
= (opcode
>> 16) & 0xf;
4065 int rt
= (opcode
>> 12) & 0xf;
4066 int op2
= (opcode
>> 6) & 0x3f;
4068 char *p1
= "", *p2
= "]";
4071 switch ((opcode
>> 23) & 0x3) {
4073 if ((rn
& rt
) == 0xf) {
4075 immed
= opcode
& 0xfff;
4076 address
= thumb_alignpc4(address
);
4077 if (opcode
& (1 << 23))
4081 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4085 if (rn
== 0x0f && rt
!= 0x0f) {
4087 immed
= opcode
& 0xfff;
4088 address
= thumb_alignpc4(address
);
4089 if (opcode
& (1 << 23))
4093 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4099 if ((op2
& 0x3c) == 0x38) {
4100 immed
= opcode
& 0xff;
4101 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4102 rt
, rn
, immed
, immed
);
4105 if ((op2
& 0x3c) == 0x30) {
4107 immed
= opcode
& 0xff;
4110 p1
= (opcode
& (1 << 21)) ? "W" : "";
4111 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4112 p1
, rn
, immed
, immed
);
4117 immed
= opcode
& 0xff;
4118 if (!(opcode
& 0x200))
4121 /* two indexed modes will write back rn */
4122 if (opcode
& 0x100) {
4123 if (opcode
& 0x400) /* pre-indexed */
4125 else { /* post-indexed */
4131 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4132 mnemonic
, rt
, rn
, p1
,
4136 if ((op2
& 0x24) == 0x24) {
4138 goto ldrxb_immediate_t3
;
4141 int rm
= opcode
& 0xf;
4144 sprintf(cp
, "PLD\t");
4146 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4147 immed
= (opcode
>> 4) & 0x3;
4149 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4154 if ((rn
& rt
) == 0xf)
4157 immed
= opcode
& 0xfff;
4158 goto preload_immediate
;
4162 mnemonic
= "LDRB.W";
4163 immed
= opcode
& 0xfff;
4164 goto ldrxb_immediate_t2
;
4166 if ((rn
& rt
) == 0xf) {
4167 immed
= opcode
& 0xfff;
4168 address
= thumb_alignpc4(address
);
4169 if (opcode
& (1 << 23))
4173 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4176 if (rn
== 0xf && rt
!= 0xf) {
4178 immed
= opcode
& 0xfff;
4179 address
= thumb_alignpc4(address
);
4180 if (opcode
& (1 << 23))
4184 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4189 if ((op2
& 0x3c) == 0x38) {
4190 immed
= opcode
& 0xff;
4191 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4192 rt
, rn
, immed
, immed
);
4195 if ((op2
& 0x3c) == 0x30) {
4197 immed
= opcode
& 0xff;
4198 immed
= -immed
; /* pli */
4199 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4204 goto ldrxb_immediate_t3
;
4206 if ((op2
& 0x24) == 0x24) {
4208 goto ldrxb_immediate_t3
;
4211 int rm
= opcode
& 0xf;
4214 sprintf(cp
, "PLI\t");
4216 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4217 immed
= (opcode
>> 4) & 0x3;
4219 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4225 immed
= opcode
& 0xfff;
4226 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4232 immed
= opcode
& 0xfff;
4234 goto ldrxb_immediate_t2
;
4237 return ERROR_COMMAND_SYNTAX_ERROR
;
4240 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4241 struct arm_instruction
*instruction
, char *cp
)
4243 int rn
= (opcode
>> 16) & 0xf;
4244 int rt
= (opcode
>> 12) & 0xf;
4245 int op2
= (opcode
>> 6) & 0x3f;
4250 sprintf(cp
, "HINT (UNALLOCATED)");
4254 if (opcode
& (1 << 24))
4257 if ((opcode
& (1 << 23)) == 0) {
4260 immed
= opcode
& 0xfff;
4261 address
= thumb_alignpc4(address
);
4262 if (opcode
& (1 << 23))
4266 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4271 int rm
= opcode
& 0xf;
4273 immed
= (opcode
>> 4) & 0x3;
4274 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4275 sign
, rt
, rn
, rm
, immed
);
4278 if ((op2
& 0x3c) == 0x38) {
4279 immed
= opcode
& 0xff;
4280 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4281 sign
, rt
, rn
, immed
, immed
);
4284 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4285 char *p1
= "", *p2
= "]";
4287 immed
= opcode
& 0xff;
4288 if (!(opcode
& 0x200))
4291 /* two indexed modes will write back rn */
4292 if (opcode
& 0x100) {
4293 if (opcode
& 0x400) /* pre-indexed */
4295 else { /* post-indexed */
4300 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4301 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4308 immed
= opcode
& 0xfff;
4309 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4310 sign
, *sign
? "" : ".W",
4311 rt
, rn
, immed
, immed
);
4315 return ERROR_COMMAND_SYNTAX_ERROR
;
4319 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4320 * always set. That means eventual arm_simulate_step() support for Thumb2
4321 * will need work in this area.
4323 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4330 /* clear low bit ... it's set on function pointers */
4333 /* clear fields, to avoid confusion */
4334 memset(instruction
, 0, sizeof(struct arm_instruction
));
4336 /* read first halfword, see if this is the only one */
4337 retval
= target_read_u16(target
, address
, &op
);
4338 if (retval
!= ERROR_OK
)
4341 switch (op
& 0xf800) {
4345 /* 32-bit instructions */
4346 instruction
->instruction_size
= 4;
4348 retval
= target_read_u16(target
, address
+ 2, &op
);
4349 if (retval
!= ERROR_OK
)
4352 instruction
->opcode
= opcode
;
4355 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4356 return thumb_evaluate_opcode(op
, address
, instruction
);
4359 snprintf(instruction
->text
, 128,
4360 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4362 cp
= strchr(instruction
->text
, 0);
4363 retval
= ERROR_FAIL
;
4365 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4366 if ((opcode
& 0x1a008000) == 0x10000000)
4367 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4369 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4370 else if ((opcode
& 0x1a008000) == 0x12000000)
4371 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4373 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4374 else if ((opcode
& 0x18008000) == 0x10008000)
4375 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4377 /* ARMv7-M: A5.3.5 Load/store multiple */
4378 else if ((opcode
& 0x1e400000) == 0x08000000)
4379 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4381 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4382 else if ((opcode
& 0x1e400000) == 0x08400000)
4383 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4385 /* ARMv7-M: A5.3.7 Load word */
4386 else if ((opcode
& 0x1f700000) == 0x18500000)
4387 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4389 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4390 else if ((opcode
& 0x1e700000) == 0x18300000)
4391 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4393 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4394 else if ((opcode
& 0x1e700000) == 0x18100000)
4395 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4397 /* ARMv7-M: A5.3.10 Store single data item */
4398 else if ((opcode
& 0x1f100000) == 0x18000000)
4399 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4401 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4402 else if ((opcode
& 0x1e000000) == 0x0a000000)
4403 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4405 /* ARMv7-M: A5.3.12 Data processing (register)
4406 * and A5.3.13 Miscellaneous operations
4408 else if ((opcode
& 0x1f000000) == 0x1a000000)
4409 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4411 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4412 else if ((opcode
& 0x1f800000) == 0x1b000000)
4413 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4415 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4416 else if ((opcode
& 0x1f800000) == 0x1b800000)
4417 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4419 if (retval
== ERROR_OK
)
4423 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4424 * instructions; not yet handled here.
4427 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4428 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4429 strcpy(cp
, "UNDEFINED OPCODE");
4433 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4436 strcpy(cp
, "(32-bit Thumb2 ...)");
4440 int arm_access_size(struct arm_instruction
*instruction
)
4442 if ((instruction
->type
== ARM_LDRB
)
4443 || (instruction
->type
== ARM_LDRBT
)
4444 || (instruction
->type
== ARM_LDRSB
)
4445 || (instruction
->type
== ARM_STRB
)
4446 || (instruction
->type
== ARM_STRBT
))
4448 else if ((instruction
->type
== ARM_LDRH
)
4449 || (instruction
->type
== ARM_LDRSH
)
4450 || (instruction
->type
== ARM_STRH
))
4452 else if ((instruction
->type
== ARM_LDR
)
4453 || (instruction
->type
== ARM_LDRT
)
4454 || (instruction
->type
== ARM_STR
)
4455 || (instruction
->type
== ARM_STRT
))
4457 else if ((instruction
->type
== ARM_LDRD
)
4458 || (instruction
->type
== ARM_STRD
))
4461 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)