1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
27 #include "arm_disassembler.h"
32 * This disassembler supports two main functions for OpenOCD:
34 * - Various "disassemble" commands. OpenOCD can serve as a
35 * machine-language debugger, without help from GDB.
37 * - Single stepping. Not all ARM cores support hardware single
38 * stepping. To work without that support, the debugger must
39 * be able to decode instructions to find out where to put a
40 * "next instruction" breakpoint.
42 * In addition, interpretation of ETM trace data needs some of the
43 * decoding mechanisms.
45 * At this writing (September 2009) neither function is complete.
48 * * Old-style syntax (not UAL) is generally used
49 * * VFP instructions are not understood (ARMv5 and later)
50 * except as coprocessor 10/11 operations
51 * * Most ARM instructions through ARMv6 are decoded, but some
52 * of the post-ARMv4 opcodes may not be handled yet
53 * * NEON instructions are not understood (ARMv7-A)
55 * - Thumb/Thumb2 decoding
56 * * UAL syntax should be consistently used
57 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
58 * be handled properly. Accordingly, so should the subset
59 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
61 * * Conditional effects of Thumb2 "IT" (if-then) instructions
62 * are not handled: the affected instructions are not shown
63 * with their now-conditional suffixes.
64 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
65 * handled (minimally for coprocessor access).
66 * * SIMD instructions, and some other Thumb2 instructions
67 * from ARMv7-A, are not understood.
70 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
71 * * Opcodes changed by ThumbEE mode are not handled; these
72 * instructions wrongly decode as LDM and STM.
74 * - Jazelle decoding ... no support whatsoever for Jazelle mode
75 * or decoding. ARM encourages use of the more generic ThumbEE
76 * mode, instead of Jazelle mode, in current chips.
78 * - Single-step/emulation ... spotty support, which is only weakly
79 * tested. Thumb2 is not supported. (Arguably a full simulator
80 * is not needed to support just single stepping. Recognizing
81 * branch vs non-branch instructions suffices, except when the
82 * instruction faults and triggers a synchronous exception which
83 * can be intercepted using other means.)
85 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
86 * ARM v7-R edition" gives the most complete coverage of the various
87 * generations of ARM instructions. At this writing it is publicly
88 * accessible to anyone willing to create an account at the ARM
89 * web site; see http://www.arm.com/documentation/ for information.
91 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
92 * more details relevant to the Thumb2-only processors (such as
93 * the Cortex-M implementations).
96 /* textual represenation of the condition field */
97 /* ALways (default) is ommitted (empty string) */
98 static const char *arm_condition_strings
[] =
100 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
103 /* make up for C's missing ROR */
104 static uint32_t ror(uint32_t value
, int places
)
106 return (value
>> places
) | (value
<< (32 - places
));
109 static int evaluate_pld(uint32_t opcode
,
110 uint32_t address
, arm_instruction_t
*instruction
)
113 if ((opcode
& 0x0d70f0000) == 0x0550f000)
115 instruction
->type
= ARM_PLD
;
117 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
123 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
127 LOG_ERROR("should never reach this point");
131 static int evaluate_swi(uint32_t opcode
,
132 uint32_t address
, arm_instruction_t
*instruction
)
134 instruction
->type
= ARM_SWI
;
136 snprintf(instruction
->text
, 128,
137 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
138 address
, opcode
, (opcode
& 0xffffff));
143 static int evaluate_blx_imm(uint32_t opcode
,
144 uint32_t address
, arm_instruction_t
*instruction
)
148 uint32_t target_address
;
150 instruction
->type
= ARM_BLX
;
151 immediate
= opcode
& 0x00ffffff;
153 /* sign extend 24-bit immediate */
154 if (immediate
& 0x00800000)
155 offset
= 0xff000000 | immediate
;
159 /* shift two bits left */
162 /* odd/event halfword */
163 if (opcode
& 0x01000000)
166 target_address
= address
+ 8 + offset
;
168 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
170 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
171 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
176 static int evaluate_b_bl(uint32_t opcode
,
177 uint32_t address
, arm_instruction_t
*instruction
)
182 uint32_t target_address
;
184 immediate
= opcode
& 0x00ffffff;
185 L
= (opcode
& 0x01000000) >> 24;
187 /* sign extend 24-bit immediate */
188 if (immediate
& 0x00800000)
189 offset
= 0xff000000 | immediate
;
193 /* shift two bits left */
196 target_address
= address
+ 8 + offset
;
199 instruction
->type
= ARM_BL
;
201 instruction
->type
= ARM_B
;
203 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
204 (L
) ? "L" : "", COND(opcode
), target_address
);
206 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
207 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
212 /* Coprocessor load/store and double register transfers */
213 /* both normal and extended instruction space (condition field b1111) */
214 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
215 uint32_t address
, arm_instruction_t
*instruction
)
217 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
220 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
222 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
225 cp_opcode
= (opcode
& 0xf0) >> 4;
226 Rd
= (opcode
& 0xf000) >> 12;
227 Rn
= (opcode
& 0xf0000) >> 16;
228 CRm
= (opcode
& 0xf);
231 if ((opcode
& 0x0ff00000) == 0x0c400000)
233 instruction
->type
= ARM_MCRR
;
238 if ((opcode
& 0x0ff00000) == 0x0c500000)
240 instruction
->type
= ARM_MRRC
;
244 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
245 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
247 else /* LDC or STC */
249 uint8_t CRd
, Rn
, offset
;
252 char addressing_mode
[32];
254 CRd
= (opcode
& 0xf000) >> 12;
255 Rn
= (opcode
& 0xf0000) >> 16;
256 offset
= (opcode
& 0xff);
259 if (opcode
& 0x00100000)
261 instruction
->type
= ARM_LDC
;
266 instruction
->type
= ARM_STC
;
270 U
= (opcode
& 0x00800000) >> 23;
271 N
= (opcode
& 0x00400000) >> 22;
273 /* addressing modes */
274 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
275 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
276 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
277 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
278 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
279 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
280 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
281 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
283 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
284 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
286 cp_num
, CRd
, addressing_mode
);
292 /* Coprocessor data processing instructions */
293 /* Coprocessor register transfer instructions */
294 /* both normal and extended instruction space (condition field b1111) */
295 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
296 uint32_t address
, arm_instruction_t
*instruction
)
300 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
302 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
303 cp_num
= (opcode
& 0xf00) >> 8;
304 CRd_Rd
= (opcode
& 0xf000) >> 12;
305 CRn
= (opcode
& 0xf0000) >> 16;
306 CRm
= (opcode
& 0xf);
307 opcode_2
= (opcode
& 0xe0) >> 5;
310 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
312 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
314 instruction
->type
= ARM_MRC
;
317 else /* bit 20 not set -> MCR */
319 instruction
->type
= ARM_MCR
;
323 opcode_1
= (opcode
& 0x00e00000) >> 21;
325 snprintf(instruction
->text
, 128, "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",
326 address
, opcode
, mnemonic
, cond
,
327 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
329 else /* bit 4 not set -> CDP */
331 instruction
->type
= ARM_CDP
;
334 opcode_1
= (opcode
& 0x00f00000) >> 20;
336 snprintf(instruction
->text
, 128, "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",
337 address
, opcode
, mnemonic
, cond
,
338 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
344 /* Load/store instructions */
345 static int evaluate_load_store(uint32_t opcode
,
346 uint32_t address
, arm_instruction_t
*instruction
)
348 uint8_t I
, P
, U
, B
, W
, L
;
350 char *operation
; /* "LDR" or "STR" */
351 char *suffix
; /* "", "B", "T", "BT" */
355 I
= (opcode
& 0x02000000) >> 25;
356 P
= (opcode
& 0x01000000) >> 24;
357 U
= (opcode
& 0x00800000) >> 23;
358 B
= (opcode
& 0x00400000) >> 22;
359 W
= (opcode
& 0x00200000) >> 21;
360 L
= (opcode
& 0x00100000) >> 20;
362 /* target register */
363 Rd
= (opcode
& 0xf000) >> 12;
366 Rn
= (opcode
& 0xf0000) >> 16;
368 instruction
->info
.load_store
.Rd
= Rd
;
369 instruction
->info
.load_store
.Rn
= Rn
;
370 instruction
->info
.load_store
.U
= U
;
372 /* determine operation */
378 /* determine instruction type and suffix */
381 if ((P
== 0) && (W
== 1))
384 instruction
->type
= ARM_LDRBT
;
386 instruction
->type
= ARM_STRBT
;
392 instruction
->type
= ARM_LDRB
;
394 instruction
->type
= ARM_STRB
;
400 if ((P
== 0) && (W
== 1))
403 instruction
->type
= ARM_LDRT
;
405 instruction
->type
= ARM_STRT
;
411 instruction
->type
= ARM_LDR
;
413 instruction
->type
= ARM_STR
;
418 if (!I
) /* #+-<offset_12> */
420 uint32_t offset_12
= (opcode
& 0xfff);
422 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
424 snprintf(offset
, 32, "%s", "");
426 instruction
->info
.load_store
.offset_mode
= 0;
427 instruction
->info
.load_store
.offset
.offset
= offset_12
;
429 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
431 uint8_t shift_imm
, shift
;
434 shift_imm
= (opcode
& 0xf80) >> 7;
435 shift
= (opcode
& 0x60) >> 5;
438 /* LSR encodes a shift by 32 bit as 0x0 */
439 if ((shift
== 0x1) && (shift_imm
== 0x0))
442 /* ASR encodes a shift by 32 bit as 0x0 */
443 if ((shift
== 0x2) && (shift_imm
== 0x0))
446 /* ROR by 32 bit is actually a RRX */
447 if ((shift
== 0x3) && (shift_imm
== 0x0))
450 instruction
->info
.load_store
.offset_mode
= 1;
451 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
452 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
453 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
455 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
457 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
459 else /* +-<Rm>, <Shift>, #<shift_imm> */
464 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
467 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
470 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
473 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
476 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
484 if (W
== 0) /* offset */
486 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
487 address
, opcode
, operation
, COND(opcode
), suffix
,
490 instruction
->info
.load_store
.index_mode
= 0;
492 else /* pre-indexed */
494 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
495 address
, opcode
, operation
, COND(opcode
), suffix
,
498 instruction
->info
.load_store
.index_mode
= 1;
501 else /* post-indexed */
503 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
504 address
, opcode
, operation
, COND(opcode
), suffix
,
507 instruction
->info
.load_store
.index_mode
= 2;
513 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
515 unsigned rm
= (opcode
>> 0) & 0xf;
516 unsigned rd
= (opcode
>> 12) & 0xf;
517 unsigned rn
= (opcode
>> 16) & 0xf;
520 switch ((opcode
>> 24) & 0x3) {
525 sprintf(cp
, "UNDEFINED");
526 return ARM_UNDEFINED_INSTRUCTION
;
535 switch ((opcode
>> 10) & 0x3) {
551 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
552 (opcode
& (1 << 22)) ? 'U' : 'S',
557 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
558 (opcode
& (1 << 22)) ? 'U' : 'S',
565 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
571 switch ((opcode
>> 20) & 0x7) {
594 switch ((opcode
>> 5) & 0x7) {
623 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
624 (int) (opcode
>> 12) & 0xf,
625 (int) (opcode
>> 16) & 0xf,
626 (int) (opcode
>> 0) & 0xf);
630 /* these opcodes might be used someday */
631 sprintf(cp
, "UNDEFINED");
632 return ARM_UNDEFINED_INSTRUCTION
;
635 /* ARMv6 and later support "media" instructions (includes SIMD) */
636 static int evaluate_media(uint32_t opcode
, uint32_t address
,
637 arm_instruction_t
*instruction
)
639 char *cp
= instruction
->text
;
640 char *mnemonic
= NULL
;
643 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
647 /* parallel add/subtract */
648 if ((opcode
& 0x01800000) == 0x00000000) {
649 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
654 if ((opcode
& 0x01f00020) == 0x00800000) {
656 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
658 if (opcode
& (1 << 6)) {
667 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
669 (int) (opcode
>> 12) & 0xf,
670 (int) (opcode
>> 16) & 0xf,
671 (int) (opcode
>> 0) & 0xf,
677 if ((opcode
& 0x01a00020) == 0x00a00000) {
679 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
681 if (opcode
& (1 << 6)) {
689 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
690 (opcode
& (1 << 22)) ? 'U' : 'S',
692 (int) (opcode
>> 12) & 0xf,
693 (int) (opcode
>> 16) & 0x1f,
694 (int) (opcode
>> 0) & 0xf,
700 if ((opcode
& 0x018000f0) == 0x00800070) {
701 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
706 if ((opcode
& 0x01f00080) == 0x01000000) {
707 unsigned rn
= (opcode
>> 12) & 0xf;
710 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
711 (opcode
& (1 << 6)) ? 'S' : 'A',
712 (opcode
& (1 << 5)) ? "X" : "",
714 (int) (opcode
>> 16) & 0xf,
715 (int) (opcode
>> 0) & 0xf,
716 (int) (opcode
>> 8) & 0xf,
719 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
720 (opcode
& (1 << 6)) ? 'S' : 'A',
721 (opcode
& (1 << 5)) ? "X" : "",
723 (int) (opcode
>> 16) & 0xf,
724 (int) (opcode
>> 0) & 0xf,
725 (int) (opcode
>> 8) & 0xf);
728 if ((opcode
& 0x01f00000) == 0x01400000) {
729 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
730 (opcode
& (1 << 6)) ? 'S' : 'A',
731 (opcode
& (1 << 5)) ? "X" : "",
733 (int) (opcode
>> 12) & 0xf,
734 (int) (opcode
>> 16) & 0xf,
735 (int) (opcode
>> 0) & 0xf,
736 (int) (opcode
>> 8) & 0xf);
739 if ((opcode
& 0x01f00000) == 0x01500000) {
740 unsigned rn
= (opcode
>> 12) & 0xf;
742 switch (opcode
& 0xc0) {
754 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
755 (opcode
& (1 << 6)) ? 'S' : 'A',
756 (opcode
& (1 << 5)) ? "R" : "",
758 (int) (opcode
>> 16) & 0xf,
759 (int) (opcode
>> 0) & 0xf,
760 (int) (opcode
>> 8) & 0xf,
763 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
764 (opcode
& (1 << 5)) ? "R" : "",
766 (int) (opcode
>> 16) & 0xf,
767 (int) (opcode
>> 0) & 0xf,
768 (int) (opcode
>> 8) & 0xf);
773 /* simple matches against the remaining decode bits */
774 switch (opcode
& 0x01f000f0) {
777 /* parallel halfword saturate */
778 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
779 (opcode
& (1 << 22)) ? 'U' : 'S',
781 (int) (opcode
>> 12) & 0xf,
782 (int) (opcode
>> 16) & 0xf,
783 (int) (opcode
>> 0) & 0xf);
796 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
797 (int) (opcode
>> 12) & 0xf,
798 (int) (opcode
>> 16) & 0xf,
799 (int) (opcode
>> 0) & 0xf);
802 /* unsigned sum of absolute differences */
803 if (((opcode
>> 12) & 0xf) == 0xf)
804 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
805 (int) (opcode
>> 16) & 0xf,
806 (int) (opcode
>> 0) & 0xf,
807 (int) (opcode
>> 8) & 0xf);
809 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
810 (int) (opcode
>> 16) & 0xf,
811 (int) (opcode
>> 0) & 0xf,
812 (int) (opcode
>> 8) & 0xf,
813 (int) (opcode
>> 12) & 0xf);
817 unsigned rm
= (opcode
>> 0) & 0xf;
818 unsigned rd
= (opcode
>> 12) & 0xf;
820 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
825 /* these opcodes might be used someday */
826 sprintf(cp
, "UNDEFINED");
830 /* Miscellaneous load/store instructions */
831 static int evaluate_misc_load_store(uint32_t opcode
,
832 uint32_t address
, arm_instruction_t
*instruction
)
834 uint8_t P
, U
, I
, W
, L
, S
, H
;
836 char *operation
; /* "LDR" or "STR" */
837 char *suffix
; /* "H", "SB", "SH", "D" */
841 P
= (opcode
& 0x01000000) >> 24;
842 U
= (opcode
& 0x00800000) >> 23;
843 I
= (opcode
& 0x00400000) >> 22;
844 W
= (opcode
& 0x00200000) >> 21;
845 L
= (opcode
& 0x00100000) >> 20;
846 S
= (opcode
& 0x00000040) >> 6;
847 H
= (opcode
& 0x00000020) >> 5;
849 /* target register */
850 Rd
= (opcode
& 0xf000) >> 12;
853 Rn
= (opcode
& 0xf0000) >> 16;
855 instruction
->info
.load_store
.Rd
= Rd
;
856 instruction
->info
.load_store
.Rn
= Rn
;
857 instruction
->info
.load_store
.U
= U
;
859 /* determine instruction type and suffix */
867 instruction
->type
= ARM_LDRSH
;
873 instruction
->type
= ARM_LDRSB
;
877 else /* there are no signed stores, so this is used to encode double-register load/stores */
883 instruction
->type
= ARM_STRD
;
888 instruction
->type
= ARM_LDRD
;
898 instruction
->type
= ARM_LDRH
;
903 instruction
->type
= ARM_STRH
;
907 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
909 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
910 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
912 instruction
->info
.load_store
.offset_mode
= 0;
913 instruction
->info
.load_store
.offset
.offset
= offset_8
;
915 else /* Register offset/index (+-<Rm>) */
919 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
921 instruction
->info
.load_store
.offset_mode
= 1;
922 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
923 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
924 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
929 if (W
== 0) /* offset */
931 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
932 address
, opcode
, operation
, COND(opcode
), suffix
,
935 instruction
->info
.load_store
.index_mode
= 0;
937 else /* pre-indexed */
939 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
940 address
, opcode
, operation
, COND(opcode
), suffix
,
943 instruction
->info
.load_store
.index_mode
= 1;
946 else /* post-indexed */
948 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
949 address
, opcode
, operation
, COND(opcode
), suffix
,
952 instruction
->info
.load_store
.index_mode
= 2;
958 /* Load/store multiples instructions */
959 static int evaluate_ldm_stm(uint32_t opcode
,
960 uint32_t address
, arm_instruction_t
*instruction
)
962 uint8_t P
, U
, S
, W
, L
, Rn
;
963 uint32_t register_list
;
964 char *addressing_mode
;
971 P
= (opcode
& 0x01000000) >> 24;
972 U
= (opcode
& 0x00800000) >> 23;
973 S
= (opcode
& 0x00400000) >> 22;
974 W
= (opcode
& 0x00200000) >> 21;
975 L
= (opcode
& 0x00100000) >> 20;
976 register_list
= (opcode
& 0xffff);
977 Rn
= (opcode
& 0xf0000) >> 16;
979 instruction
->info
.load_store_multiple
.Rn
= Rn
;
980 instruction
->info
.load_store_multiple
.register_list
= register_list
;
981 instruction
->info
.load_store_multiple
.S
= S
;
982 instruction
->info
.load_store_multiple
.W
= W
;
986 instruction
->type
= ARM_LDM
;
991 instruction
->type
= ARM_STM
;
999 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1000 addressing_mode
= "IB";
1004 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1005 addressing_mode
= "DB";
1012 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1013 /* "IA" is the default in UAL syntax */
1014 addressing_mode
= "";
1018 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1019 addressing_mode
= "DA";
1023 reg_list_p
= reg_list
;
1024 for (i
= 0; i
<= 15; i
++)
1026 if ((register_list
>> i
) & 1)
1031 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1035 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1040 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
1041 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
1042 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1047 /* Multiplies, extra load/stores */
1048 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1049 uint32_t address
, arm_instruction_t
*instruction
)
1051 /* Multiply (accumulate) (long) and Swap/swap byte */
1052 if ((opcode
& 0x000000f0) == 0x00000090)
1054 /* Multiply (accumulate) */
1055 if ((opcode
& 0x0f800000) == 0x00000000)
1057 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1059 Rs
= (opcode
& 0xf00) >> 8;
1060 Rn
= (opcode
& 0xf000) >> 12;
1061 Rd
= (opcode
& 0xf0000) >> 16;
1062 S
= (opcode
& 0x00100000) >> 20;
1064 /* examine A bit (accumulate) */
1065 if (opcode
& 0x00200000)
1067 instruction
->type
= ARM_MLA
;
1068 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1069 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1073 instruction
->type
= ARM_MUL
;
1074 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1075 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1081 /* Multiply (accumulate) long */
1082 if ((opcode
& 0x0f800000) == 0x00800000)
1084 char* mnemonic
= NULL
;
1085 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1087 Rs
= (opcode
& 0xf00) >> 8;
1088 RdHi
= (opcode
& 0xf000) >> 12;
1089 RdLow
= (opcode
& 0xf0000) >> 16;
1090 S
= (opcode
& 0x00100000) >> 20;
1092 switch ((opcode
& 0x00600000) >> 21)
1095 instruction
->type
= ARM_UMULL
;
1099 instruction
->type
= ARM_UMLAL
;
1103 instruction
->type
= ARM_SMULL
;
1107 instruction
->type
= ARM_SMLAL
;
1112 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1113 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1114 RdLow
, RdHi
, Rm
, Rs
);
1119 /* Swap/swap byte */
1120 if ((opcode
& 0x0f800000) == 0x01000000)
1124 Rd
= (opcode
& 0xf000) >> 12;
1125 Rn
= (opcode
& 0xf0000) >> 16;
1127 /* examine B flag */
1128 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1130 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1131 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1137 return evaluate_misc_load_store(opcode
, address
, instruction
);
1140 static int evaluate_mrs_msr(uint32_t opcode
,
1141 uint32_t address
, arm_instruction_t
*instruction
)
1143 int R
= (opcode
& 0x00400000) >> 22;
1144 char *PSR
= (R
) ? "SPSR" : "CPSR";
1146 /* Move register to status register (MSR) */
1147 if (opcode
& 0x00200000)
1149 instruction
->type
= ARM_MSR
;
1151 /* immediate variant */
1152 if (opcode
& 0x02000000)
1154 uint8_t immediate
= (opcode
& 0xff);
1155 uint8_t rotate
= (opcode
& 0xf00);
1157 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1158 address
, opcode
, COND(opcode
), PSR
,
1159 (opcode
& 0x10000) ? "c" : "",
1160 (opcode
& 0x20000) ? "x" : "",
1161 (opcode
& 0x40000) ? "s" : "",
1162 (opcode
& 0x80000) ? "f" : "",
1163 ror(immediate
, (rotate
* 2))
1166 else /* register variant */
1168 uint8_t Rm
= opcode
& 0xf;
1169 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1170 address
, opcode
, COND(opcode
), PSR
,
1171 (opcode
& 0x10000) ? "c" : "",
1172 (opcode
& 0x20000) ? "x" : "",
1173 (opcode
& 0x40000) ? "s" : "",
1174 (opcode
& 0x80000) ? "f" : "",
1180 else /* Move status register to register (MRS) */
1184 instruction
->type
= ARM_MRS
;
1185 Rd
= (opcode
& 0x0000f000) >> 12;
1187 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1188 address
, opcode
, COND(opcode
), Rd
, PSR
);
1194 /* Miscellaneous instructions */
1195 static int evaluate_misc_instr(uint32_t opcode
,
1196 uint32_t address
, arm_instruction_t
*instruction
)
1199 if ((opcode
& 0x000000f0) == 0x00000000)
1201 evaluate_mrs_msr(opcode
, address
, instruction
);
1205 if ((opcode
& 0x006000f0) == 0x00200010)
1208 instruction
->type
= ARM_BX
;
1211 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1212 address
, opcode
, COND(opcode
), Rm
);
1214 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1215 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1218 /* BXJ - "Jazelle" support (ARMv5-J) */
1219 if ((opcode
& 0x006000f0) == 0x00200020)
1222 instruction
->type
= ARM_BX
;
1225 snprintf(instruction
->text
, 128,
1226 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1227 address
, opcode
, COND(opcode
), Rm
);
1229 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1230 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1234 if ((opcode
& 0x006000f0) == 0x00600010)
1237 instruction
->type
= ARM_CLZ
;
1239 Rd
= (opcode
& 0xf000) >> 12;
1241 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1242 address
, opcode
, COND(opcode
), Rd
, Rm
);
1246 if ((opcode
& 0x006000f0) == 0x00200030)
1249 instruction
->type
= ARM_BLX
;
1252 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1253 address
, opcode
, COND(opcode
), Rm
);
1255 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1256 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1259 /* Enhanced DSP add/subtracts */
1260 if ((opcode
& 0x0000000f0) == 0x00000050)
1263 char *mnemonic
= NULL
;
1265 Rd
= (opcode
& 0xf000) >> 12;
1266 Rn
= (opcode
& 0xf0000) >> 16;
1268 switch ((opcode
& 0x00600000) >> 21)
1271 instruction
->type
= ARM_QADD
;
1275 instruction
->type
= ARM_QSUB
;
1279 instruction
->type
= ARM_QDADD
;
1283 instruction
->type
= ARM_QDSUB
;
1288 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1289 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1292 /* Software breakpoints */
1293 if ((opcode
& 0x0000000f0) == 0x00000070)
1296 instruction
->type
= ARM_BKPT
;
1297 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1299 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1300 address
, opcode
, immediate
);
1303 /* Enhanced DSP multiplies */
1304 if ((opcode
& 0x000000090) == 0x00000080)
1306 int x
= (opcode
& 0x20) >> 5;
1307 int y
= (opcode
& 0x40) >> 6;
1310 if ((opcode
& 0x00600000) == 0x00000000)
1312 uint8_t Rd
, Rm
, Rs
, Rn
;
1313 instruction
->type
= ARM_SMLAxy
;
1314 Rd
= (opcode
& 0xf0000) >> 16;
1315 Rm
= (opcode
& 0xf);
1316 Rs
= (opcode
& 0xf00) >> 8;
1317 Rn
= (opcode
& 0xf000) >> 12;
1319 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1320 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1325 if ((opcode
& 0x00600000) == 0x00400000)
1327 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1328 instruction
->type
= ARM_SMLAxy
;
1329 RdHi
= (opcode
& 0xf0000) >> 16;
1330 RdLow
= (opcode
& 0xf000) >> 12;
1331 Rm
= (opcode
& 0xf);
1332 Rs
= (opcode
& 0xf00) >> 8;
1334 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1335 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1336 RdLow
, RdHi
, Rm
, Rs
);
1340 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1342 uint8_t Rd
, Rm
, Rs
, Rn
;
1343 instruction
->type
= ARM_SMLAWy
;
1344 Rd
= (opcode
& 0xf0000) >> 16;
1345 Rm
= (opcode
& 0xf);
1346 Rs
= (opcode
& 0xf00) >> 8;
1347 Rn
= (opcode
& 0xf000) >> 12;
1349 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1350 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1355 if ((opcode
& 0x00600000) == 0x00300000)
1358 instruction
->type
= ARM_SMULxy
;
1359 Rd
= (opcode
& 0xf0000) >> 16;
1360 Rm
= (opcode
& 0xf);
1361 Rs
= (opcode
& 0xf00) >> 8;
1363 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1364 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1369 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1372 instruction
->type
= ARM_SMULWy
;
1373 Rd
= (opcode
& 0xf0000) >> 16;
1374 Rm
= (opcode
& 0xf);
1375 Rs
= (opcode
& 0xf00) >> 8;
1377 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1378 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1386 static int evaluate_data_proc(uint32_t opcode
,
1387 uint32_t address
, arm_instruction_t
*instruction
)
1389 uint8_t I
, op
, S
, Rn
, Rd
;
1390 char *mnemonic
= NULL
;
1391 char shifter_operand
[32];
1393 I
= (opcode
& 0x02000000) >> 25;
1394 op
= (opcode
& 0x01e00000) >> 21;
1395 S
= (opcode
& 0x00100000) >> 20;
1397 Rd
= (opcode
& 0xf000) >> 12;
1398 Rn
= (opcode
& 0xf0000) >> 16;
1400 instruction
->info
.data_proc
.Rd
= Rd
;
1401 instruction
->info
.data_proc
.Rn
= Rn
;
1402 instruction
->info
.data_proc
.S
= S
;
1407 instruction
->type
= ARM_AND
;
1411 instruction
->type
= ARM_EOR
;
1415 instruction
->type
= ARM_SUB
;
1419 instruction
->type
= ARM_RSB
;
1423 instruction
->type
= ARM_ADD
;
1427 instruction
->type
= ARM_ADC
;
1431 instruction
->type
= ARM_SBC
;
1435 instruction
->type
= ARM_RSC
;
1439 instruction
->type
= ARM_TST
;
1443 instruction
->type
= ARM_TEQ
;
1447 instruction
->type
= ARM_CMP
;
1451 instruction
->type
= ARM_CMN
;
1455 instruction
->type
= ARM_ORR
;
1459 instruction
->type
= ARM_MOV
;
1463 instruction
->type
= ARM_BIC
;
1467 instruction
->type
= ARM_MVN
;
1472 if (I
) /* immediate shifter operand (#<immediate>)*/
1474 uint8_t immed_8
= opcode
& 0xff;
1475 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1478 immediate
= ror(immed_8
, rotate_imm
* 2);
1480 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1482 instruction
->info
.data_proc
.variant
= 0;
1483 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1485 else /* register-based shifter operand */
1488 shift
= (opcode
& 0x60) >> 5;
1489 Rm
= (opcode
& 0xf);
1491 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1494 shift_imm
= (opcode
& 0xf80) >> 7;
1496 instruction
->info
.data_proc
.variant
= 1;
1497 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1498 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1499 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1501 /* LSR encodes a shift by 32 bit as 0x0 */
1502 if ((shift
== 0x1) && (shift_imm
== 0x0))
1505 /* ASR encodes a shift by 32 bit as 0x0 */
1506 if ((shift
== 0x2) && (shift_imm
== 0x0))
1509 /* ROR by 32 bit is actually a RRX */
1510 if ((shift
== 0x3) && (shift_imm
== 0x0))
1513 if ((shift_imm
== 0x0) && (shift
== 0x0))
1515 snprintf(shifter_operand
, 32, "r%i", Rm
);
1519 if (shift
== 0x0) /* LSL */
1521 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1523 else if (shift
== 0x1) /* LSR */
1525 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1527 else if (shift
== 0x2) /* ASR */
1529 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1531 else if (shift
== 0x3) /* ROR */
1533 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1535 else if (shift
== 0x4) /* RRX */
1537 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1541 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1543 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1545 instruction
->info
.data_proc
.variant
= 2;
1546 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1547 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1548 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1550 if (shift
== 0x0) /* LSL */
1552 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1554 else if (shift
== 0x1) /* LSR */
1556 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1558 else if (shift
== 0x2) /* ASR */
1560 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1562 else if (shift
== 0x3) /* ROR */
1564 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1569 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1571 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1572 address
, opcode
, mnemonic
, COND(opcode
),
1573 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1575 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1577 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1578 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1580 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1581 address
, opcode
, mnemonic
, COND(opcode
),
1582 (S
) ? "S" : "", Rd
, shifter_operand
);
1584 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1586 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1587 address
, opcode
, mnemonic
, COND(opcode
),
1588 Rn
, shifter_operand
);
1594 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1596 /* clear fields, to avoid confusion */
1597 memset(instruction
, 0, sizeof(arm_instruction_t
));
1598 instruction
->opcode
= opcode
;
1599 instruction
->instruction_size
= 4;
1601 /* catch opcodes with condition field [31:28] = b1111 */
1602 if ((opcode
& 0xf0000000) == 0xf0000000)
1604 /* Undefined instruction (or ARMv5E cache preload PLD) */
1605 if ((opcode
& 0x08000000) == 0x00000000)
1606 return evaluate_pld(opcode
, address
, instruction
);
1608 /* Undefined instruction */
1609 if ((opcode
& 0x0e000000) == 0x08000000)
1611 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1612 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1616 /* Branch and branch with link and change to Thumb */
1617 if ((opcode
& 0x0e000000) == 0x0a000000)
1618 return evaluate_blx_imm(opcode
, address
, instruction
);
1620 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1621 /* Coprocessor load/store and double register transfers */
1622 if ((opcode
& 0x0e000000) == 0x0c000000)
1623 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1625 /* Coprocessor data processing */
1626 if ((opcode
& 0x0f000100) == 0x0c000000)
1627 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1629 /* Coprocessor register transfers */
1630 if ((opcode
& 0x0f000010) == 0x0c000010)
1631 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1633 /* Undefined instruction */
1634 if ((opcode
& 0x0f000000) == 0x0f000000)
1636 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1637 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1642 /* catch opcodes with [27:25] = b000 */
1643 if ((opcode
& 0x0e000000) == 0x00000000)
1645 /* Multiplies, extra load/stores */
1646 if ((opcode
& 0x00000090) == 0x00000090)
1647 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1649 /* Miscellaneous instructions */
1650 if ((opcode
& 0x0f900000) == 0x01000000)
1651 return evaluate_misc_instr(opcode
, address
, instruction
);
1653 return evaluate_data_proc(opcode
, address
, instruction
);
1656 /* catch opcodes with [27:25] = b001 */
1657 if ((opcode
& 0x0e000000) == 0x02000000)
1659 /* Undefined instruction */
1660 if ((opcode
& 0x0fb00000) == 0x03000000)
1662 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1663 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1667 /* Move immediate to status register */
1668 if ((opcode
& 0x0fb00000) == 0x03200000)
1669 return evaluate_mrs_msr(opcode
, address
, instruction
);
1671 return evaluate_data_proc(opcode
, address
, instruction
);
1675 /* catch opcodes with [27:25] = b010 */
1676 if ((opcode
& 0x0e000000) == 0x04000000)
1678 /* Load/store immediate offset */
1679 return evaluate_load_store(opcode
, address
, instruction
);
1682 /* catch opcodes with [27:25] = b011 */
1683 if ((opcode
& 0x0e000000) == 0x06000000)
1685 /* Load/store register offset */
1686 if ((opcode
& 0x00000010) == 0x00000000)
1687 return evaluate_load_store(opcode
, address
, instruction
);
1689 /* Architecturally Undefined instruction
1690 * ... don't expect these to ever be used
1692 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1694 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1695 snprintf(instruction
->text
, 128,
1696 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1701 /* "media" instructions */
1702 return evaluate_media(opcode
, address
, instruction
);
1705 /* catch opcodes with [27:25] = b100 */
1706 if ((opcode
& 0x0e000000) == 0x08000000)
1708 /* Load/store multiple */
1709 return evaluate_ldm_stm(opcode
, address
, instruction
);
1712 /* catch opcodes with [27:25] = b101 */
1713 if ((opcode
& 0x0e000000) == 0x0a000000)
1715 /* Branch and branch with link */
1716 return evaluate_b_bl(opcode
, address
, instruction
);
1719 /* catch opcodes with [27:25] = b110 */
1720 if ((opcode
& 0x0e000000) == 0x0a000000)
1722 /* Coprocessor load/store and double register transfers */
1723 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1726 /* catch opcodes with [27:25] = b111 */
1727 if ((opcode
& 0x0e000000) == 0x0e000000)
1729 /* Software interrupt */
1730 if ((opcode
& 0x0f000000) == 0x0f000000)
1731 return evaluate_swi(opcode
, address
, instruction
);
1733 /* Coprocessor data processing */
1734 if ((opcode
& 0x0f000010) == 0x0e000000)
1735 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1737 /* Coprocessor register transfers */
1738 if ((opcode
& 0x0f000010) == 0x0e000010)
1739 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1742 LOG_ERROR("should never reach this point");
1746 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1747 uint32_t address
, arm_instruction_t
*instruction
)
1749 uint32_t offset
= opcode
& 0x7ff;
1750 uint32_t opc
= (opcode
>> 11) & 0x3;
1751 uint32_t target_address
;
1752 char *mnemonic
= NULL
;
1754 /* sign extend 11-bit offset */
1755 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1756 offset
= 0xfffff800 | offset
;
1758 target_address
= address
+ 4 + (offset
<< 1);
1762 /* unconditional branch */
1764 instruction
->type
= ARM_B
;
1769 instruction
->type
= ARM_BLX
;
1774 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1775 mnemonic
= "prefix";
1776 target_address
= offset
<< 12;
1780 instruction
->type
= ARM_BL
;
1785 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1786 * these are effectively 32-bit instructions even in Thumb1.
1787 * Might be simplest to always use the Thumb2 decoder.
1790 snprintf(instruction
->text
, 128,
1791 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1792 address
, opcode
, mnemonic
, target_address
);
1794 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1795 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1800 static int evaluate_add_sub_thumb(uint16_t opcode
,
1801 uint32_t address
, arm_instruction_t
*instruction
)
1803 uint8_t Rd
= (opcode
>> 0) & 0x7;
1804 uint8_t Rn
= (opcode
>> 3) & 0x7;
1805 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1806 uint32_t opc
= opcode
& (1 << 9);
1807 uint32_t reg_imm
= opcode
& (1 << 10);
1812 instruction
->type
= ARM_SUB
;
1817 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1818 instruction
->type
= ARM_ADD
;
1822 instruction
->info
.data_proc
.Rd
= Rd
;
1823 instruction
->info
.data_proc
.Rn
= Rn
;
1824 instruction
->info
.data_proc
.S
= 1;
1828 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1829 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1830 snprintf(instruction
->text
, 128,
1831 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1832 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1836 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1837 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1838 snprintf(instruction
->text
, 128,
1839 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1840 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1846 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1847 uint32_t address
, arm_instruction_t
*instruction
)
1849 uint8_t Rd
= (opcode
>> 0) & 0x7;
1850 uint8_t Rm
= (opcode
>> 3) & 0x7;
1851 uint8_t imm
= (opcode
>> 6) & 0x1f;
1852 uint8_t opc
= (opcode
>> 11) & 0x3;
1853 char *mnemonic
= NULL
;
1858 instruction
->type
= ARM_MOV
;
1860 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1863 instruction
->type
= ARM_MOV
;
1865 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1868 instruction
->type
= ARM_MOV
;
1870 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1874 if ((imm
== 0) && (opc
!= 0))
1877 instruction
->info
.data_proc
.Rd
= Rd
;
1878 instruction
->info
.data_proc
.Rn
= -1;
1879 instruction
->info
.data_proc
.S
= 1;
1881 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1882 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1883 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1885 snprintf(instruction
->text
, 128,
1886 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1887 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1892 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1893 uint32_t address
, arm_instruction_t
*instruction
)
1895 uint8_t imm
= opcode
& 0xff;
1896 uint8_t Rd
= (opcode
>> 8) & 0x7;
1897 uint32_t opc
= (opcode
>> 11) & 0x3;
1898 char *mnemonic
= NULL
;
1900 instruction
->info
.data_proc
.Rd
= Rd
;
1901 instruction
->info
.data_proc
.Rn
= Rd
;
1902 instruction
->info
.data_proc
.S
= 1;
1903 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1904 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1909 instruction
->type
= ARM_MOV
;
1911 instruction
->info
.data_proc
.Rn
= -1;
1914 instruction
->type
= ARM_CMP
;
1916 instruction
->info
.data_proc
.Rd
= -1;
1919 instruction
->type
= ARM_ADD
;
1923 instruction
->type
= ARM_SUB
;
1928 snprintf(instruction
->text
, 128,
1929 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1930 address
, opcode
, mnemonic
, Rd
, imm
);
1935 static int evaluate_data_proc_thumb(uint16_t opcode
,
1936 uint32_t address
, arm_instruction_t
*instruction
)
1938 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1939 char *mnemonic
= NULL
;
1942 high_reg
= (opcode
& 0x0400) >> 10;
1943 op
= (opcode
& 0x03C0) >> 6;
1945 Rd
= (opcode
& 0x0007);
1946 Rm
= (opcode
& 0x0038) >> 3;
1947 H1
= (opcode
& 0x0080) >> 7;
1948 H2
= (opcode
& 0x0040) >> 6;
1950 instruction
->info
.data_proc
.Rd
= Rd
;
1951 instruction
->info
.data_proc
.Rn
= Rd
;
1952 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1953 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1954 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1965 instruction
->type
= ARM_ADD
;
1969 instruction
->type
= ARM_CMP
;
1973 instruction
->type
= ARM_MOV
;
1979 if ((opcode
& 0x7) == 0x0)
1981 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1984 instruction
->type
= ARM_BLX
;
1985 snprintf(instruction
->text
, 128,
1987 " 0x%4.4x \tBLX\tr%i",
1988 address
, opcode
, Rm
);
1992 instruction
->type
= ARM_BX
;
1993 snprintf(instruction
->text
, 128,
1995 " 0x%4.4x \tBX\tr%i",
1996 address
, opcode
, Rm
);
2001 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2002 snprintf(instruction
->text
, 128,
2005 "UNDEFINED INSTRUCTION",
2017 instruction
->type
= ARM_AND
;
2021 instruction
->type
= ARM_EOR
;
2025 instruction
->type
= ARM_MOV
;
2027 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2028 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2029 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2030 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2033 instruction
->type
= ARM_MOV
;
2035 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2036 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2037 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2038 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2041 instruction
->type
= ARM_MOV
;
2043 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2044 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2045 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2046 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2049 instruction
->type
= ARM_ADC
;
2053 instruction
->type
= ARM_SBC
;
2057 instruction
->type
= ARM_MOV
;
2059 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2060 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2061 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2062 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2065 instruction
->type
= ARM_TST
;
2069 instruction
->type
= ARM_RSB
;
2071 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2072 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2073 instruction
->info
.data_proc
.Rn
= Rm
;
2076 instruction
->type
= ARM_CMP
;
2080 instruction
->type
= ARM_CMN
;
2084 instruction
->type
= ARM_ORR
;
2088 instruction
->type
= ARM_MUL
;
2092 instruction
->type
= ARM_BIC
;
2096 instruction
->type
= ARM_MVN
;
2103 snprintf(instruction
->text
, 128,
2104 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2106 address
, opcode
, mnemonic
, Rd
, Rm
);
2108 snprintf(instruction
->text
, 128,
2109 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2110 address
, opcode
, mnemonic
, Rd
, Rm
);
2115 /* PC-relative data addressing is word-aligned even with Thumb */
2116 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2118 return (addr
+ 4) & ~3;
2121 static int evaluate_load_literal_thumb(uint16_t opcode
,
2122 uint32_t address
, arm_instruction_t
*instruction
)
2125 uint8_t Rd
= (opcode
>> 8) & 0x7;
2127 instruction
->type
= ARM_LDR
;
2128 immediate
= opcode
& 0x000000ff;
2131 instruction
->info
.load_store
.Rd
= Rd
;
2132 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2133 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2134 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2135 instruction
->info
.load_store
.offset
.offset
= immediate
;
2137 snprintf(instruction
->text
, 128,
2138 "0x%8.8" PRIx32
" 0x%4.4x \t"
2139 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2140 address
, opcode
, Rd
, immediate
,
2141 thumb_alignpc4(address
) + immediate
);
2146 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2147 uint32_t address
, arm_instruction_t
*instruction
)
2149 uint8_t Rd
= (opcode
>> 0) & 0x7;
2150 uint8_t Rn
= (opcode
>> 3) & 0x7;
2151 uint8_t Rm
= (opcode
>> 6) & 0x7;
2152 uint8_t opc
= (opcode
>> 9) & 0x7;
2153 char *mnemonic
= NULL
;
2158 instruction
->type
= ARM_STR
;
2162 instruction
->type
= ARM_STRH
;
2166 instruction
->type
= ARM_STRB
;
2170 instruction
->type
= ARM_LDRSB
;
2174 instruction
->type
= ARM_LDR
;
2178 instruction
->type
= ARM_LDRH
;
2182 instruction
->type
= ARM_LDRB
;
2186 instruction
->type
= ARM_LDRSH
;
2191 snprintf(instruction
->text
, 128,
2192 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2193 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2195 instruction
->info
.load_store
.Rd
= Rd
;
2196 instruction
->info
.load_store
.Rn
= Rn
;
2197 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2198 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2199 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2204 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2205 uint32_t address
, arm_instruction_t
*instruction
)
2207 uint32_t offset
= (opcode
>> 6) & 0x1f;
2208 uint8_t Rd
= (opcode
>> 0) & 0x7;
2209 uint8_t Rn
= (opcode
>> 3) & 0x7;
2210 uint32_t L
= opcode
& (1 << 11);
2211 uint32_t B
= opcode
& (1 << 12);
2218 instruction
->type
= ARM_LDR
;
2223 instruction
->type
= ARM_STR
;
2227 if ((opcode
&0xF000) == 0x8000)
2238 snprintf(instruction
->text
, 128,
2239 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2240 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2242 instruction
->info
.load_store
.Rd
= Rd
;
2243 instruction
->info
.load_store
.Rn
= Rn
;
2244 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2245 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2246 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2251 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2252 uint32_t address
, arm_instruction_t
*instruction
)
2254 uint32_t offset
= opcode
& 0xff;
2255 uint8_t Rd
= (opcode
>> 8) & 0x7;
2256 uint32_t L
= opcode
& (1 << 11);
2261 instruction
->type
= ARM_LDR
;
2266 instruction
->type
= ARM_STR
;
2270 snprintf(instruction
->text
, 128,
2271 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2272 address
, opcode
, mnemonic
, Rd
, offset
*4);
2274 instruction
->info
.load_store
.Rd
= Rd
;
2275 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2276 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2277 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2278 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2283 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2284 uint32_t address
, arm_instruction_t
*instruction
)
2286 uint32_t imm
= opcode
& 0xff;
2287 uint8_t Rd
= (opcode
>> 8) & 0x7;
2289 uint32_t SP
= opcode
& (1 << 11);
2292 instruction
->type
= ARM_ADD
;
2305 snprintf(instruction
->text
, 128,
2306 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2307 address
, opcode
, Rd
, reg_name
, imm
* 4);
2309 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2310 instruction
->info
.data_proc
.Rd
= Rd
;
2311 instruction
->info
.data_proc
.Rn
= Rn
;
2312 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2317 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2318 uint32_t address
, arm_instruction_t
*instruction
)
2320 uint32_t imm
= opcode
& 0x7f;
2321 uint8_t opc
= opcode
& (1 << 7);
2327 instruction
->type
= ARM_SUB
;
2332 instruction
->type
= ARM_ADD
;
2336 snprintf(instruction
->text
, 128,
2337 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2338 address
, opcode
, mnemonic
, imm
*4);
2340 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2341 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2342 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2343 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2348 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2349 uint32_t address
, arm_instruction_t
*instruction
)
2351 uint32_t imm
= opcode
& 0xff;
2353 instruction
->type
= ARM_BKPT
;
2355 snprintf(instruction
->text
, 128,
2356 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2357 address
, opcode
, imm
);
2362 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2363 uint32_t address
, arm_instruction_t
*instruction
)
2365 uint32_t reg_list
= opcode
& 0xff;
2366 uint32_t L
= opcode
& (1 << 11);
2367 uint32_t R
= opcode
& (1 << 8);
2368 uint8_t Rn
= (opcode
>> 8) & 7;
2369 uint8_t addr_mode
= 0 /* IA */;
2373 char ptr_name
[7] = "";
2376 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2377 * The STMIA and LDMIA opcodes are used for other instructions.
2380 if ((opcode
& 0xf000) == 0xc000)
2381 { /* generic load/store multiple */
2386 instruction
->type
= ARM_LDM
;
2388 if (opcode
& (1 << Rn
))
2393 instruction
->type
= ARM_STM
;
2396 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2403 instruction
->type
= ARM_LDM
;
2406 reg_list
|= (1 << 15) /*PC*/;
2410 instruction
->type
= ARM_STM
;
2412 addr_mode
= 3; /*DB*/
2414 reg_list
|= (1 << 14) /*LR*/;
2418 reg_names_p
= reg_names
;
2419 for (i
= 0; i
<= 15; i
++)
2421 if (reg_list
& (1 << i
))
2422 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2424 if (reg_names_p
> reg_names
)
2425 reg_names_p
[-2] = '\0';
2426 else /* invalid op : no registers */
2427 reg_names
[0] = '\0';
2429 snprintf(instruction
->text
, 128,
2430 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2431 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2433 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2434 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2435 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2440 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2441 uint32_t address
, arm_instruction_t
*instruction
)
2443 uint32_t offset
= opcode
& 0xff;
2444 uint8_t cond
= (opcode
>> 8) & 0xf;
2445 uint32_t target_address
;
2449 instruction
->type
= ARM_SWI
;
2450 snprintf(instruction
->text
, 128,
2451 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2452 address
, opcode
, offset
);
2455 else if (cond
== 0xe)
2457 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2458 snprintf(instruction
->text
, 128,
2459 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2464 /* sign extend 8-bit offset */
2465 if (offset
& 0x00000080)
2466 offset
= 0xffffff00 | offset
;
2468 target_address
= address
+ 4 + (offset
<< 1);
2470 snprintf(instruction
->text
, 128,
2471 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2473 arm_condition_strings
[cond
], target_address
);
2475 instruction
->type
= ARM_B
;
2476 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2477 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2482 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2483 arm_instruction_t
*instruction
)
2487 /* added in Thumb2 */
2488 offset
= (opcode
>> 3) & 0x1f;
2489 offset
|= (opcode
& 0x0200) >> 4;
2491 snprintf(instruction
->text
, 128,
2492 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2494 (opcode
& 0x0800) ? "N" : "",
2495 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2500 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2501 arm_instruction_t
*instruction
)
2503 /* added in ARMv6 */
2504 snprintf(instruction
->text
, 128,
2505 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2507 (opcode
& 0x0080) ? 'U' : 'S',
2508 (opcode
& 0x0040) ? 'B' : 'H',
2509 opcode
& 0x7, (opcode
>> 3) & 0x7);
2514 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2515 arm_instruction_t
*instruction
)
2517 /* added in ARMv6 */
2518 if ((opcode
& 0x0ff0) == 0x0650)
2519 snprintf(instruction
->text
, 128,
2520 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2522 (opcode
& 0x80) ? "BE" : "LE");
2523 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2524 snprintf(instruction
->text
, 128,
2525 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2527 (opcode
& 0x0010) ? 'D' : 'E',
2528 (opcode
& 0x0004) ? "A" : "",
2529 (opcode
& 0x0002) ? "I" : "",
2530 (opcode
& 0x0001) ? "F" : "");
2535 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2536 arm_instruction_t
*instruction
)
2540 /* added in ARMv6 */
2541 switch ((opcode
>> 6) & 3) {
2552 snprintf(instruction
->text
, 128,
2553 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2554 address
, opcode
, suffix
,
2555 opcode
& 0x7, (opcode
>> 3) & 0x7);
2560 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2561 arm_instruction_t
*instruction
)
2565 switch ((opcode
>> 4) & 0x0f) {
2582 hint
= "HINT (UNRECOGNIZED)";
2586 snprintf(instruction
->text
, 128,
2587 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2588 address
, opcode
, hint
);
2593 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2594 arm_instruction_t
*instruction
)
2596 unsigned cond
= (opcode
>> 4) & 0x0f;
2597 char *x
= "", *y
= "", *z
= "";
2600 z
= (opcode
& 0x02) ? "T" : "E";
2602 y
= (opcode
& 0x04) ? "T" : "E";
2604 x
= (opcode
& 0x08) ? "T" : "E";
2606 snprintf(instruction
->text
, 128,
2607 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2609 x
, y
, z
, arm_condition_strings
[cond
]);
2611 /* NOTE: strictly speaking, the next 1-4 instructions should
2612 * now be displayed with the relevant conditional suffix...
2618 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2620 /* clear fields, to avoid confusion */
2621 memset(instruction
, 0, sizeof(arm_instruction_t
));
2622 instruction
->opcode
= opcode
;
2623 instruction
->instruction_size
= 2;
2625 if ((opcode
& 0xe000) == 0x0000)
2627 /* add/substract register or immediate */
2628 if ((opcode
& 0x1800) == 0x1800)
2629 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2630 /* shift by immediate */
2632 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2635 /* Add/substract/compare/move immediate */
2636 if ((opcode
& 0xe000) == 0x2000)
2638 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2641 /* Data processing instructions */
2642 if ((opcode
& 0xf800) == 0x4000)
2644 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2647 /* Load from literal pool */
2648 if ((opcode
& 0xf800) == 0x4800)
2650 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2653 /* Load/Store register offset */
2654 if ((opcode
& 0xf000) == 0x5000)
2656 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2659 /* Load/Store immediate offset */
2660 if (((opcode
& 0xe000) == 0x6000)
2661 ||((opcode
& 0xf000) == 0x8000))
2663 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2666 /* Load/Store from/to stack */
2667 if ((opcode
& 0xf000) == 0x9000)
2669 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2673 if ((opcode
& 0xf000) == 0xa000)
2675 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2679 if ((opcode
& 0xf000) == 0xb000)
2681 switch ((opcode
>> 8) & 0x0f) {
2683 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2688 return evaluate_cb_thumb(opcode
, address
, instruction
);
2690 return evaluate_extend_thumb(opcode
, address
, instruction
);
2695 return evaluate_load_store_multiple_thumb(opcode
, address
,
2698 return evaluate_cps_thumb(opcode
, address
, instruction
);
2700 if ((opcode
& 0x00c0) == 0x0080)
2702 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2704 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2706 if (opcode
& 0x000f)
2707 return evaluate_ifthen_thumb(opcode
, address
,
2710 return evaluate_hint_thumb(opcode
, address
,
2714 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2715 snprintf(instruction
->text
, 128,
2716 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2721 /* Load/Store multiple */
2722 if ((opcode
& 0xf000) == 0xc000)
2724 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2727 /* Conditional branch + SWI */
2728 if ((opcode
& 0xf000) == 0xd000)
2730 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2733 if ((opcode
& 0xe000) == 0xe000)
2735 /* Undefined instructions */
2736 if ((opcode
& 0xf801) == 0xe801)
2738 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2739 snprintf(instruction
->text
, 128,
2740 "0x%8.8" PRIx32
" 0x%8.8x\t"
2741 "UNDEFINED INSTRUCTION",
2746 { /* Branch to offset */
2747 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2751 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2755 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2756 arm_instruction_t
*instruction
, char *cp
)
2759 unsigned b21
= 1 << 21;
2760 unsigned b22
= 1 << 22;
2762 /* instead of combining two smaller 16-bit branch instructions,
2763 * Thumb2 uses only one larger 32-bit instruction.
2765 offset
= opcode
& 0x7ff;
2766 offset
|= (opcode
& 0x03ff0000) >> 5;
2767 if (opcode
& (1 << 26)) {
2768 offset
|= 0xff << 23;
2769 if ((opcode
& (1 << 11)) == 0)
2771 if ((opcode
& (1 << 13)) == 0)
2774 if (opcode
& (1 << 11))
2776 if (opcode
& (1 << 13))
2784 address
+= offset
<< 1;
2786 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2787 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2788 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2789 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2790 (opcode
& (1 << 14)) ? "BL" : "B.W",
2796 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2797 arm_instruction_t
*instruction
, char *cp
)
2800 unsigned b17
= 1 << 17;
2801 unsigned b18
= 1 << 18;
2802 unsigned cond
= (opcode
>> 22) & 0x0f;
2804 offset
= opcode
& 0x7ff;
2805 offset
|= (opcode
& 0x003f0000) >> 5;
2806 if (opcode
& (1 << 26)) {
2807 offset
|= 0xffff << 19;
2808 if ((opcode
& (1 << 11)) == 0)
2810 if ((opcode
& (1 << 13)) == 0)
2813 if (opcode
& (1 << 11))
2815 if (opcode
& (1 << 13))
2822 address
+= offset
<< 1;
2824 instruction
->type
= ARM_B
;
2825 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2826 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2827 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2828 arm_condition_strings
[cond
],
2834 static const char *special_name(int number
)
2836 char *special
= "(RESERVED)";
2867 special
= "primask";
2870 special
= "basepri";
2873 special
= "basepri_max";
2876 special
= "faultmask";
2879 special
= "control";
2885 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2886 arm_instruction_t
*instruction
, char *cp
)
2888 const char *mnemonic
;
2890 if (opcode
& 0x0700) {
2891 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2892 strcpy(cp
, "UNDEFINED");
2896 if (opcode
& 0x00f0) {
2897 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2901 switch (opcode
& 0x0f) {
2906 mnemonic
= "YIELD.W";
2918 mnemonic
= "HINT.W (UNRECOGNIZED)";
2921 strcpy(cp
, mnemonic
);
2925 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2926 arm_instruction_t
*instruction
, char *cp
)
2928 const char *mnemonic
;
2930 switch ((opcode
>> 4) & 0x0f) {
2932 mnemonic
= "LEAVEX";
2935 mnemonic
= "ENTERX";
2950 return ERROR_INVALID_ARGUMENTS
;
2952 strcpy(cp
, mnemonic
);
2956 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2957 arm_instruction_t
*instruction
, char *cp
)
2959 /* permanently undefined */
2960 if ((opcode
& 0x07f07000) == 0x07f02000) {
2961 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2962 strcpy(cp
, "UNDEFINED");
2966 switch ((opcode
>> 12) & 0x5) {
2969 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2973 if (((opcode
>> 23) & 0x07) != 0x07)
2974 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2975 if (opcode
& (1 << 26))
2980 switch ((opcode
>> 20) & 0x7f) {
2983 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2984 (int) (opcode
>> 16) & 0x0f);
2987 return t2ev_hint(opcode
, address
, instruction
, cp
);
2989 return t2ev_misc(opcode
, address
, instruction
, cp
);
2991 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
2995 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
2996 special_name(opcode
& 0xff));
3001 return ERROR_INVALID_ARGUMENTS
;
3004 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3005 arm_instruction_t
*instruction
, char *cp
)
3007 char *mnemonic
= NULL
;
3008 int rn
= (opcode
>> 16) & 0xf;
3009 int rd
= (opcode
>> 8) & 0xf;
3010 unsigned immed
= opcode
& 0xff;
3016 /* ARMv7-M: A5.3.2 Modified immediate constants */
3017 func
= (opcode
>> 11) & 0x0e;
3020 if (opcode
& (1 << 26))
3023 /* "Modified" immediates */
3024 switch (func
>> 1) {
3031 immed
+= immed
<< 16;
3034 immed
+= immed
<< 8;
3035 immed
+= immed
<< 16;
3039 immed
= ror(immed
, func
);
3042 if (opcode
& (1 << 20))
3045 switch ((opcode
>> 21) & 0xf) {
3048 instruction
->type
= ARM_TST
;
3054 instruction
->type
= ARM_AND
;
3059 instruction
->type
= ARM_BIC
;
3064 instruction
->type
= ARM_MOV
;
3069 instruction
->type
= ARM_ORR
;
3075 instruction
->type
= ARM_MVN
;
3079 // instruction->type = ARM_ORN;
3085 instruction
->type
= ARM_TEQ
;
3091 instruction
->type
= ARM_EOR
;
3097 instruction
->type
= ARM_CMN
;
3103 instruction
->type
= ARM_ADD
;
3109 instruction
->type
= ARM_ADC
;
3114 instruction
->type
= ARM_SBC
;
3119 instruction
->type
= ARM_CMP
;
3125 instruction
->type
= ARM_SUB
;
3131 instruction
->type
= ARM_RSB
;
3136 return ERROR_INVALID_ARGUMENTS
;
3140 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3141 mnemonic
, suffix2
,rd
, immed
, immed
);
3143 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3144 mnemonic
, suffix
, suffix2
,
3145 rd
, rn
, immed
, immed
);
3150 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3151 arm_instruction_t
*instruction
, char *cp
)
3153 char *mnemonic
= NULL
;
3154 int rn
= (opcode
>> 16) & 0xf;
3155 int rd
= (opcode
>> 8) & 0xf;
3158 bool is_signed
= false;
3160 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3161 if (opcode
& (1 << 26))
3164 switch ((opcode
>> 20) & 0x1f) {
3173 immed
|= (opcode
>> 4) & 0xf000;
3174 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3182 /* move constant to top 16 bits of register */
3183 immed
|= (opcode
>> 4) & 0xf000;
3184 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3191 /* signed/unsigned saturated add */
3192 immed
= (opcode
>> 6) & 0x03;
3193 immed
|= (opcode
>> 10) & 0x1c;
3194 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3195 is_signed
? "S" : "U",
3196 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3197 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3198 immed
? immed
: 32);
3204 /* signed/unsigned bitfield extract */
3205 immed
= (opcode
>> 6) & 0x03;
3206 immed
|= (opcode
>> 10) & 0x1c;
3207 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3208 is_signed
? "S" : "U",
3210 (int) (opcode
& 0x1f) + 1);
3213 immed
= (opcode
>> 6) & 0x03;
3214 immed
|= (opcode
>> 10) & 0x1c;
3215 if (rn
== 0xf) /* bitfield clear */
3216 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3218 (int) (opcode
& 0x1f) + 1 - immed
);
3219 else /* bitfield insert */
3220 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3222 (int) (opcode
& 0x1f) + 1 - immed
);
3225 return ERROR_INVALID_ARGUMENTS
;
3228 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3229 rd
, rn
, immed
, immed
);
3233 address
= thumb_alignpc4(address
);
3238 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3239 * not hiding the pc-relative stuff will sometimes be useful.
3241 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3245 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3246 arm_instruction_t
*instruction
, char *cp
)
3248 unsigned op
= (opcode
>> 20) & 0xf;
3254 unsigned rn
= (opcode
>> 16) & 0x0f;
3255 unsigned rt
= (opcode
>> 12) & 0x0f;
3258 return ERROR_INVALID_ARGUMENTS
;
3260 if (opcode
& 0x0800)
3295 return ERROR_INVALID_ARGUMENTS
;
3298 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3299 size
, rt
, rn
, (int) opcode
& 0x0f,
3300 (int) (opcode
>> 4) & 0x03);
3304 immed
= opcode
& 0x0fff;
3305 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3306 size
, rt
, rn
, immed
, immed
);
3310 immed
= opcode
& 0x00ff;
3312 switch (opcode
& 0x700) {
3318 return ERROR_INVALID_ARGUMENTS
;
3321 /* two indexed modes will write back rn */
3322 if (opcode
& 0x100) {
3323 if (opcode
& 0x400) /* pre-indexed */
3325 else { /* post-indexed */
3331 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3332 size
, suffix
, rt
, rn
, p1
,
3333 (opcode
& 0x200) ? "" : "-",
3338 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3339 arm_instruction_t
*instruction
, char *cp
)
3341 int ra
= (opcode
>> 12) & 0xf;
3343 switch (opcode
& 0x007000f0) {
3346 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3347 (int) (opcode
>> 8) & 0xf,
3348 (int) (opcode
>> 16) & 0xf,
3349 (int) (opcode
>> 0) & 0xf);
3351 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3352 (int) (opcode
>> 8) & 0xf,
3353 (int) (opcode
>> 16) & 0xf,
3354 (int) (opcode
>> 0) & 0xf, ra
);
3357 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3358 (int) (opcode
>> 8) & 0xf,
3359 (int) (opcode
>> 16) & 0xf,
3360 (int) (opcode
>> 0) & 0xf, ra
);
3363 return ERROR_INVALID_ARGUMENTS
;
3368 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3369 arm_instruction_t
*instruction
, char *cp
)
3371 int op
= (opcode
>> 4) & 0xf;
3372 char *infix
= "MUL";
3374 op
+= (opcode
>> 16) & 0x70;
3382 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3383 (op
& 0x20) ? 'U' : 'S',
3385 (int) (opcode
>> 12) & 0xf,
3386 (int) (opcode
>> 8) & 0xf,
3387 (int) (opcode
>> 16) & 0xf,
3388 (int) (opcode
>> 0) & 0xf);
3392 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3393 (op
& 0x20) ? 'U' : 'S',
3394 (int) (opcode
>> 8) & 0xf,
3395 (int) (opcode
>> 16) & 0xf,
3396 (int) (opcode
>> 0) & 0xf);
3399 return ERROR_INVALID_ARGUMENTS
;
3405 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3406 arm_instruction_t
*instruction
, char *cp
)
3408 int rn
= (opcode
>> 16) & 0xf;
3409 int op
= (opcode
>> 22) & 0x6;
3410 int t
= (opcode
>> 21) & 1;
3411 unsigned registers
= opcode
& 0xffff;
3413 if (opcode
& (1 << 20))
3418 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3422 sprintf(cp
, "POP.W\t");
3424 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3428 sprintf(cp
, "PUSH.W\t");
3430 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3433 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3436 return ERROR_INVALID_ARGUMENTS
;
3441 for (t
= 0; registers
; t
++, registers
>>= 1) {
3442 if ((registers
& 1) == 0)
3445 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3454 /* load/store dual or exclusive, table branch */
3455 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3456 arm_instruction_t
*instruction
, char *cp
)
3458 unsigned op1op2
= (opcode
>> 20) & 0x3;
3459 unsigned op3
= (opcode
>> 4) & 0xf;
3461 unsigned rn
= (opcode
>> 16) & 0xf;
3462 unsigned rt
= (opcode
>> 12) & 0xf;
3463 unsigned rd
= (opcode
>> 8) & 0xf;
3464 unsigned imm
= opcode
& 0xff;
3468 op1op2
|= (opcode
>> 21) & 0xc;
3498 mnemonic
= "STREXB";
3501 mnemonic
= "STREXH";
3504 return ERROR_INVALID_ARGUMENTS
;
3512 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3515 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3518 mnemonic
= "LDREXB";
3521 mnemonic
= "LDREXH";
3524 return ERROR_INVALID_ARGUMENTS
;
3529 return ERROR_INVALID_ARGUMENTS
;
3534 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3535 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3537 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3538 mnemonic
, rd
, rt
, rn
);
3544 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3545 mnemonic
, rt
, rn
, imm
, imm
);
3547 sprintf(cp
, "%s\tr%u, [r%u]",
3552 /* two indexed modes will write back rn */
3553 if (opcode
& (1 << 21)) {
3554 if (opcode
& (1 << 24)) /* pre-indexed */
3556 else { /* post-indexed */
3563 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3564 mnemonic
, rt
, rd
, rn
, p1
,
3565 (opcode
& (1 << 23)) ? "" : "-",
3570 address
= thumb_alignpc4(address
);
3572 if (opcode
& (1 << 23))
3576 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3577 mnemonic
, rt
, rd
, address
);
3581 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3582 arm_instruction_t
*instruction
, char *cp
)
3584 int op
= (opcode
>> 21) & 0xf;
3585 int rd
= (opcode
>> 8) & 0xf;
3586 int rn
= (opcode
>> 16) & 0xf;
3587 int type
= (opcode
>> 4) & 0x3;
3588 int immed
= (opcode
>> 6) & 0x3;
3592 immed
|= (opcode
>> 10) & 0x1c;
3593 if (opcode
& (1 << 20))
3599 if (!(opcode
& (1 << 20)))
3600 return ERROR_INVALID_ARGUMENTS
;
3601 instruction
->type
= ARM_TST
;
3606 instruction
->type
= ARM_AND
;
3610 instruction
->type
= ARM_BIC
;
3615 instruction
->type
= ARM_MOV
;
3619 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3621 (int) (opcode
& 0xf));
3634 sprintf(cp
, "RRX%s\tr%d, r%d",
3636 (int) (opcode
& 0xf));
3644 instruction
->type
= ARM_ORR
;
3650 instruction
->type
= ARM_MVN
;
3655 // instruction->type = ARM_ORN;
3661 if (!(opcode
& (1 << 20)))
3662 return ERROR_INVALID_ARGUMENTS
;
3663 instruction
->type
= ARM_TEQ
;
3668 instruction
->type
= ARM_EOR
;
3673 if (!(opcode
& (1 << 20)))
3674 return ERROR_INVALID_ARGUMENTS
;
3675 instruction
->type
= ARM_CMN
;
3680 instruction
->type
= ARM_ADD
;
3684 instruction
->type
= ARM_ADC
;
3688 instruction
->type
= ARM_SBC
;
3693 if (!(opcode
& (1 << 21)))
3694 return ERROR_INVALID_ARGUMENTS
;
3695 instruction
->type
= ARM_CMP
;
3700 instruction
->type
= ARM_SUB
;
3704 instruction
->type
= ARM_RSB
;
3708 return ERROR_INVALID_ARGUMENTS
;
3711 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3712 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3735 strcpy(cp
, ", RRX");
3741 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3745 sprintf(cp
, "%s%s.W\tr%d, r%d",
3746 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3750 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3751 mnemonic
, suffix
, rd
,
3752 (int) (opcode
& 0xf), immed
? immed
: 32);
3756 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3757 arm_instruction_t
*instruction
, char *cp
)
3762 if (((opcode
>> 4) & 0xf) == 0) {
3763 switch ((opcode
>> 21) & 0x7) {
3777 return ERROR_INVALID_ARGUMENTS
;
3780 instruction
->type
= ARM_MOV
;
3781 if (opcode
& (1 << 20))
3783 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3785 (int) (opcode
>> 8) & 0xf,
3786 (int) (opcode
>> 16) & 0xf,
3787 (int) (opcode
>> 0) & 0xf);
3789 } else if (opcode
& (1 << 7)) {
3790 switch ((opcode
>> 20) & 0xf) {
3795 switch ((opcode
>> 4) & 0x3) {
3797 suffix
= ", ROR #8";
3800 suffix
= ", ROR #16";
3803 suffix
= ", ROR #24";
3806 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3807 (opcode
& (1 << 24)) ? 'U' : 'S',
3808 (opcode
& (1 << 26)) ? 'B' : 'H',
3809 (int) (opcode
>> 8) & 0xf,
3810 (int) (opcode
>> 0) & 0xf,
3817 if (opcode
& (1 << 6))
3818 return ERROR_INVALID_ARGUMENTS
;
3819 if (((opcode
>> 12) & 0xf) != 0xf)
3820 return ERROR_INVALID_ARGUMENTS
;
3821 if (!(opcode
& (1 << 20)))
3822 return ERROR_INVALID_ARGUMENTS
;
3824 switch (((opcode
>> 19) & 0x04)
3825 | ((opcode
>> 4) & 0x3)) {
3830 mnemonic
= "REV16.W";
3836 mnemonic
= "REVSH.W";
3842 return ERROR_INVALID_ARGUMENTS
;
3844 sprintf(cp
, "%s\tr%d, r%d",
3846 (int) (opcode
>> 8) & 0xf,
3847 (int) (opcode
>> 0) & 0xf);
3850 return ERROR_INVALID_ARGUMENTS
;
3857 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3858 arm_instruction_t
*instruction
, char *cp
)
3860 int rn
= (opcode
>> 16) & 0xf;
3863 instruction
->type
= ARM_LDR
;
3866 immed
= opcode
& 0x0fff;
3867 if ((opcode
& (1 << 23)) == 0)
3869 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3870 (int) (opcode
>> 12) & 0xf,
3871 thumb_alignpc4(address
) + immed
);
3875 if (opcode
& (1 << 23)) {
3876 immed
= opcode
& 0x0fff;
3877 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3878 (int) (opcode
>> 12) & 0xf,
3883 if (!(opcode
& (0x3f << 6))) {
3884 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3885 (int) (opcode
>> 12) & 0xf,
3887 (int) (opcode
>> 0) & 0xf,
3888 (int) (opcode
>> 4) & 0x3);
3893 if (((opcode
>> 8) & 0xf) == 0xe) {
3894 immed
= opcode
& 0x00ff;
3896 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3897 (int) (opcode
>> 12) & 0xf,
3902 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3903 char *p1
= "]", *p2
= "";
3905 if (!(opcode
& 0x0500))
3906 return ERROR_INVALID_ARGUMENTS
;
3908 immed
= opcode
& 0x00ff;
3910 /* two indexed modes will write back rn */
3911 if (opcode
& 0x100) {
3912 if (opcode
& 0x400) /* pre-indexed */
3914 else { /* post-indexed */
3920 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3921 (int) (opcode
>> 12) & 0xf,
3923 (opcode
& 0x200) ? "" : "-",
3928 return ERROR_INVALID_ARGUMENTS
;
3931 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3932 arm_instruction_t
*instruction
, char *cp
)
3934 int rn
= (opcode
>> 16) & 0xf;
3935 int rt
= (opcode
>> 12) & 0xf;
3936 int op2
= (opcode
>> 6) & 0x3f;
3938 char *p1
= "", *p2
= "]";
3941 switch ((opcode
>> 23) & 0x3) {
3943 if ((rn
& rt
) == 0xf) {
3945 immed
= opcode
& 0xfff;
3946 address
= thumb_alignpc4(address
);
3947 if (opcode
& (1 << 23))
3951 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
3955 if (rn
== 0x0f && rt
!= 0x0f) {
3957 immed
= opcode
& 0xfff;
3958 address
= thumb_alignpc4(address
);
3959 if (opcode
& (1 << 23))
3963 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
3969 if ((op2
& 0x3c) == 0x38) {
3970 immed
= opcode
& 0xff;
3971 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3972 rt
, rn
, immed
, immed
);
3975 if ((op2
& 0x3c) == 0x30) {
3977 immed
= opcode
& 0xff;
3980 p1
= (opcode
& (1 << 21)) ? "W" : "";
3981 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3982 p1
, rn
, immed
, immed
);
3987 immed
= opcode
& 0xff;
3988 if (!(opcode
& 0x200))
3991 /* two indexed modes will write back rn */
3992 if (opcode
& 0x100) {
3993 if (opcode
& 0x400) /* pre-indexed */
3995 else { /* post-indexed */
4001 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4002 mnemonic
, rt
, rn
, p1
,
4006 if ((op2
& 0x24) == 0x24) {
4008 goto ldrxb_immediate_t3
;
4011 int rm
= opcode
& 0xf;
4014 sprintf(cp
, "PLD\t");
4016 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4017 immed
= (opcode
>> 4) & 0x3;
4019 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4024 if ((rn
& rt
) == 0xf)
4027 immed
= opcode
& 0xfff;
4028 goto preload_immediate
;
4032 mnemonic
= "LDRB.W";
4033 immed
= opcode
& 0xfff;
4034 goto ldrxb_immediate_t2
;
4036 if ((rn
& rt
) == 0xf) {
4037 immed
= opcode
& 0xfff;
4038 address
= thumb_alignpc4(address
);
4039 if (opcode
& (1 << 23))
4043 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4046 if (rn
== 0xf && rt
!= 0xf) {
4048 immed
= opcode
& 0xfff;
4049 address
= thumb_alignpc4(address
);
4050 if (opcode
& (1 << 23))
4054 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4059 if ((op2
& 0x3c) == 0x38) {
4060 immed
= opcode
& 0xff;
4061 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4062 rt
, rn
, immed
, immed
);
4065 if ((op2
& 0x3c) == 0x30) {
4067 immed
= opcode
& 0xff;
4068 immed
= -immed
; // pli
4069 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4074 goto ldrxb_immediate_t3
;
4076 if ((op2
& 0x24) == 0x24) {
4078 goto ldrxb_immediate_t3
;
4081 int rm
= opcode
& 0xf;
4084 sprintf(cp
, "PLI\t");
4086 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4087 immed
= (opcode
>> 4) & 0x3;
4089 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4095 immed
= opcode
& 0xfff;
4096 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4102 immed
= opcode
& 0xfff;
4104 goto ldrxb_immediate_t2
;
4107 return ERROR_INVALID_ARGUMENTS
;
4110 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4111 arm_instruction_t
*instruction
, char *cp
)
4113 int rn
= (opcode
>> 16) & 0xf;
4114 int rt
= (opcode
>> 12) & 0xf;
4115 int op2
= (opcode
>> 6) & 0x3f;
4120 sprintf(cp
, "HINT (UNALLOCATED)");
4124 if (opcode
& (1 << 24))
4127 if ((opcode
& (1 << 23)) == 0) {
4130 immed
= opcode
& 0xfff;
4131 address
= thumb_alignpc4(address
);
4132 if (opcode
& (1 << 23))
4136 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4141 int rm
= opcode
& 0xf;
4143 immed
= (opcode
>> 4) & 0x3;
4144 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4145 sign
, rt
, rn
, rm
, immed
);
4148 if ((op2
& 0x3c) == 0x38) {
4149 immed
= opcode
& 0xff;
4150 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4151 sign
, rt
, rn
, immed
, immed
);
4154 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4155 char *p1
= "", *p2
= "]";
4157 immed
= opcode
& 0xff;
4158 if (!(opcode
& 0x200))
4161 /* two indexed modes will write back rn */
4162 if (opcode
& 0x100) {
4163 if (opcode
& 0x400) /* pre-indexed */
4165 else { /* post-indexed */
4170 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4171 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4178 immed
= opcode
& 0xfff;
4179 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4180 sign
, *sign
? "" : ".W",
4181 rt
, rn
, immed
, immed
);
4185 return ERROR_INVALID_ARGUMENTS
;
4189 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4190 * always set. That means eventual arm_simulate_step() support for Thumb2
4191 * will need work in this area.
4193 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
4200 /* clear low bit ... it's set on function pointers */
4203 /* clear fields, to avoid confusion */
4204 memset(instruction
, 0, sizeof(arm_instruction_t
));
4206 /* read first halfword, see if this is the only one */
4207 retval
= target_read_u16(target
, address
, &op
);
4208 if (retval
!= ERROR_OK
)
4211 switch (op
& 0xf800) {
4215 /* 32-bit instructions */
4216 instruction
->instruction_size
= 4;
4218 retval
= target_read_u16(target
, address
+ 2, &op
);
4219 if (retval
!= ERROR_OK
)
4222 instruction
->opcode
= opcode
;
4225 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4226 return thumb_evaluate_opcode(op
, address
, instruction
);
4229 snprintf(instruction
->text
, 128,
4230 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4232 cp
= strchr(instruction
->text
, 0);
4233 retval
= ERROR_FAIL
;
4235 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4236 if ((opcode
& 0x1a008000) == 0x10000000)
4237 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4239 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4240 else if ((opcode
& 0x1a008000) == 0x12000000)
4241 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4243 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4244 else if ((opcode
& 0x18008000) == 0x10008000)
4245 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4247 /* ARMv7-M: A5.3.5 Load/store multiple */
4248 else if ((opcode
& 0x1e400000) == 0x08000000)
4249 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4251 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4252 else if ((opcode
& 0x1e400000) == 0x08400000)
4253 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4255 /* ARMv7-M: A5.3.7 Load word */
4256 else if ((opcode
& 0x1f700000) == 0x18500000)
4257 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4259 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4260 else if ((opcode
& 0x1e700000) == 0x18300000)
4261 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4263 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4264 else if ((opcode
& 0x1e700000) == 0x18100000)
4265 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4267 /* ARMv7-M: A5.3.10 Store single data item */
4268 else if ((opcode
& 0x1f100000) == 0x18000000)
4269 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4271 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4272 else if ((opcode
& 0x1e000000) == 0x0a000000)
4273 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4275 /* ARMv7-M: A5.3.12 Data processing (register)
4276 * and A5.3.13 Miscellaneous operations
4278 else if ((opcode
& 0x1f000000) == 0x1a000000)
4279 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4281 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4282 else if ((opcode
& 0x1f800000) == 0x1b000000)
4283 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4285 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4286 else if ((opcode
& 0x1f800000) == 0x1b800000)
4287 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4289 if (retval
== ERROR_OK
)
4293 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4294 * instructions; not yet handled here.
4297 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4298 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4299 strcpy(cp
, "UNDEFINED OPCODE");
4303 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4306 strcpy(cp
, "(32-bit Thumb2 ...)");
4310 int arm_access_size(arm_instruction_t
*instruction
)
4312 if ((instruction
->type
== ARM_LDRB
)
4313 || (instruction
->type
== ARM_LDRBT
)
4314 || (instruction
->type
== ARM_LDRSB
)
4315 || (instruction
->type
== ARM_STRB
)
4316 || (instruction
->type
== ARM_STRBT
))
4320 else if ((instruction
->type
== ARM_LDRH
)
4321 || (instruction
->type
== ARM_LDRSH
)
4322 || (instruction
->type
== ARM_STRH
))
4326 else if ((instruction
->type
== ARM_LDR
)
4327 || (instruction
->type
== ARM_LDRT
)
4328 || (instruction
->type
== ARM_STR
)
4329 || (instruction
->type
== ARM_STRT
))
4333 else if ((instruction
->type
== ARM_LDRD
)
4334 || (instruction
->type
== ARM_STRD
))
4340 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction
->type
);
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)