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...",
133 if ((opcode
& 0x07f000f0) == 0x05700040) {
134 instruction
->type
= ARM_DSB
;
137 switch (opcode
& 0x0000000f) {
166 snprintf(instruction
->text
,
168 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tDSB %s",
169 address
, opcode
, opt
);
173 return evaluate_unknown(opcode
, address
, instruction
);
176 static int evaluate_srs(uint32_t opcode
,
177 uint32_t address
, struct arm_instruction
*instruction
)
179 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
180 const char *mode
= "";
182 switch ((opcode
>> 23) & 0x3) {
187 /* "IA" is default */
197 switch (opcode
& 0x0e500000) {
199 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
201 "\tSRS%s\tSP%s, #%d",
204 (unsigned)(opcode
& 0x1f));
207 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
212 (unsigned)((opcode
>> 16) & 0xf), wback
);
215 return evaluate_unknown(opcode
, address
, instruction
);
220 static int evaluate_swi(uint32_t opcode
,
221 uint32_t address
, struct arm_instruction
*instruction
)
223 instruction
->type
= ARM_SWI
;
225 snprintf(instruction
->text
, 128,
226 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
227 address
, opcode
, (opcode
& 0xffffff));
232 static int evaluate_blx_imm(uint32_t opcode
,
233 uint32_t address
, struct arm_instruction
*instruction
)
237 uint32_t target_address
;
239 instruction
->type
= ARM_BLX
;
240 immediate
= opcode
& 0x00ffffff;
242 /* sign extend 24-bit immediate */
243 if (immediate
& 0x00800000)
244 offset
= 0xff000000 | immediate
;
248 /* shift two bits left */
251 /* odd/event halfword */
252 if (opcode
& 0x01000000)
255 target_address
= address
+ 8 + offset
;
257 snprintf(instruction
->text
,
259 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"",
264 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
265 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
270 static int evaluate_b_bl(uint32_t opcode
,
271 uint32_t address
, struct arm_instruction
*instruction
)
276 uint32_t target_address
;
278 immediate
= opcode
& 0x00ffffff;
279 L
= (opcode
& 0x01000000) >> 24;
281 /* sign extend 24-bit immediate */
282 if (immediate
& 0x00800000)
283 offset
= 0xff000000 | immediate
;
287 /* shift two bits left */
290 target_address
= address
+ 8 + offset
;
293 instruction
->type
= ARM_BL
;
295 instruction
->type
= ARM_B
;
297 snprintf(instruction
->text
,
299 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
,
306 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
307 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
312 /* Coprocessor load/store and double register transfers
313 * both normal and extended instruction space (condition field b1111) */
314 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
315 uint32_t address
, struct arm_instruction
*instruction
)
317 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
320 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c500000)) {
321 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
324 cp_opcode
= (opcode
& 0xf0) >> 4;
325 Rd
= (opcode
& 0xf000) >> 12;
326 Rn
= (opcode
& 0xf0000) >> 16;
327 CRm
= (opcode
& 0xf);
330 if ((opcode
& 0x0ff00000) == 0x0c400000) {
331 instruction
->type
= ARM_MCRR
;
333 } else if ((opcode
& 0x0ff00000) == 0x0c500000) {
335 instruction
->type
= ARM_MRRC
;
338 LOG_ERROR("Unknown instruction");
342 snprintf(instruction
->text
, 128,
343 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
344 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
345 address
, opcode
, mnemonic
,
346 ((opcode
& 0xf0000000) == 0xf0000000)
347 ? "2" : COND(opcode
),
348 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
349 } else {/* LDC or STC */
350 uint8_t CRd
, Rn
, offset
;
353 char addressing_mode
[32];
355 CRd
= (opcode
& 0xf000) >> 12;
356 Rn
= (opcode
& 0xf0000) >> 16;
357 offset
= (opcode
& 0xff) << 2;
360 if (opcode
& 0x00100000) {
361 instruction
->type
= ARM_LDC
;
364 instruction
->type
= ARM_STC
;
368 U
= (opcode
& 0x00800000) >> 23;
370 /* addressing modes */
371 if ((opcode
& 0x01200000) == 0x01000000)/* offset */
372 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
373 Rn
, U
? "" : "-", offset
);
374 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
375 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
376 Rn
, U
? "" : "-", offset
);
377 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
378 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
379 Rn
, U
? "" : "-", offset
);
380 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
381 snprintf(addressing_mode
, 32, "[r%i], {%d}",
384 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
386 "\t%s%s%s p%i, c%i, %s",
387 address
, opcode
, mnemonic
,
388 ((opcode
& 0xf0000000) == 0xf0000000)
389 ? "2" : COND(opcode
),
390 (opcode
& (1 << 22)) ? "L" : "",
391 cp_num
, CRd
, addressing_mode
);
397 /* Coprocessor data processing instructions
398 * Coprocessor register transfer instructions
399 * both normal and extended instruction space (condition field b1111) */
400 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
401 uint32_t address
, struct arm_instruction
*instruction
)
405 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
407 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
408 cp_num
= (opcode
& 0xf00) >> 8;
409 CRd_Rd
= (opcode
& 0xf000) >> 12;
410 CRn
= (opcode
& 0xf0000) >> 16;
411 CRm
= (opcode
& 0xf);
412 opcode_2
= (opcode
& 0xe0) >> 5;
415 if (opcode
& 0x00000010) { /* bit 4 set -> MRC/MCR */
416 if (opcode
& 0x00100000) { /* bit 20 set -> MRC */
417 instruction
->type
= ARM_MRC
;
419 } else {/* bit 20 not set -> MCR */
420 instruction
->type
= ARM_MCR
;
424 opcode_1
= (opcode
& 0x00e00000) >> 21;
426 snprintf(instruction
->text
,
428 "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",
439 } else {/* bit 4 not set -> CDP */
440 instruction
->type
= ARM_CDP
;
443 opcode_1
= (opcode
& 0x00f00000) >> 20;
445 snprintf(instruction
->text
,
447 "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",
463 /* Load/store instructions */
464 static int evaluate_load_store(uint32_t opcode
,
465 uint32_t address
, struct arm_instruction
*instruction
)
467 uint8_t I
, P
, U
, B
, W
, L
;
469 char *operation
;/* "LDR" or "STR" */
470 char *suffix
; /* "", "B", "T", "BT" */
474 I
= (opcode
& 0x02000000) >> 25;
475 P
= (opcode
& 0x01000000) >> 24;
476 U
= (opcode
& 0x00800000) >> 23;
477 B
= (opcode
& 0x00400000) >> 22;
478 W
= (opcode
& 0x00200000) >> 21;
479 L
= (opcode
& 0x00100000) >> 20;
481 /* target register */
482 Rd
= (opcode
& 0xf000) >> 12;
485 Rn
= (opcode
& 0xf0000) >> 16;
487 instruction
->info
.load_store
.Rd
= Rd
;
488 instruction
->info
.load_store
.Rn
= Rn
;
489 instruction
->info
.load_store
.U
= U
;
491 /* determine operation */
497 /* determine instruction type and suffix */
499 if ((P
== 0) && (W
== 1)) {
501 instruction
->type
= ARM_LDRBT
;
503 instruction
->type
= ARM_STRBT
;
507 instruction
->type
= ARM_LDRB
;
509 instruction
->type
= ARM_STRB
;
513 if ((P
== 0) && (W
== 1)) {
515 instruction
->type
= ARM_LDRT
;
517 instruction
->type
= ARM_STRT
;
521 instruction
->type
= ARM_LDR
;
523 instruction
->type
= ARM_STR
;
528 if (!I
) { /* #+-<offset_12> */
529 uint32_t offset_12
= (opcode
& 0xfff);
531 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
533 snprintf(offset
, 32, "%s", "");
535 instruction
->info
.load_store
.offset_mode
= 0;
536 instruction
->info
.load_store
.offset
.offset
= offset_12
;
537 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
538 uint8_t shift_imm
, shift
;
541 shift_imm
= (opcode
& 0xf80) >> 7;
542 shift
= (opcode
& 0x60) >> 5;
545 /* LSR encodes a shift by 32 bit as 0x0 */
546 if ((shift
== 0x1) && (shift_imm
== 0x0))
549 /* ASR encodes a shift by 32 bit as 0x0 */
550 if ((shift
== 0x2) && (shift_imm
== 0x0))
553 /* ROR by 32 bit is actually a RRX */
554 if ((shift
== 0x3) && (shift_imm
== 0x0))
557 instruction
->info
.load_store
.offset_mode
= 1;
558 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
559 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
560 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
562 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
563 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
564 else { /* +-<Rm>, <Shift>, #<shift_imm> */
567 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
570 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
573 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
576 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
579 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
586 if (W
== 0) { /* offset */
587 snprintf(instruction
->text
,
589 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
599 instruction
->info
.load_store
.index_mode
= 0;
600 } else {/* pre-indexed */
601 snprintf(instruction
->text
,
603 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
613 instruction
->info
.load_store
.index_mode
= 1;
615 } else {/* post-indexed */
616 snprintf(instruction
->text
,
618 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
628 instruction
->info
.load_store
.index_mode
= 2;
634 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
636 unsigned rm
= (opcode
>> 0) & 0xf;
637 unsigned rd
= (opcode
>> 12) & 0xf;
638 unsigned rn
= (opcode
>> 16) & 0xf;
641 switch ((opcode
>> 24) & 0x3) {
646 sprintf(cp
, "UNDEFINED");
647 return ARM_UNDEFINED_INSTRUCTION
;
656 switch ((opcode
>> 10) & 0x3) {
672 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
673 (opcode
& (1 << 22)) ? 'U' : 'S',
678 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
679 (opcode
& (1 << 22)) ? 'U' : 'S',
686 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
692 switch ((opcode
>> 20) & 0x7) {
715 switch ((opcode
>> 5) & 0x7) {
744 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
745 (int) (opcode
>> 12) & 0xf,
746 (int) (opcode
>> 16) & 0xf,
747 (int) (opcode
>> 0) & 0xf);
751 /* these opcodes might be used someday */
752 sprintf(cp
, "UNDEFINED");
753 return ARM_UNDEFINED_INSTRUCTION
;
756 /* ARMv6 and later support "media" instructions (includes SIMD) */
757 static int evaluate_media(uint32_t opcode
, uint32_t address
,
758 struct arm_instruction
*instruction
)
760 char *cp
= instruction
->text
;
761 char *mnemonic
= NULL
;
764 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
768 /* parallel add/subtract */
769 if ((opcode
& 0x01800000) == 0x00000000) {
770 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
775 if ((opcode
& 0x01f00020) == 0x00800000) {
777 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
779 if (opcode
& (1 << 6)) {
788 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
790 (int) (opcode
>> 12) & 0xf,
791 (int) (opcode
>> 16) & 0xf,
792 (int) (opcode
>> 0) & 0xf,
798 if ((opcode
& 0x01a00020) == 0x00a00000) {
800 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
802 if (opcode
& (1 << 6)) {
809 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
810 (opcode
& (1 << 22)) ? 'U' : 'S',
812 (int) (opcode
>> 12) & 0xf,
813 (int) (opcode
>> 16) & 0x1f,
814 (int) (opcode
>> 0) & 0xf,
820 if ((opcode
& 0x018000f0) == 0x00800070) {
821 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
826 if ((opcode
& 0x01f00080) == 0x01000000) {
827 unsigned rn
= (opcode
>> 12) & 0xf;
830 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
831 (opcode
& (1 << 6)) ? 'S' : 'A',
832 (opcode
& (1 << 5)) ? "X" : "",
834 (int) (opcode
>> 16) & 0xf,
835 (int) (opcode
>> 0) & 0xf,
836 (int) (opcode
>> 8) & 0xf,
839 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
840 (opcode
& (1 << 6)) ? 'S' : 'A',
841 (opcode
& (1 << 5)) ? "X" : "",
843 (int) (opcode
>> 16) & 0xf,
844 (int) (opcode
>> 0) & 0xf,
845 (int) (opcode
>> 8) & 0xf);
848 if ((opcode
& 0x01f00000) == 0x01400000) {
849 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
850 (opcode
& (1 << 6)) ? 'S' : 'A',
851 (opcode
& (1 << 5)) ? "X" : "",
853 (int) (opcode
>> 12) & 0xf,
854 (int) (opcode
>> 16) & 0xf,
855 (int) (opcode
>> 0) & 0xf,
856 (int) (opcode
>> 8) & 0xf);
859 if ((opcode
& 0x01f00000) == 0x01500000) {
860 unsigned rn
= (opcode
>> 12) & 0xf;
862 switch (opcode
& 0xc0) {
874 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
875 (opcode
& (1 << 6)) ? 'S' : 'A',
876 (opcode
& (1 << 5)) ? "R" : "",
878 (int) (opcode
>> 16) & 0xf,
879 (int) (opcode
>> 0) & 0xf,
880 (int) (opcode
>> 8) & 0xf,
883 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
884 (opcode
& (1 << 5)) ? "R" : "",
886 (int) (opcode
>> 16) & 0xf,
887 (int) (opcode
>> 0) & 0xf,
888 (int) (opcode
>> 8) & 0xf);
892 /* simple matches against the remaining decode bits */
893 switch (opcode
& 0x01f000f0) {
896 /* parallel halfword saturate */
897 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
898 (opcode
& (1 << 22)) ? 'U' : 'S',
900 (int) (opcode
>> 12) & 0xf,
901 (int) (opcode
>> 16) & 0xf,
902 (int) (opcode
>> 0) & 0xf);
915 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
916 (int) (opcode
>> 12) & 0xf,
917 (int) (opcode
>> 16) & 0xf,
918 (int) (opcode
>> 0) & 0xf);
921 /* unsigned sum of absolute differences */
922 if (((opcode
>> 12) & 0xf) == 0xf)
923 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
924 (int) (opcode
>> 16) & 0xf,
925 (int) (opcode
>> 0) & 0xf,
926 (int) (opcode
>> 8) & 0xf);
928 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
929 (int) (opcode
>> 16) & 0xf,
930 (int) (opcode
>> 0) & 0xf,
931 (int) (opcode
>> 8) & 0xf,
932 (int) (opcode
>> 12) & 0xf);
936 unsigned rm
= (opcode
>> 0) & 0xf;
937 unsigned rd
= (opcode
>> 12) & 0xf;
939 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
944 /* these opcodes might be used someday */
945 sprintf(cp
, "UNDEFINED");
949 /* Miscellaneous load/store instructions */
950 static int evaluate_misc_load_store(uint32_t opcode
,
951 uint32_t address
, struct arm_instruction
*instruction
)
953 uint8_t P
, U
, I
, W
, L
, S
, H
;
955 char *operation
;/* "LDR" or "STR" */
956 char *suffix
; /* "H", "SB", "SH", "D" */
960 P
= (opcode
& 0x01000000) >> 24;
961 U
= (opcode
& 0x00800000) >> 23;
962 I
= (opcode
& 0x00400000) >> 22;
963 W
= (opcode
& 0x00200000) >> 21;
964 L
= (opcode
& 0x00100000) >> 20;
965 S
= (opcode
& 0x00000040) >> 6;
966 H
= (opcode
& 0x00000020) >> 5;
968 /* target register */
969 Rd
= (opcode
& 0xf000) >> 12;
972 Rn
= (opcode
& 0xf0000) >> 16;
974 instruction
->info
.load_store
.Rd
= Rd
;
975 instruction
->info
.load_store
.Rn
= Rn
;
976 instruction
->info
.load_store
.U
= U
;
978 /* determine instruction type and suffix */
983 instruction
->type
= ARM_LDRSH
;
987 instruction
->type
= ARM_LDRSB
;
990 } else {/* there are no signed stores, so this is used to encode double-register
995 instruction
->type
= ARM_STRD
;
998 instruction
->type
= ARM_LDRD
;
1001 } else {/* unsigned */
1005 instruction
->type
= ARM_LDRH
;
1008 instruction
->type
= ARM_STRH
;
1012 if (I
) {/* Immediate offset/index (#+-<offset_8>)*/
1013 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
1014 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
1016 instruction
->info
.load_store
.offset_mode
= 0;
1017 instruction
->info
.load_store
.offset
.offset
= offset_8
;
1018 } else {/* Register offset/index (+-<Rm>) */
1020 Rm
= (opcode
& 0xf);
1021 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
1023 instruction
->info
.load_store
.offset_mode
= 1;
1024 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1025 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
1026 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
1030 if (W
== 0) { /* offset */
1031 snprintf(instruction
->text
,
1033 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
1043 instruction
->info
.load_store
.index_mode
= 0;
1044 } else {/* pre-indexed */
1045 snprintf(instruction
->text
,
1047 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1057 instruction
->info
.load_store
.index_mode
= 1;
1059 } else {/* post-indexed */
1060 snprintf(instruction
->text
,
1062 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1072 instruction
->info
.load_store
.index_mode
= 2;
1078 /* Load/store multiples instructions */
1079 static int evaluate_ldm_stm(uint32_t opcode
,
1080 uint32_t address
, struct arm_instruction
*instruction
)
1082 uint8_t P
, U
, S
, W
, L
, Rn
;
1083 uint32_t register_list
;
1084 char *addressing_mode
;
1091 P
= (opcode
& 0x01000000) >> 24;
1092 U
= (opcode
& 0x00800000) >> 23;
1093 S
= (opcode
& 0x00400000) >> 22;
1094 W
= (opcode
& 0x00200000) >> 21;
1095 L
= (opcode
& 0x00100000) >> 20;
1096 register_list
= (opcode
& 0xffff);
1097 Rn
= (opcode
& 0xf0000) >> 16;
1099 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1100 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1101 instruction
->info
.load_store_multiple
.S
= S
;
1102 instruction
->info
.load_store_multiple
.W
= W
;
1105 instruction
->type
= ARM_LDM
;
1108 instruction
->type
= ARM_STM
;
1114 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1115 addressing_mode
= "IB";
1117 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1118 addressing_mode
= "DB";
1122 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1123 /* "IA" is the default in UAL syntax */
1124 addressing_mode
= "";
1126 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1127 addressing_mode
= "DA";
1131 reg_list_p
= reg_list
;
1132 for (i
= 0; i
<= 15; i
++) {
1133 if ((register_list
>> i
) & 1) {
1136 reg_list_p
+= snprintf(reg_list_p
,
1137 (reg_list
+ 69 - reg_list_p
),
1141 reg_list_p
+= snprintf(reg_list_p
,
1142 (reg_list
+ 69 - reg_list_p
),
1148 snprintf(instruction
->text
, 128,
1149 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1150 "\t%s%s%s r%i%s, {%s}%s",
1152 mnemonic
, addressing_mode
, COND(opcode
),
1153 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1158 /* Multiplies, extra load/stores */
1159 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1160 uint32_t address
, struct arm_instruction
*instruction
)
1162 /* Multiply (accumulate) (long) and Swap/swap byte */
1163 if ((opcode
& 0x000000f0) == 0x00000090) {
1164 /* Multiply (accumulate) */
1165 if ((opcode
& 0x0f800000) == 0x00000000) {
1166 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1168 Rs
= (opcode
& 0xf00) >> 8;
1169 Rn
= (opcode
& 0xf000) >> 12;
1170 Rd
= (opcode
& 0xf0000) >> 16;
1171 S
= (opcode
& 0x00100000) >> 20;
1173 /* examine A bit (accumulate) */
1174 if (opcode
& 0x00200000) {
1175 instruction
->type
= ARM_MLA
;
1176 snprintf(instruction
->text
,
1178 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1188 instruction
->type
= ARM_MUL
;
1189 snprintf(instruction
->text
,
1191 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1204 /* Multiply (accumulate) long */
1205 if ((opcode
& 0x0f800000) == 0x00800000) {
1206 char *mnemonic
= NULL
;
1207 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1209 Rs
= (opcode
& 0xf00) >> 8;
1210 RdHi
= (opcode
& 0xf000) >> 12;
1211 RdLow
= (opcode
& 0xf0000) >> 16;
1212 S
= (opcode
& 0x00100000) >> 20;
1214 switch ((opcode
& 0x00600000) >> 21) {
1216 instruction
->type
= ARM_UMULL
;
1220 instruction
->type
= ARM_UMLAL
;
1224 instruction
->type
= ARM_SMULL
;
1228 instruction
->type
= ARM_SMLAL
;
1233 snprintf(instruction
->text
,
1235 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1249 /* Swap/swap byte */
1250 if ((opcode
& 0x0f800000) == 0x01000000) {
1253 Rd
= (opcode
& 0xf000) >> 12;
1254 Rn
= (opcode
& 0xf0000) >> 16;
1256 /* examine B flag */
1257 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1259 snprintf(instruction
->text
,
1261 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1264 (opcode
& 0x00400000) ? "SWPB" : "SWP",
1274 return evaluate_misc_load_store(opcode
, address
, instruction
);
1277 static int evaluate_mrs_msr(uint32_t opcode
,
1278 uint32_t address
, struct arm_instruction
*instruction
)
1280 int R
= (opcode
& 0x00400000) >> 22;
1281 char *PSR
= (R
) ? "SPSR" : "CPSR";
1283 /* Move register to status register (MSR) */
1284 if (opcode
& 0x00200000) {
1285 instruction
->type
= ARM_MSR
;
1287 /* immediate variant */
1288 if (opcode
& 0x02000000) {
1289 uint8_t immediate
= (opcode
& 0xff);
1290 uint8_t rotate
= (opcode
& 0xf00);
1292 snprintf(instruction
->text
,
1294 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1299 (opcode
& 0x10000) ? "c" : "",
1300 (opcode
& 0x20000) ? "x" : "",
1301 (opcode
& 0x40000) ? "s" : "",
1302 (opcode
& 0x80000) ? "f" : "",
1303 ror(immediate
, (rotate
* 2))
1305 } else {/* register variant */
1306 uint8_t Rm
= opcode
& 0xf;
1307 snprintf(instruction
->text
,
1309 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1314 (opcode
& 0x10000) ? "c" : "",
1315 (opcode
& 0x20000) ? "x" : "",
1316 (opcode
& 0x40000) ? "s" : "",
1317 (opcode
& 0x80000) ? "f" : "",
1322 } else {/* Move status register to register (MRS) */
1325 instruction
->type
= ARM_MRS
;
1326 Rd
= (opcode
& 0x0000f000) >> 12;
1328 snprintf(instruction
->text
,
1330 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1341 /* Miscellaneous instructions */
1342 static int evaluate_misc_instr(uint32_t opcode
,
1343 uint32_t address
, struct arm_instruction
*instruction
)
1346 if ((opcode
& 0x000000f0) == 0x00000000)
1347 evaluate_mrs_msr(opcode
, address
, instruction
);
1350 if ((opcode
& 0x006000f0) == 0x00200010) {
1352 instruction
->type
= ARM_BX
;
1355 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1356 address
, opcode
, COND(opcode
), Rm
);
1358 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1359 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1362 /* BXJ - "Jazelle" support (ARMv5-J) */
1363 if ((opcode
& 0x006000f0) == 0x00200020) {
1365 instruction
->type
= ARM_BX
;
1368 snprintf(instruction
->text
, 128,
1369 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1370 address
, opcode
, COND(opcode
), Rm
);
1372 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1373 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1377 if ((opcode
& 0x006000f0) == 0x00600010) {
1379 instruction
->type
= ARM_CLZ
;
1381 Rd
= (opcode
& 0xf000) >> 12;
1383 snprintf(instruction
->text
,
1385 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1394 if ((opcode
& 0x006000f0) == 0x00200030) {
1396 instruction
->type
= ARM_BLX
;
1399 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1400 address
, opcode
, COND(opcode
), Rm
);
1402 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1403 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1406 /* Enhanced DSP add/subtracts */
1407 if ((opcode
& 0x0000000f0) == 0x00000050) {
1409 char *mnemonic
= NULL
;
1411 Rd
= (opcode
& 0xf000) >> 12;
1412 Rn
= (opcode
& 0xf0000) >> 16;
1414 switch ((opcode
& 0x00600000) >> 21) {
1416 instruction
->type
= ARM_QADD
;
1420 instruction
->type
= ARM_QSUB
;
1424 instruction
->type
= ARM_QDADD
;
1428 instruction
->type
= ARM_QDSUB
;
1433 snprintf(instruction
->text
,
1435 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1445 /* exception return */
1446 if ((opcode
& 0x0000000f0) == 0x00000060) {
1447 if (((opcode
& 0x600000) >> 21) == 3)
1448 instruction
->type
= ARM_ERET
;
1449 snprintf(instruction
->text
,
1451 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tERET",
1456 /* exception generate instructions */
1457 if ((opcode
& 0x0000000f0) == 0x00000070) {
1458 uint32_t immediate
= 0;
1459 char *mnemonic
= NULL
;
1461 switch ((opcode
& 0x600000) >> 21) {
1463 instruction
->type
= ARM_BKPT
;
1465 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1468 instruction
->type
= ARM_HVC
;
1470 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1473 instruction
->type
= ARM_SMC
;
1475 immediate
= (opcode
& 0xf);
1479 snprintf(instruction
->text
,
1481 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s 0x%4.4" PRIx32
"",
1488 /* Enhanced DSP multiplies */
1489 if ((opcode
& 0x000000090) == 0x00000080) {
1490 int x
= (opcode
& 0x20) >> 5;
1491 int y
= (opcode
& 0x40) >> 6;
1494 if ((opcode
& 0x00600000) == 0x00000000) {
1495 uint8_t Rd
, Rm
, Rs
, Rn
;
1496 instruction
->type
= ARM_SMLAxy
;
1497 Rd
= (opcode
& 0xf0000) >> 16;
1498 Rm
= (opcode
& 0xf);
1499 Rs
= (opcode
& 0xf00) >> 8;
1500 Rn
= (opcode
& 0xf000) >> 12;
1502 snprintf(instruction
->text
,
1504 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1517 if ((opcode
& 0x00600000) == 0x00400000) {
1518 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1519 instruction
->type
= ARM_SMLAxy
;
1520 RdHi
= (opcode
& 0xf0000) >> 16;
1521 RdLow
= (opcode
& 0xf000) >> 12;
1522 Rm
= (opcode
& 0xf);
1523 Rs
= (opcode
& 0xf00) >> 8;
1525 snprintf(instruction
->text
,
1527 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1540 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0)) {
1541 uint8_t Rd
, Rm
, Rs
, Rn
;
1542 instruction
->type
= ARM_SMLAWy
;
1543 Rd
= (opcode
& 0xf0000) >> 16;
1544 Rm
= (opcode
& 0xf);
1545 Rs
= (opcode
& 0xf00) >> 8;
1546 Rn
= (opcode
& 0xf000) >> 12;
1548 snprintf(instruction
->text
,
1550 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1562 if ((opcode
& 0x00600000) == 0x00300000) {
1564 instruction
->type
= ARM_SMULxy
;
1565 Rd
= (opcode
& 0xf0000) >> 16;
1566 Rm
= (opcode
& 0xf);
1567 Rs
= (opcode
& 0xf00) >> 8;
1569 snprintf(instruction
->text
,
1571 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1583 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1)) {
1585 instruction
->type
= ARM_SMULWy
;
1586 Rd
= (opcode
& 0xf0000) >> 16;
1587 Rm
= (opcode
& 0xf);
1588 Rs
= (opcode
& 0xf00) >> 8;
1590 snprintf(instruction
->text
,
1592 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1606 static int evaluate_data_proc(uint32_t opcode
,
1607 uint32_t address
, struct arm_instruction
*instruction
)
1609 uint8_t I
, op
, S
, Rn
, Rd
;
1610 char *mnemonic
= NULL
;
1611 char shifter_operand
[32];
1613 I
= (opcode
& 0x02000000) >> 25;
1614 op
= (opcode
& 0x01e00000) >> 21;
1615 S
= (opcode
& 0x00100000) >> 20;
1617 Rd
= (opcode
& 0xf000) >> 12;
1618 Rn
= (opcode
& 0xf0000) >> 16;
1620 instruction
->info
.data_proc
.Rd
= Rd
;
1621 instruction
->info
.data_proc
.Rn
= Rn
;
1622 instruction
->info
.data_proc
.S
= S
;
1626 instruction
->type
= ARM_AND
;
1630 instruction
->type
= ARM_EOR
;
1634 instruction
->type
= ARM_SUB
;
1638 instruction
->type
= ARM_RSB
;
1642 instruction
->type
= ARM_ADD
;
1646 instruction
->type
= ARM_ADC
;
1650 instruction
->type
= ARM_SBC
;
1654 instruction
->type
= ARM_RSC
;
1658 instruction
->type
= ARM_TST
;
1662 instruction
->type
= ARM_TEQ
;
1666 instruction
->type
= ARM_CMP
;
1670 instruction
->type
= ARM_CMN
;
1674 instruction
->type
= ARM_ORR
;
1678 instruction
->type
= ARM_MOV
;
1682 instruction
->type
= ARM_BIC
;
1686 instruction
->type
= ARM_MVN
;
1691 if (I
) {/* immediate shifter operand (#<immediate>)*/
1692 uint8_t immed_8
= opcode
& 0xff;
1693 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1696 immediate
= ror(immed_8
, rotate_imm
* 2);
1698 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1700 instruction
->info
.data_proc
.variant
= 0;
1701 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1702 } else {/* register-based shifter operand */
1704 shift
= (opcode
& 0x60) >> 5;
1705 Rm
= (opcode
& 0xf);
1707 if ((opcode
& 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1708 *#<shift_immediate>") */
1710 shift_imm
= (opcode
& 0xf80) >> 7;
1712 instruction
->info
.data_proc
.variant
= 1;
1713 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1714 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
=
1716 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1718 /* LSR encodes a shift by 32 bit as 0x0 */
1719 if ((shift
== 0x1) && (shift_imm
== 0x0))
1722 /* ASR encodes a shift by 32 bit as 0x0 */
1723 if ((shift
== 0x2) && (shift_imm
== 0x0))
1726 /* ROR by 32 bit is actually a RRX */
1727 if ((shift
== 0x3) && (shift_imm
== 0x0))
1730 if ((shift_imm
== 0x0) && (shift
== 0x0))
1731 snprintf(shifter_operand
, 32, "r%i", Rm
);
1733 if (shift
== 0x0) /* LSL */
1734 snprintf(shifter_operand
,
1739 else if (shift
== 0x1) /* LSR */
1740 snprintf(shifter_operand
,
1745 else if (shift
== 0x2) /* ASR */
1746 snprintf(shifter_operand
,
1751 else if (shift
== 0x3) /* ROR */
1752 snprintf(shifter_operand
,
1757 else if (shift
== 0x4) /* RRX */
1758 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1760 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1761 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1763 instruction
->info
.data_proc
.variant
= 2;
1764 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1765 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1766 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1768 if (shift
== 0x0) /* LSL */
1769 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1770 else if (shift
== 0x1) /* LSR */
1771 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1772 else if (shift
== 0x2) /* ASR */
1773 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1774 else if (shift
== 0x3) /* ROR */
1775 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1779 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1780 *<shifter_operand> */
1781 snprintf(instruction
->text
,
1783 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1792 } else if ((op
== 0xd) || (op
== 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1793 *<shifter_operand> */
1794 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1795 snprintf(instruction
->text
,
1797 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",
1801 snprintf(instruction
->text
,
1803 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1811 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1812 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1813 address
, opcode
, mnemonic
, COND(opcode
),
1814 Rn
, shifter_operand
);
1820 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1821 struct arm_instruction
*instruction
)
1823 /* clear fields, to avoid confusion */
1824 memset(instruction
, 0, sizeof(struct arm_instruction
));
1825 instruction
->opcode
= opcode
;
1826 instruction
->instruction_size
= 4;
1828 /* catch opcodes with condition field [31:28] = b1111 */
1829 if ((opcode
& 0xf0000000) == 0xf0000000) {
1830 /* Undefined instruction (or ARMv5E cache preload PLD) */
1831 if ((opcode
& 0x08000000) == 0x00000000)
1832 return evaluate_pld(opcode
, address
, instruction
);
1834 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1835 if ((opcode
& 0x0e000000) == 0x08000000)
1836 return evaluate_srs(opcode
, address
, instruction
);
1838 /* Branch and branch with link and change to Thumb */
1839 if ((opcode
& 0x0e000000) == 0x0a000000)
1840 return evaluate_blx_imm(opcode
, address
, instruction
);
1842 /* Extended coprocessor opcode space (ARMv5 and higher)
1843 * Coprocessor load/store and double register transfers */
1844 if ((opcode
& 0x0e000000) == 0x0c000000)
1845 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1847 /* Coprocessor data processing */
1848 if ((opcode
& 0x0f000100) == 0x0c000000)
1849 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1851 /* Coprocessor register transfers */
1852 if ((opcode
& 0x0f000010) == 0x0c000010)
1853 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1855 /* Undefined instruction */
1856 if ((opcode
& 0x0f000000) == 0x0f000000) {
1857 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1858 snprintf(instruction
->text
,
1860 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1867 /* catch opcodes with [27:25] = b000 */
1868 if ((opcode
& 0x0e000000) == 0x00000000) {
1869 /* Multiplies, extra load/stores */
1870 if ((opcode
& 0x00000090) == 0x00000090)
1871 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1873 /* Miscellaneous instructions */
1874 if ((opcode
& 0x0f900000) == 0x01000000)
1875 return evaluate_misc_instr(opcode
, address
, instruction
);
1877 return evaluate_data_proc(opcode
, address
, instruction
);
1880 /* catch opcodes with [27:25] = b001 */
1881 if ((opcode
& 0x0e000000) == 0x02000000) {
1882 /* Undefined instruction */
1883 if ((opcode
& 0x0fb00000) == 0x03000000) {
1884 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1885 snprintf(instruction
->text
,
1887 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1893 /* Move immediate to status register */
1894 if ((opcode
& 0x0fb00000) == 0x03200000)
1895 return evaluate_mrs_msr(opcode
, address
, instruction
);
1897 return evaluate_data_proc(opcode
, address
, instruction
);
1901 /* catch opcodes with [27:25] = b010 */
1902 if ((opcode
& 0x0e000000) == 0x04000000) {
1903 /* Load/store immediate offset */
1904 return evaluate_load_store(opcode
, address
, instruction
);
1907 /* catch opcodes with [27:25] = b011 */
1908 if ((opcode
& 0x0e000000) == 0x06000000) {
1909 /* Load/store register offset */
1910 if ((opcode
& 0x00000010) == 0x00000000)
1911 return evaluate_load_store(opcode
, address
, instruction
);
1913 /* Architecturally Undefined instruction
1914 * ... don't expect these to ever be used
1916 if ((opcode
& 0x07f000f0) == 0x07f000f0) {
1917 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1918 snprintf(instruction
->text
, 128,
1919 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1924 /* "media" instructions */
1925 return evaluate_media(opcode
, address
, instruction
);
1928 /* catch opcodes with [27:25] = b100 */
1929 if ((opcode
& 0x0e000000) == 0x08000000) {
1930 /* Load/store multiple */
1931 return evaluate_ldm_stm(opcode
, address
, instruction
);
1934 /* catch opcodes with [27:25] = b101 */
1935 if ((opcode
& 0x0e000000) == 0x0a000000) {
1936 /* Branch and branch with link */
1937 return evaluate_b_bl(opcode
, address
, instruction
);
1940 /* catch opcodes with [27:25] = b110 */
1941 if ((opcode
& 0x0e000000) == 0x0c000000) {
1942 /* Coprocessor load/store and double register transfers */
1943 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1946 /* catch opcodes with [27:25] = b111 */
1947 if ((opcode
& 0x0e000000) == 0x0e000000) {
1948 /* Software interrupt */
1949 if ((opcode
& 0x0f000000) == 0x0f000000)
1950 return evaluate_swi(opcode
, address
, instruction
);
1952 /* Coprocessor data processing */
1953 if ((opcode
& 0x0f000010) == 0x0e000000)
1954 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1956 /* Coprocessor register transfers */
1957 if ((opcode
& 0x0f000010) == 0x0e000010)
1958 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1961 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1966 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1967 uint32_t address
, struct arm_instruction
*instruction
)
1969 uint32_t offset
= opcode
& 0x7ff;
1970 uint32_t opc
= (opcode
>> 11) & 0x3;
1971 uint32_t target_address
;
1972 char *mnemonic
= NULL
;
1974 /* sign extend 11-bit offset */
1975 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1976 offset
= 0xfffff800 | offset
;
1978 target_address
= address
+ 4 + (offset
<< 1);
1981 /* unconditional branch */
1983 instruction
->type
= ARM_B
;
1988 instruction
->type
= ARM_BLX
;
1990 target_address
&= 0xfffffffc;
1994 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1995 mnemonic
= "prefix";
1996 target_address
= offset
<< 12;
2000 instruction
->type
= ARM_BL
;
2005 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
2006 * these are effectively 32-bit instructions even in Thumb1. For
2007 * disassembly, it's simplest to always use the Thumb2 decoder.
2009 * But some cores will evidently handle them as two instructions,
2010 * where exceptions may occur between the two. The ETMv3.2+ ID
2011 * register has a bit which exposes this behavior.
2014 snprintf(instruction
->text
, 128,
2015 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
2016 address
, opcode
, mnemonic
, target_address
);
2018 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2019 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2024 static int evaluate_add_sub_thumb(uint16_t opcode
,
2025 uint32_t address
, struct arm_instruction
*instruction
)
2027 uint8_t Rd
= (opcode
>> 0) & 0x7;
2028 uint8_t Rn
= (opcode
>> 3) & 0x7;
2029 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
2030 uint32_t opc
= opcode
& (1 << 9);
2031 uint32_t reg_imm
= opcode
& (1 << 10);
2035 instruction
->type
= ARM_SUB
;
2038 /* REVISIT: if reg_imm == 0, display as "MOVS" */
2039 instruction
->type
= ARM_ADD
;
2043 instruction
->info
.data_proc
.Rd
= Rd
;
2044 instruction
->info
.data_proc
.Rn
= Rn
;
2045 instruction
->info
.data_proc
.S
= 1;
2048 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2049 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
2050 snprintf(instruction
->text
, 128,
2051 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
2052 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2054 instruction
->info
.data_proc
.variant
= 1;/*immediate shift*/
2055 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
2056 snprintf(instruction
->text
, 128,
2057 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
2058 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2064 static int evaluate_shift_imm_thumb(uint16_t opcode
,
2065 uint32_t address
, struct arm_instruction
*instruction
)
2067 uint8_t Rd
= (opcode
>> 0) & 0x7;
2068 uint8_t Rm
= (opcode
>> 3) & 0x7;
2069 uint8_t imm
= (opcode
>> 6) & 0x1f;
2070 uint8_t opc
= (opcode
>> 11) & 0x3;
2071 char *mnemonic
= NULL
;
2075 instruction
->type
= ARM_MOV
;
2077 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
2080 instruction
->type
= ARM_MOV
;
2082 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
2085 instruction
->type
= ARM_MOV
;
2087 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
2091 if ((imm
== 0) && (opc
!= 0))
2094 instruction
->info
.data_proc
.Rd
= Rd
;
2095 instruction
->info
.data_proc
.Rn
= -1;
2096 instruction
->info
.data_proc
.S
= 1;
2098 instruction
->info
.data_proc
.variant
= 1;/*immediate_shift*/
2099 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2100 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
2102 snprintf(instruction
->text
, 128,
2103 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2104 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
2109 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
2110 uint32_t address
, struct arm_instruction
*instruction
)
2112 uint8_t imm
= opcode
& 0xff;
2113 uint8_t Rd
= (opcode
>> 8) & 0x7;
2114 uint32_t opc
= (opcode
>> 11) & 0x3;
2115 char *mnemonic
= NULL
;
2117 instruction
->info
.data_proc
.Rd
= Rd
;
2118 instruction
->info
.data_proc
.Rn
= Rd
;
2119 instruction
->info
.data_proc
.S
= 1;
2120 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2121 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
2125 instruction
->type
= ARM_MOV
;
2127 instruction
->info
.data_proc
.Rn
= -1;
2130 instruction
->type
= ARM_CMP
;
2132 instruction
->info
.data_proc
.Rd
= -1;
2135 instruction
->type
= ARM_ADD
;
2139 instruction
->type
= ARM_SUB
;
2144 snprintf(instruction
->text
, 128,
2145 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
2146 address
, opcode
, mnemonic
, Rd
, imm
);
2151 static int evaluate_data_proc_thumb(uint16_t opcode
,
2152 uint32_t address
, struct arm_instruction
*instruction
)
2154 uint8_t high_reg
, op
, Rm
, Rd
, H1
, H2
;
2155 char *mnemonic
= NULL
;
2158 high_reg
= (opcode
& 0x0400) >> 10;
2159 op
= (opcode
& 0x03C0) >> 6;
2161 Rd
= (opcode
& 0x0007);
2162 Rm
= (opcode
& 0x0038) >> 3;
2163 H1
= (opcode
& 0x0080) >> 7;
2164 H2
= (opcode
& 0x0040) >> 6;
2166 instruction
->info
.data_proc
.Rd
= Rd
;
2167 instruction
->info
.data_proc
.Rn
= Rd
;
2168 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2169 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2170 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2179 instruction
->type
= ARM_ADD
;
2183 instruction
->type
= ARM_CMP
;
2187 instruction
->type
= ARM_MOV
;
2193 if ((opcode
& 0x7) == 0x0) {
2194 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2196 instruction
->type
= ARM_BLX
;
2197 snprintf(instruction
->text
, 128,
2199 " 0x%4.4x \tBLX\tr%i",
2200 address
, opcode
, Rm
);
2202 instruction
->type
= ARM_BX
;
2203 snprintf(instruction
->text
, 128,
2205 " 0x%4.4x \tBX\tr%i",
2206 address
, opcode
, Rm
);
2209 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2210 snprintf(instruction
->text
, 128,
2213 "UNDEFINED INSTRUCTION",
2222 instruction
->type
= ARM_AND
;
2226 instruction
->type
= ARM_EOR
;
2230 instruction
->type
= ARM_MOV
;
2232 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2233 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2234 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2235 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2238 instruction
->type
= ARM_MOV
;
2240 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2241 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2242 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2243 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2246 instruction
->type
= ARM_MOV
;
2248 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2249 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2250 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2251 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2254 instruction
->type
= ARM_ADC
;
2258 instruction
->type
= ARM_SBC
;
2262 instruction
->type
= ARM_MOV
;
2264 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2265 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2266 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2267 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2270 instruction
->type
= ARM_TST
;
2274 instruction
->type
= ARM_RSB
;
2276 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2277 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2278 instruction
->info
.data_proc
.Rn
= Rm
;
2281 instruction
->type
= ARM_CMP
;
2285 instruction
->type
= ARM_CMN
;
2289 instruction
->type
= ARM_ORR
;
2293 instruction
->type
= ARM_MUL
;
2297 instruction
->type
= ARM_BIC
;
2301 instruction
->type
= ARM_MVN
;
2308 snprintf(instruction
->text
, 128,
2309 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2311 address
, opcode
, mnemonic
, Rd
, Rm
);
2313 snprintf(instruction
->text
, 128,
2314 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2315 address
, opcode
, mnemonic
, Rd
, Rm
);
2320 /* PC-relative data addressing is word-aligned even with Thumb */
2321 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2323 return (addr
+ 4) & ~3;
2326 static int evaluate_load_literal_thumb(uint16_t opcode
,
2327 uint32_t address
, struct arm_instruction
*instruction
)
2330 uint8_t Rd
= (opcode
>> 8) & 0x7;
2332 instruction
->type
= ARM_LDR
;
2333 immediate
= opcode
& 0x000000ff;
2336 instruction
->info
.load_store
.Rd
= Rd
;
2337 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2338 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2339 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2340 instruction
->info
.load_store
.offset
.offset
= immediate
;
2342 snprintf(instruction
->text
, 128,
2343 "0x%8.8" PRIx32
" 0x%4.4x \t"
2344 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2345 address
, opcode
, Rd
, immediate
,
2346 thumb_alignpc4(address
) + immediate
);
2351 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2352 uint32_t address
, struct arm_instruction
*instruction
)
2354 uint8_t Rd
= (opcode
>> 0) & 0x7;
2355 uint8_t Rn
= (opcode
>> 3) & 0x7;
2356 uint8_t Rm
= (opcode
>> 6) & 0x7;
2357 uint8_t opc
= (opcode
>> 9) & 0x7;
2358 char *mnemonic
= NULL
;
2362 instruction
->type
= ARM_STR
;
2366 instruction
->type
= ARM_STRH
;
2370 instruction
->type
= ARM_STRB
;
2374 instruction
->type
= ARM_LDRSB
;
2378 instruction
->type
= ARM_LDR
;
2382 instruction
->type
= ARM_LDRH
;
2386 instruction
->type
= ARM_LDRB
;
2390 instruction
->type
= ARM_LDRSH
;
2395 snprintf(instruction
->text
, 128,
2396 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2397 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
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
= 1; /*register*/
2403 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2408 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2409 uint32_t address
, struct arm_instruction
*instruction
)
2411 uint32_t offset
= (opcode
>> 6) & 0x1f;
2412 uint8_t Rd
= (opcode
>> 0) & 0x7;
2413 uint8_t Rn
= (opcode
>> 3) & 0x7;
2414 uint32_t L
= opcode
& (1 << 11);
2415 uint32_t B
= opcode
& (1 << 12);
2421 instruction
->type
= ARM_LDR
;
2424 instruction
->type
= ARM_STR
;
2428 if ((opcode
&0xF000) == 0x8000) {
2436 snprintf(instruction
->text
, 128,
2437 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2438 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2440 instruction
->info
.load_store
.Rd
= Rd
;
2441 instruction
->info
.load_store
.Rn
= Rn
;
2442 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2443 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2444 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2449 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2450 uint32_t address
, struct arm_instruction
*instruction
)
2452 uint32_t offset
= opcode
& 0xff;
2453 uint8_t Rd
= (opcode
>> 8) & 0x7;
2454 uint32_t L
= opcode
& (1 << 11);
2458 instruction
->type
= ARM_LDR
;
2461 instruction
->type
= ARM_STR
;
2465 snprintf(instruction
->text
, 128,
2466 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2467 address
, opcode
, mnemonic
, Rd
, offset
*4);
2469 instruction
->info
.load_store
.Rd
= Rd
;
2470 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2471 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2472 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2473 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2478 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2479 uint32_t address
, struct arm_instruction
*instruction
)
2481 uint32_t imm
= opcode
& 0xff;
2482 uint8_t Rd
= (opcode
>> 8) & 0x7;
2484 uint32_t SP
= opcode
& (1 << 11);
2485 const char *reg_name
;
2487 instruction
->type
= ARM_ADD
;
2497 snprintf(instruction
->text
, 128,
2498 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2499 address
, opcode
, Rd
, reg_name
, imm
* 4);
2501 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2502 instruction
->info
.data_proc
.Rd
= Rd
;
2503 instruction
->info
.data_proc
.Rn
= Rn
;
2504 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2509 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2510 uint32_t address
, struct arm_instruction
*instruction
)
2512 uint32_t imm
= opcode
& 0x7f;
2513 uint8_t opc
= opcode
& (1 << 7);
2518 instruction
->type
= ARM_SUB
;
2521 instruction
->type
= ARM_ADD
;
2525 snprintf(instruction
->text
, 128,
2526 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2527 address
, opcode
, mnemonic
, imm
*4);
2529 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2530 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2531 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2532 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2537 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2538 uint32_t address
, struct arm_instruction
*instruction
)
2540 uint32_t imm
= opcode
& 0xff;
2542 instruction
->type
= ARM_BKPT
;
2544 snprintf(instruction
->text
, 128,
2545 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2546 address
, opcode
, imm
);
2551 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2552 uint32_t address
, struct arm_instruction
*instruction
)
2554 uint32_t reg_list
= opcode
& 0xff;
2555 uint32_t L
= opcode
& (1 << 11);
2556 uint32_t R
= opcode
& (1 << 8);
2557 uint8_t Rn
= (opcode
>> 8) & 7;
2558 uint8_t addr_mode
= 0 /* IA */;
2562 char ptr_name
[7] = "";
2565 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2566 * The STMIA and LDMIA opcodes are used for other instructions.
2569 if ((opcode
& 0xf000) == 0xc000) { /* generic load/store multiple */
2573 instruction
->type
= ARM_LDM
;
2575 if (opcode
& (1 << Rn
))
2578 instruction
->type
= ARM_STM
;
2581 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2582 } else {/* push/pop */
2585 instruction
->type
= ARM_LDM
;
2588 reg_list
|= (1 << 15) /*PC*/;
2590 instruction
->type
= ARM_STM
;
2592 addr_mode
= 3; /*DB*/
2594 reg_list
|= (1 << 14) /*LR*/;
2598 reg_names_p
= reg_names
;
2599 for (i
= 0; i
<= 15; i
++) {
2600 if (reg_list
& (1 << i
))
2601 reg_names_p
+= snprintf(reg_names_p
,
2602 (reg_names
+ 40 - reg_names_p
),
2606 if (reg_names_p
> reg_names
)
2607 reg_names_p
[-2] = '\0';
2608 else /* invalid op : no registers */
2609 reg_names
[0] = '\0';
2611 snprintf(instruction
->text
, 128,
2612 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2613 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2615 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2616 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2617 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2622 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2623 uint32_t address
, struct arm_instruction
*instruction
)
2625 uint32_t offset
= opcode
& 0xff;
2626 uint8_t cond
= (opcode
>> 8) & 0xf;
2627 uint32_t target_address
;
2630 instruction
->type
= ARM_SWI
;
2631 snprintf(instruction
->text
, 128,
2632 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2633 address
, opcode
, offset
);
2635 } else if (cond
== 0xe) {
2636 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2637 snprintf(instruction
->text
, 128,
2638 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2643 /* sign extend 8-bit offset */
2644 if (offset
& 0x00000080)
2645 offset
= 0xffffff00 | offset
;
2647 target_address
= address
+ 4 + (offset
<< 1);
2649 snprintf(instruction
->text
, 128,
2650 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2652 arm_condition_strings
[cond
], target_address
);
2654 instruction
->type
= ARM_B
;
2655 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2656 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2661 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2662 struct arm_instruction
*instruction
)
2666 /* added in Thumb2 */
2667 offset
= (opcode
>> 3) & 0x1f;
2668 offset
|= (opcode
& 0x0200) >> 4;
2670 snprintf(instruction
->text
, 128,
2671 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2673 (opcode
& 0x0800) ? "N" : "",
2674 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2679 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2680 struct arm_instruction
*instruction
)
2682 /* added in ARMv6 */
2683 snprintf(instruction
->text
, 128,
2684 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2686 (opcode
& 0x0080) ? 'U' : 'S',
2687 (opcode
& 0x0040) ? 'B' : 'H',
2688 opcode
& 0x7, (opcode
>> 3) & 0x7);
2693 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2694 struct arm_instruction
*instruction
)
2696 /* added in ARMv6 */
2697 if ((opcode
& 0x0ff0) == 0x0650)
2698 snprintf(instruction
->text
, 128,
2699 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2701 (opcode
& 0x80) ? "BE" : "LE");
2702 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2703 snprintf(instruction
->text
, 128,
2704 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2706 (opcode
& 0x0010) ? 'D' : 'E',
2707 (opcode
& 0x0004) ? "A" : "",
2708 (opcode
& 0x0002) ? "I" : "",
2709 (opcode
& 0x0001) ? "F" : "");
2714 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2715 struct arm_instruction
*instruction
)
2719 /* added in ARMv6 */
2720 switch ((opcode
>> 6) & 3) {
2731 snprintf(instruction
->text
, 128,
2732 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2733 address
, opcode
, suffix
,
2734 opcode
& 0x7, (opcode
>> 3) & 0x7);
2739 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2740 struct arm_instruction
*instruction
)
2744 switch ((opcode
>> 4) & 0x0f) {
2761 hint
= "HINT (UNRECOGNIZED)";
2765 snprintf(instruction
->text
, 128,
2766 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2767 address
, opcode
, hint
);
2772 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2773 struct arm_instruction
*instruction
)
2775 unsigned cond
= (opcode
>> 4) & 0x0f;
2776 char *x
= "", *y
= "", *z
= "";
2779 z
= (opcode
& 0x02) ? "T" : "E";
2781 y
= (opcode
& 0x04) ? "T" : "E";
2783 x
= (opcode
& 0x08) ? "T" : "E";
2785 snprintf(instruction
->text
, 128,
2786 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2788 x
, y
, z
, arm_condition_strings
[cond
]);
2790 /* NOTE: strictly speaking, the next 1-4 instructions should
2791 * now be displayed with the relevant conditional suffix...
2797 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2799 /* clear fields, to avoid confusion */
2800 memset(instruction
, 0, sizeof(struct arm_instruction
));
2801 instruction
->opcode
= opcode
;
2802 instruction
->instruction_size
= 2;
2804 if ((opcode
& 0xe000) == 0x0000) {
2805 /* add/substract register or immediate */
2806 if ((opcode
& 0x1800) == 0x1800)
2807 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2808 /* shift by immediate */
2810 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2813 /* Add/substract/compare/move immediate */
2814 if ((opcode
& 0xe000) == 0x2000)
2815 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2817 /* Data processing instructions */
2818 if ((opcode
& 0xf800) == 0x4000)
2819 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2821 /* Load from literal pool */
2822 if ((opcode
& 0xf800) == 0x4800)
2823 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2825 /* Load/Store register offset */
2826 if ((opcode
& 0xf000) == 0x5000)
2827 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2829 /* Load/Store immediate offset */
2830 if (((opcode
& 0xe000) == 0x6000)
2831 || ((opcode
& 0xf000) == 0x8000))
2832 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2834 /* Load/Store from/to stack */
2835 if ((opcode
& 0xf000) == 0x9000)
2836 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2839 if ((opcode
& 0xf000) == 0xa000)
2840 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2843 if ((opcode
& 0xf000) == 0xb000) {
2844 switch ((opcode
>> 8) & 0x0f) {
2846 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2851 return evaluate_cb_thumb(opcode
, address
, instruction
);
2853 return evaluate_extend_thumb(opcode
, address
, instruction
);
2858 return evaluate_load_store_multiple_thumb(opcode
, address
,
2861 return evaluate_cps_thumb(opcode
, address
, instruction
);
2863 if ((opcode
& 0x00c0) == 0x0080)
2865 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2867 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2869 if (opcode
& 0x000f)
2870 return evaluate_ifthen_thumb(opcode
, address
,
2873 return evaluate_hint_thumb(opcode
, address
,
2877 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2878 snprintf(instruction
->text
, 128,
2879 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2884 /* Load/Store multiple */
2885 if ((opcode
& 0xf000) == 0xc000)
2886 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2888 /* Conditional branch + SWI */
2889 if ((opcode
& 0xf000) == 0xd000)
2890 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2892 if ((opcode
& 0xe000) == 0xe000) {
2893 /* Undefined instructions */
2894 if ((opcode
& 0xf801) == 0xe801) {
2895 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2896 snprintf(instruction
->text
, 128,
2897 "0x%8.8" PRIx32
" 0x%8.8x\t"
2898 "UNDEFINED INSTRUCTION",
2901 } else /* Branch to offset */
2902 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2905 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2909 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2910 struct arm_instruction
*instruction
, char *cp
)
2913 unsigned b21
= 1 << 21;
2914 unsigned b22
= 1 << 22;
2916 /* instead of combining two smaller 16-bit branch instructions,
2917 * Thumb2 uses only one larger 32-bit instruction.
2919 offset
= opcode
& 0x7ff;
2920 offset
|= (opcode
& 0x03ff0000) >> 5;
2921 if (opcode
& (1 << 26)) {
2922 offset
|= 0xff << 23;
2923 if ((opcode
& (1 << 11)) == 0)
2925 if ((opcode
& (1 << 13)) == 0)
2928 if (opcode
& (1 << 11))
2930 if (opcode
& (1 << 13))
2938 address
+= offset
<< 1;
2941 switch ((opcode
>> 12) & 0x5) {
2944 instruction
->type
= ARM_B
;
2948 instruction
->type
= ARM_BLX
;
2952 instruction
->type
= ARM_BL
;
2955 return ERROR_COMMAND_SYNTAX_ERROR
;
2957 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2958 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2959 sprintf(cp
, "%s\t%#8.8" PRIx32
, inst
, address
);
2964 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2965 struct arm_instruction
*instruction
, char *cp
)
2968 unsigned b17
= 1 << 17;
2969 unsigned b18
= 1 << 18;
2970 unsigned cond
= (opcode
>> 22) & 0x0f;
2972 offset
= opcode
& 0x7ff;
2973 offset
|= (opcode
& 0x003f0000) >> 5;
2974 if (opcode
& (1 << 26)) {
2975 offset
|= 0x1fff << 19;
2976 if ((opcode
& (1 << 11)) == 0)
2978 if ((opcode
& (1 << 13)) == 0)
2981 if (opcode
& (1 << 11))
2983 if (opcode
& (1 << 13))
2990 address
+= offset
<< 1;
2992 instruction
->type
= ARM_B
;
2993 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2994 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2995 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2996 arm_condition_strings
[cond
],
3002 static const char *special_name(int number
)
3004 char *special
= "(RESERVED)";
3035 special
= "primask";
3038 special
= "basepri";
3041 special
= "basepri_max";
3044 special
= "faultmask";
3047 special
= "control";
3053 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
3054 struct arm_instruction
*instruction
, char *cp
)
3056 const char *mnemonic
;
3058 if (opcode
& 0x0700) {
3059 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3060 strcpy(cp
, "UNDEFINED");
3064 if (opcode
& 0x00f0) {
3065 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
3069 switch (opcode
& 0x0f) {
3074 mnemonic
= "YIELD.W";
3086 mnemonic
= "HINT.W (UNRECOGNIZED)";
3089 strcpy(cp
, mnemonic
);
3093 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3094 struct arm_instruction
*instruction
, char *cp
)
3096 const char *mnemonic
;
3098 switch ((opcode
>> 4) & 0x0f) {
3100 mnemonic
= "LEAVEX";
3103 mnemonic
= "ENTERX";
3118 return ERROR_COMMAND_SYNTAX_ERROR
;
3120 strcpy(cp
, mnemonic
);
3124 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3125 struct arm_instruction
*instruction
, char *cp
)
3127 /* permanently undefined */
3128 if ((opcode
& 0x07f07000) == 0x07f02000) {
3129 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3130 strcpy(cp
, "UNDEFINED");
3134 switch ((opcode
>> 12) & 0x5) {
3138 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3140 if (((opcode
>> 23) & 0x07) != 0x07)
3141 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3142 if (opcode
& (1 << 26))
3147 switch ((opcode
>> 20) & 0x7f) {
3150 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3151 (int) (opcode
>> 16) & 0x0f);
3154 return t2ev_hint(opcode
, address
, instruction
, cp
);
3156 return t2ev_misc(opcode
, address
, instruction
, cp
);
3158 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3162 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3163 special_name(opcode
& 0xff));
3168 return ERROR_COMMAND_SYNTAX_ERROR
;
3171 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3172 struct arm_instruction
*instruction
, char *cp
)
3174 char *mnemonic
= NULL
;
3175 int rn
= (opcode
>> 16) & 0xf;
3176 int rd
= (opcode
>> 8) & 0xf;
3177 unsigned immed
= opcode
& 0xff;
3183 /* ARMv7-M: A5.3.2 Modified immediate constants */
3184 func
= (opcode
>> 11) & 0x0e;
3187 if (opcode
& (1 << 26))
3190 /* "Modified" immediates */
3191 switch (func
>> 1) {
3198 immed
+= immed
<< 16;
3201 immed
+= immed
<< 8;
3202 immed
+= immed
<< 16;
3206 immed
= ror(immed
, func
);
3209 if (opcode
& (1 << 20))
3212 switch ((opcode
>> 21) & 0xf) {
3215 instruction
->type
= ARM_TST
;
3221 instruction
->type
= ARM_AND
;
3226 instruction
->type
= ARM_BIC
;
3231 instruction
->type
= ARM_MOV
;
3236 instruction
->type
= ARM_ORR
;
3242 instruction
->type
= ARM_MVN
;
3246 /* instruction->type = ARM_ORN; */
3252 instruction
->type
= ARM_TEQ
;
3258 instruction
->type
= ARM_EOR
;
3264 instruction
->type
= ARM_CMN
;
3270 instruction
->type
= ARM_ADD
;
3276 instruction
->type
= ARM_ADC
;
3281 instruction
->type
= ARM_SBC
;
3286 instruction
->type
= ARM_CMP
;
3292 instruction
->type
= ARM_SUB
;
3298 instruction
->type
= ARM_RSB
;
3303 return ERROR_COMMAND_SYNTAX_ERROR
;
3307 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3308 mnemonic
, suffix2
, rd
, immed
, immed
);
3310 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3311 mnemonic
, suffix
, suffix2
,
3312 rd
, rn
, immed
, immed
);
3317 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3318 struct arm_instruction
*instruction
, char *cp
)
3320 char *mnemonic
= NULL
;
3321 int rn
= (opcode
>> 16) & 0xf;
3322 int rd
= (opcode
>> 8) & 0xf;
3325 bool is_signed
= false;
3327 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3328 if (opcode
& (1 << 26))
3331 switch ((opcode
>> 20) & 0x1f) {
3340 immed
|= (opcode
>> 4) & 0xf000;
3341 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3349 /* move constant to top 16 bits of register */
3350 immed
|= (opcode
>> 4) & 0xf000;
3351 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3359 /* signed/unsigned saturated add */
3360 immed
= (opcode
>> 6) & 0x03;
3361 immed
|= (opcode
>> 10) & 0x1c;
3362 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3363 is_signed
? "S" : "U",
3364 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3365 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3366 immed
? immed
: 32);
3372 /* signed/unsigned bitfield extract */
3373 immed
= (opcode
>> 6) & 0x03;
3374 immed
|= (opcode
>> 10) & 0x1c;
3375 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3376 is_signed
? "S" : "U",
3378 (int) (opcode
& 0x1f) + 1);
3381 immed
= (opcode
>> 6) & 0x03;
3382 immed
|= (opcode
>> 10) & 0x1c;
3383 if (rn
== 0xf) /* bitfield clear */
3384 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3386 (int) (opcode
& 0x1f) + 1 - immed
);
3387 else /* bitfield insert */
3388 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3390 (int) (opcode
& 0x1f) + 1 - immed
);
3393 return ERROR_COMMAND_SYNTAX_ERROR
;
3396 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3397 rd
, rn
, immed
, immed
);
3401 address
= thumb_alignpc4(address
);
3406 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3407 * not hiding the pc-relative stuff will sometimes be useful.
3409 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3413 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3414 struct arm_instruction
*instruction
, char *cp
)
3416 unsigned op
= (opcode
>> 20) & 0xf;
3422 unsigned rn
= (opcode
>> 16) & 0x0f;
3423 unsigned rt
= (opcode
>> 12) & 0x0f;
3426 return ERROR_COMMAND_SYNTAX_ERROR
;
3428 if (opcode
& 0x0800)
3463 return ERROR_COMMAND_SYNTAX_ERROR
;
3466 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3467 size
, rt
, rn
, (int) opcode
& 0x0f,
3468 (int) (opcode
>> 4) & 0x03);
3472 immed
= opcode
& 0x0fff;
3473 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3474 size
, rt
, rn
, immed
, immed
);
3478 immed
= opcode
& 0x00ff;
3480 switch (opcode
& 0x700) {
3486 return ERROR_COMMAND_SYNTAX_ERROR
;
3489 /* two indexed modes will write back rn */
3490 if (opcode
& 0x100) {
3491 if (opcode
& 0x400) /* pre-indexed */
3493 else { /* post-indexed */
3499 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3500 size
, suffix
, rt
, rn
, p1
,
3501 (opcode
& 0x200) ? "" : "-",
3506 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3507 struct arm_instruction
*instruction
, char *cp
)
3509 int ra
= (opcode
>> 12) & 0xf;
3511 switch (opcode
& 0x007000f0) {
3514 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3515 (int) (opcode
>> 8) & 0xf,
3516 (int) (opcode
>> 16) & 0xf,
3517 (int) (opcode
>> 0) & 0xf);
3519 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3520 (int) (opcode
>> 8) & 0xf,
3521 (int) (opcode
>> 16) & 0xf,
3522 (int) (opcode
>> 0) & 0xf, ra
);
3525 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3526 (int) (opcode
>> 8) & 0xf,
3527 (int) (opcode
>> 16) & 0xf,
3528 (int) (opcode
>> 0) & 0xf, ra
);
3531 return ERROR_COMMAND_SYNTAX_ERROR
;
3536 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3537 struct arm_instruction
*instruction
, char *cp
)
3539 int op
= (opcode
>> 4) & 0xf;
3540 char *infix
= "MUL";
3542 op
+= (opcode
>> 16) & 0x70;
3550 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3551 (op
& 0x20) ? 'U' : 'S',
3553 (int) (opcode
>> 12) & 0xf,
3554 (int) (opcode
>> 8) & 0xf,
3555 (int) (opcode
>> 16) & 0xf,
3556 (int) (opcode
>> 0) & 0xf);
3560 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3561 (op
& 0x20) ? 'U' : 'S',
3562 (int) (opcode
>> 8) & 0xf,
3563 (int) (opcode
>> 16) & 0xf,
3564 (int) (opcode
>> 0) & 0xf);
3567 return ERROR_COMMAND_SYNTAX_ERROR
;
3573 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3574 struct arm_instruction
*instruction
, char *cp
)
3576 int rn
= (opcode
>> 16) & 0xf;
3577 int op
= (opcode
>> 22) & 0x6;
3578 int t
= (opcode
>> 21) & 1;
3579 unsigned registers
= opcode
& 0xffff;
3582 if (opcode
& (1 << 20))
3590 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3592 (unsigned) (opcode
& 0x1f));
3598 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3599 (unsigned) ((opcode
>> 16) & 0xf),
3603 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3607 sprintf(cp
, "POP.W\t");
3609 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3613 sprintf(cp
, "PUSH.W\t");
3615 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3618 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3621 return ERROR_COMMAND_SYNTAX_ERROR
;
3626 for (t
= 0; registers
; t
++, registers
>>= 1) {
3627 if ((registers
& 1) == 0)
3630 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3639 /* load/store dual or exclusive, table branch */
3640 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3641 struct arm_instruction
*instruction
, char *cp
)
3643 unsigned op1op2
= (opcode
>> 20) & 0x3;
3644 unsigned op3
= (opcode
>> 4) & 0xf;
3646 unsigned rn
= (opcode
>> 16) & 0xf;
3647 unsigned rt
= (opcode
>> 12) & 0xf;
3648 unsigned rd
= (opcode
>> 8) & 0xf;
3649 unsigned imm
= opcode
& 0xff;
3653 op1op2
|= (opcode
>> 21) & 0xc;
3683 mnemonic
= "STREXB";
3686 mnemonic
= "STREXH";
3689 return ERROR_COMMAND_SYNTAX_ERROR
;
3697 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3700 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3703 mnemonic
= "LDREXB";
3706 mnemonic
= "LDREXH";
3709 return ERROR_COMMAND_SYNTAX_ERROR
;
3714 return ERROR_COMMAND_SYNTAX_ERROR
;
3719 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3720 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3722 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3723 mnemonic
, rd
, rt
, rn
);
3729 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3730 mnemonic
, rt
, rn
, imm
, imm
);
3732 sprintf(cp
, "%s\tr%u, [r%u]",
3737 /* two indexed modes will write back rn */
3738 if (opcode
& (1 << 21)) {
3739 if (opcode
& (1 << 24)) /* pre-indexed */
3741 else { /* post-indexed */
3748 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3749 mnemonic
, rt
, rd
, rn
, p1
,
3750 (opcode
& (1 << 23)) ? "" : "-",
3755 address
= thumb_alignpc4(address
);
3757 if (opcode
& (1 << 23))
3761 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3762 mnemonic
, rt
, rd
, address
);
3766 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3767 struct arm_instruction
*instruction
, char *cp
)
3769 int op
= (opcode
>> 21) & 0xf;
3770 int rd
= (opcode
>> 8) & 0xf;
3771 int rn
= (opcode
>> 16) & 0xf;
3772 int type
= (opcode
>> 4) & 0x3;
3773 int immed
= (opcode
>> 6) & 0x3;
3777 immed
|= (opcode
>> 10) & 0x1c;
3778 if (opcode
& (1 << 20))
3784 if (!(opcode
& (1 << 20)))
3785 return ERROR_COMMAND_SYNTAX_ERROR
;
3786 instruction
->type
= ARM_TST
;
3791 instruction
->type
= ARM_AND
;
3795 instruction
->type
= ARM_BIC
;
3800 instruction
->type
= ARM_MOV
;
3804 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3806 (int) (opcode
& 0xf));
3819 sprintf(cp
, "RRX%s\tr%d, r%d",
3821 (int) (opcode
& 0xf));
3829 instruction
->type
= ARM_ORR
;
3835 instruction
->type
= ARM_MVN
;
3840 /* instruction->type = ARM_ORN; */
3846 if (!(opcode
& (1 << 20)))
3847 return ERROR_COMMAND_SYNTAX_ERROR
;
3848 instruction
->type
= ARM_TEQ
;
3853 instruction
->type
= ARM_EOR
;
3858 if (!(opcode
& (1 << 20)))
3859 return ERROR_COMMAND_SYNTAX_ERROR
;
3860 instruction
->type
= ARM_CMN
;
3865 instruction
->type
= ARM_ADD
;
3869 instruction
->type
= ARM_ADC
;
3873 instruction
->type
= ARM_SBC
;
3878 if (!(opcode
& (1 << 21)))
3879 return ERROR_COMMAND_SYNTAX_ERROR
;
3880 instruction
->type
= ARM_CMP
;
3885 instruction
->type
= ARM_SUB
;
3889 instruction
->type
= ARM_RSB
;
3893 return ERROR_COMMAND_SYNTAX_ERROR
;
3896 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3897 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3920 strcpy(cp
, ", RRX");
3926 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3930 sprintf(cp
, "%s%s.W\tr%d, r%d",
3931 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3935 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3936 mnemonic
, suffix
, rd
,
3937 (int) (opcode
& 0xf), immed
? immed
: 32);
3941 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3942 struct arm_instruction
*instruction
, char *cp
)
3947 if (((opcode
>> 4) & 0xf) == 0) {
3948 switch ((opcode
>> 21) & 0x7) {
3962 return ERROR_COMMAND_SYNTAX_ERROR
;
3965 instruction
->type
= ARM_MOV
;
3966 if (opcode
& (1 << 20))
3968 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3970 (int) (opcode
>> 8) & 0xf,
3971 (int) (opcode
>> 16) & 0xf,
3972 (int) (opcode
>> 0) & 0xf);
3974 } else if (opcode
& (1 << 7)) {
3975 switch ((opcode
>> 20) & 0xf) {
3980 switch ((opcode
>> 4) & 0x3) {
3982 suffix
= ", ROR #8";
3985 suffix
= ", ROR #16";
3988 suffix
= ", ROR #24";
3991 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3992 (opcode
& (1 << 24)) ? 'U' : 'S',
3993 (opcode
& (1 << 26)) ? 'B' : 'H',
3994 (int) (opcode
>> 8) & 0xf,
3995 (int) (opcode
>> 0) & 0xf,
4002 if (opcode
& (1 << 6))
4003 return ERROR_COMMAND_SYNTAX_ERROR
;
4004 if (((opcode
>> 12) & 0xf) != 0xf)
4005 return ERROR_COMMAND_SYNTAX_ERROR
;
4006 if (!(opcode
& (1 << 20)))
4007 return ERROR_COMMAND_SYNTAX_ERROR
;
4009 switch (((opcode
>> 19) & 0x04)
4010 | ((opcode
>> 4) & 0x3)) {
4015 mnemonic
= "REV16.W";
4021 mnemonic
= "REVSH.W";
4027 return ERROR_COMMAND_SYNTAX_ERROR
;
4029 sprintf(cp
, "%s\tr%d, r%d",
4031 (int) (opcode
>> 8) & 0xf,
4032 (int) (opcode
>> 0) & 0xf);
4035 return ERROR_COMMAND_SYNTAX_ERROR
;
4042 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
4043 struct arm_instruction
*instruction
, char *cp
)
4045 int rn
= (opcode
>> 16) & 0xf;
4048 instruction
->type
= ARM_LDR
;
4051 immed
= opcode
& 0x0fff;
4052 if ((opcode
& (1 << 23)) == 0)
4054 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4055 (int) (opcode
>> 12) & 0xf,
4056 thumb_alignpc4(address
) + immed
);
4060 if (opcode
& (1 << 23)) {
4061 immed
= opcode
& 0x0fff;
4062 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4063 (int) (opcode
>> 12) & 0xf,
4068 if (!(opcode
& (0x3f << 6))) {
4069 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4070 (int) (opcode
>> 12) & 0xf,
4072 (int) (opcode
>> 0) & 0xf,
4073 (int) (opcode
>> 4) & 0x3);
4078 if (((opcode
>> 8) & 0xf) == 0xe) {
4079 immed
= opcode
& 0x00ff;
4081 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4082 (int) (opcode
>> 12) & 0xf,
4087 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4088 char *p1
= "]", *p2
= "";
4090 if (!(opcode
& 0x0500))
4091 return ERROR_COMMAND_SYNTAX_ERROR
;
4093 immed
= opcode
& 0x00ff;
4095 /* two indexed modes will write back rn */
4096 if (opcode
& 0x100) {
4097 if (opcode
& 0x400) /* pre-indexed */
4099 else { /* post-indexed */
4105 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4106 (int) (opcode
>> 12) & 0xf,
4108 (opcode
& 0x200) ? "" : "-",
4113 return ERROR_COMMAND_SYNTAX_ERROR
;
4116 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4117 struct arm_instruction
*instruction
, char *cp
)
4119 int rn
= (opcode
>> 16) & 0xf;
4120 int rt
= (opcode
>> 12) & 0xf;
4121 int op2
= (opcode
>> 6) & 0x3f;
4123 char *p1
= "", *p2
= "]";
4126 switch ((opcode
>> 23) & 0x3) {
4128 if ((rn
& rt
) == 0xf) {
4130 immed
= opcode
& 0xfff;
4131 address
= thumb_alignpc4(address
);
4132 if (opcode
& (1 << 23))
4136 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4140 if (rn
== 0x0f && rt
!= 0x0f) {
4142 immed
= opcode
& 0xfff;
4143 address
= thumb_alignpc4(address
);
4144 if (opcode
& (1 << 23))
4148 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4154 if ((op2
& 0x3c) == 0x38) {
4155 immed
= opcode
& 0xff;
4156 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4157 rt
, rn
, immed
, immed
);
4160 if ((op2
& 0x3c) == 0x30) {
4162 immed
= opcode
& 0xff;
4165 p1
= (opcode
& (1 << 21)) ? "W" : "";
4166 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4167 p1
, rn
, immed
, immed
);
4172 immed
= opcode
& 0xff;
4173 if (!(opcode
& 0x200))
4176 /* two indexed modes will write back rn */
4177 if (opcode
& 0x100) {
4178 if (opcode
& 0x400) /* pre-indexed */
4180 else { /* post-indexed */
4186 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4187 mnemonic
, rt
, rn
, p1
,
4191 if ((op2
& 0x24) == 0x24) {
4193 goto ldrxb_immediate_t3
;
4196 int rm
= opcode
& 0xf;
4199 sprintf(cp
, "PLD\t");
4201 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4202 immed
= (opcode
>> 4) & 0x3;
4204 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4209 if ((rn
& rt
) == 0xf)
4212 immed
= opcode
& 0xfff;
4213 goto preload_immediate
;
4217 mnemonic
= "LDRB.W";
4218 immed
= opcode
& 0xfff;
4219 goto ldrxb_immediate_t2
;
4221 if ((rn
& rt
) == 0xf) {
4222 immed
= opcode
& 0xfff;
4223 address
= thumb_alignpc4(address
);
4224 if (opcode
& (1 << 23))
4228 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4231 if (rn
== 0xf && rt
!= 0xf) {
4233 immed
= opcode
& 0xfff;
4234 address
= thumb_alignpc4(address
);
4235 if (opcode
& (1 << 23))
4239 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4244 if ((op2
& 0x3c) == 0x38) {
4245 immed
= opcode
& 0xff;
4246 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4247 rt
, rn
, immed
, immed
);
4250 if ((op2
& 0x3c) == 0x30) {
4252 immed
= opcode
& 0xff;
4253 immed
= -immed
; /* pli */
4254 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4259 goto ldrxb_immediate_t3
;
4261 if ((op2
& 0x24) == 0x24) {
4263 goto ldrxb_immediate_t3
;
4266 int rm
= opcode
& 0xf;
4269 sprintf(cp
, "PLI\t");
4271 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4272 immed
= (opcode
>> 4) & 0x3;
4274 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4280 immed
= opcode
& 0xfff;
4281 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4287 immed
= opcode
& 0xfff;
4289 goto ldrxb_immediate_t2
;
4292 return ERROR_COMMAND_SYNTAX_ERROR
;
4295 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4296 struct arm_instruction
*instruction
, char *cp
)
4298 int rn
= (opcode
>> 16) & 0xf;
4299 int rt
= (opcode
>> 12) & 0xf;
4300 int op2
= (opcode
>> 6) & 0x3f;
4305 sprintf(cp
, "HINT (UNALLOCATED)");
4309 if (opcode
& (1 << 24))
4312 if ((opcode
& (1 << 23)) == 0) {
4315 immed
= opcode
& 0xfff;
4316 address
= thumb_alignpc4(address
);
4317 if (opcode
& (1 << 23))
4321 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4326 int rm
= opcode
& 0xf;
4328 immed
= (opcode
>> 4) & 0x3;
4329 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4330 sign
, rt
, rn
, rm
, immed
);
4333 if ((op2
& 0x3c) == 0x38) {
4334 immed
= opcode
& 0xff;
4335 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4336 sign
, rt
, rn
, immed
, immed
);
4339 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4340 char *p1
= "", *p2
= "]";
4342 immed
= opcode
& 0xff;
4343 if (!(opcode
& 0x200))
4346 /* two indexed modes will write back rn */
4347 if (opcode
& 0x100) {
4348 if (opcode
& 0x400) /* pre-indexed */
4350 else { /* post-indexed */
4355 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4356 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4363 immed
= opcode
& 0xfff;
4364 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4365 sign
, *sign
? "" : ".W",
4366 rt
, rn
, immed
, immed
);
4370 return ERROR_COMMAND_SYNTAX_ERROR
;
4374 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4375 * always set. That means eventual arm_simulate_step() support for Thumb2
4376 * will need work in this area.
4378 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4385 /* clear low bit ... it's set on function pointers */
4388 /* clear fields, to avoid confusion */
4389 memset(instruction
, 0, sizeof(struct arm_instruction
));
4391 /* read first halfword, see if this is the only one */
4392 retval
= target_read_u16(target
, address
, &op
);
4393 if (retval
!= ERROR_OK
)
4396 switch (op
& 0xf800) {
4400 /* 32-bit instructions */
4401 instruction
->instruction_size
= 4;
4403 retval
= target_read_u16(target
, address
+ 2, &op
);
4404 if (retval
!= ERROR_OK
)
4407 instruction
->opcode
= opcode
;
4410 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4411 return thumb_evaluate_opcode(op
, address
, instruction
);
4414 snprintf(instruction
->text
, 128,
4415 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4417 cp
= strchr(instruction
->text
, 0);
4418 retval
= ERROR_FAIL
;
4420 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4421 if ((opcode
& 0x1a008000) == 0x10000000)
4422 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4424 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4425 else if ((opcode
& 0x1a008000) == 0x12000000)
4426 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4428 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4429 else if ((opcode
& 0x18008000) == 0x10008000)
4430 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4432 /* ARMv7-M: A5.3.5 Load/store multiple */
4433 else if ((opcode
& 0x1e400000) == 0x08000000)
4434 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4436 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4437 else if ((opcode
& 0x1e400000) == 0x08400000)
4438 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4440 /* ARMv7-M: A5.3.7 Load word */
4441 else if ((opcode
& 0x1f700000) == 0x18500000)
4442 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4444 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4445 else if ((opcode
& 0x1e700000) == 0x18300000)
4446 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4448 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4449 else if ((opcode
& 0x1e700000) == 0x18100000)
4450 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4452 /* ARMv7-M: A5.3.10 Store single data item */
4453 else if ((opcode
& 0x1f100000) == 0x18000000)
4454 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4456 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4457 else if ((opcode
& 0x1e000000) == 0x0a000000)
4458 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4460 /* ARMv7-M: A5.3.12 Data processing (register)
4461 * and A5.3.13 Miscellaneous operations
4463 else if ((opcode
& 0x1f000000) == 0x1a000000)
4464 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4466 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4467 else if ((opcode
& 0x1f800000) == 0x1b000000)
4468 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4470 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4471 else if ((opcode
& 0x1f800000) == 0x1b800000)
4472 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4474 if (retval
== ERROR_OK
)
4478 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4479 * instructions; not yet handled here.
4482 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4483 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4484 strcpy(cp
, "UNDEFINED OPCODE");
4488 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4491 strcpy(cp
, "(32-bit Thumb2 ...)");
4495 int arm_access_size(struct arm_instruction
*instruction
)
4497 if ((instruction
->type
== ARM_LDRB
)
4498 || (instruction
->type
== ARM_LDRBT
)
4499 || (instruction
->type
== ARM_LDRSB
)
4500 || (instruction
->type
== ARM_STRB
)
4501 || (instruction
->type
== ARM_STRBT
))
4503 else if ((instruction
->type
== ARM_LDRH
)
4504 || (instruction
->type
== ARM_LDRSH
)
4505 || (instruction
->type
== ARM_STRH
))
4507 else if ((instruction
->type
== ARM_LDR
)
4508 || (instruction
->type
== ARM_LDRT
)
4509 || (instruction
->type
== ARM_STR
)
4510 || (instruction
->type
== ARM_STRT
))
4512 else if ((instruction
->type
== ARM_LDRD
)
4513 || (instruction
->type
== ARM_STRD
))
4516 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)