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
& 0x0d70f000) == 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
;
1771 target_address
&= 0xfffffffc;
1775 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1776 mnemonic
= "prefix";
1777 target_address
= offset
<< 12;
1781 instruction
->type
= ARM_BL
;
1786 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1787 * these are effectively 32-bit instructions even in Thumb1.
1788 * Might be simplest to always use the Thumb2 decoder.
1791 snprintf(instruction
->text
, 128,
1792 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1793 address
, opcode
, mnemonic
, target_address
);
1795 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1796 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1801 static int evaluate_add_sub_thumb(uint16_t opcode
,
1802 uint32_t address
, arm_instruction_t
*instruction
)
1804 uint8_t Rd
= (opcode
>> 0) & 0x7;
1805 uint8_t Rn
= (opcode
>> 3) & 0x7;
1806 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1807 uint32_t opc
= opcode
& (1 << 9);
1808 uint32_t reg_imm
= opcode
& (1 << 10);
1813 instruction
->type
= ARM_SUB
;
1818 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1819 instruction
->type
= ARM_ADD
;
1823 instruction
->info
.data_proc
.Rd
= Rd
;
1824 instruction
->info
.data_proc
.Rn
= Rn
;
1825 instruction
->info
.data_proc
.S
= 1;
1829 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1830 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1831 snprintf(instruction
->text
, 128,
1832 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1833 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1837 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1838 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1839 snprintf(instruction
->text
, 128,
1840 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1841 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1847 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1848 uint32_t address
, arm_instruction_t
*instruction
)
1850 uint8_t Rd
= (opcode
>> 0) & 0x7;
1851 uint8_t Rm
= (opcode
>> 3) & 0x7;
1852 uint8_t imm
= (opcode
>> 6) & 0x1f;
1853 uint8_t opc
= (opcode
>> 11) & 0x3;
1854 char *mnemonic
= NULL
;
1859 instruction
->type
= ARM_MOV
;
1861 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1864 instruction
->type
= ARM_MOV
;
1866 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1869 instruction
->type
= ARM_MOV
;
1871 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1875 if ((imm
== 0) && (opc
!= 0))
1878 instruction
->info
.data_proc
.Rd
= Rd
;
1879 instruction
->info
.data_proc
.Rn
= -1;
1880 instruction
->info
.data_proc
.S
= 1;
1882 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1883 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1884 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1886 snprintf(instruction
->text
, 128,
1887 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1888 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1893 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1894 uint32_t address
, arm_instruction_t
*instruction
)
1896 uint8_t imm
= opcode
& 0xff;
1897 uint8_t Rd
= (opcode
>> 8) & 0x7;
1898 uint32_t opc
= (opcode
>> 11) & 0x3;
1899 char *mnemonic
= NULL
;
1901 instruction
->info
.data_proc
.Rd
= Rd
;
1902 instruction
->info
.data_proc
.Rn
= Rd
;
1903 instruction
->info
.data_proc
.S
= 1;
1904 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1905 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1910 instruction
->type
= ARM_MOV
;
1912 instruction
->info
.data_proc
.Rn
= -1;
1915 instruction
->type
= ARM_CMP
;
1917 instruction
->info
.data_proc
.Rd
= -1;
1920 instruction
->type
= ARM_ADD
;
1924 instruction
->type
= ARM_SUB
;
1929 snprintf(instruction
->text
, 128,
1930 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1931 address
, opcode
, mnemonic
, Rd
, imm
);
1936 static int evaluate_data_proc_thumb(uint16_t opcode
,
1937 uint32_t address
, arm_instruction_t
*instruction
)
1939 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1940 char *mnemonic
= NULL
;
1943 high_reg
= (opcode
& 0x0400) >> 10;
1944 op
= (opcode
& 0x03C0) >> 6;
1946 Rd
= (opcode
& 0x0007);
1947 Rm
= (opcode
& 0x0038) >> 3;
1948 H1
= (opcode
& 0x0080) >> 7;
1949 H2
= (opcode
& 0x0040) >> 6;
1951 instruction
->info
.data_proc
.Rd
= Rd
;
1952 instruction
->info
.data_proc
.Rn
= Rd
;
1953 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1954 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1955 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1966 instruction
->type
= ARM_ADD
;
1970 instruction
->type
= ARM_CMP
;
1974 instruction
->type
= ARM_MOV
;
1980 if ((opcode
& 0x7) == 0x0)
1982 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1985 instruction
->type
= ARM_BLX
;
1986 snprintf(instruction
->text
, 128,
1988 " 0x%4.4x \tBLX\tr%i",
1989 address
, opcode
, Rm
);
1993 instruction
->type
= ARM_BX
;
1994 snprintf(instruction
->text
, 128,
1996 " 0x%4.4x \tBX\tr%i",
1997 address
, opcode
, Rm
);
2002 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2003 snprintf(instruction
->text
, 128,
2006 "UNDEFINED INSTRUCTION",
2018 instruction
->type
= ARM_AND
;
2022 instruction
->type
= ARM_EOR
;
2026 instruction
->type
= ARM_MOV
;
2028 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2029 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2030 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2031 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2034 instruction
->type
= ARM_MOV
;
2036 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2037 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2038 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2039 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2042 instruction
->type
= ARM_MOV
;
2044 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2045 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2046 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2047 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2050 instruction
->type
= ARM_ADC
;
2054 instruction
->type
= ARM_SBC
;
2058 instruction
->type
= ARM_MOV
;
2060 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2061 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2062 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2063 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2066 instruction
->type
= ARM_TST
;
2070 instruction
->type
= ARM_RSB
;
2072 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2073 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2074 instruction
->info
.data_proc
.Rn
= Rm
;
2077 instruction
->type
= ARM_CMP
;
2081 instruction
->type
= ARM_CMN
;
2085 instruction
->type
= ARM_ORR
;
2089 instruction
->type
= ARM_MUL
;
2093 instruction
->type
= ARM_BIC
;
2097 instruction
->type
= ARM_MVN
;
2104 snprintf(instruction
->text
, 128,
2105 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2107 address
, opcode
, mnemonic
, Rd
, Rm
);
2109 snprintf(instruction
->text
, 128,
2110 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2111 address
, opcode
, mnemonic
, Rd
, Rm
);
2116 /* PC-relative data addressing is word-aligned even with Thumb */
2117 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2119 return (addr
+ 4) & ~3;
2122 static int evaluate_load_literal_thumb(uint16_t opcode
,
2123 uint32_t address
, arm_instruction_t
*instruction
)
2126 uint8_t Rd
= (opcode
>> 8) & 0x7;
2128 instruction
->type
= ARM_LDR
;
2129 immediate
= opcode
& 0x000000ff;
2132 instruction
->info
.load_store
.Rd
= Rd
;
2133 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2134 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2135 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2136 instruction
->info
.load_store
.offset
.offset
= immediate
;
2138 snprintf(instruction
->text
, 128,
2139 "0x%8.8" PRIx32
" 0x%4.4x \t"
2140 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2141 address
, opcode
, Rd
, immediate
,
2142 thumb_alignpc4(address
) + immediate
);
2147 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2148 uint32_t address
, arm_instruction_t
*instruction
)
2150 uint8_t Rd
= (opcode
>> 0) & 0x7;
2151 uint8_t Rn
= (opcode
>> 3) & 0x7;
2152 uint8_t Rm
= (opcode
>> 6) & 0x7;
2153 uint8_t opc
= (opcode
>> 9) & 0x7;
2154 char *mnemonic
= NULL
;
2159 instruction
->type
= ARM_STR
;
2163 instruction
->type
= ARM_STRH
;
2167 instruction
->type
= ARM_STRB
;
2171 instruction
->type
= ARM_LDRSB
;
2175 instruction
->type
= ARM_LDR
;
2179 instruction
->type
= ARM_LDRH
;
2183 instruction
->type
= ARM_LDRB
;
2187 instruction
->type
= ARM_LDRSH
;
2192 snprintf(instruction
->text
, 128,
2193 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2194 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2196 instruction
->info
.load_store
.Rd
= Rd
;
2197 instruction
->info
.load_store
.Rn
= Rn
;
2198 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2199 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2200 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2205 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2206 uint32_t address
, arm_instruction_t
*instruction
)
2208 uint32_t offset
= (opcode
>> 6) & 0x1f;
2209 uint8_t Rd
= (opcode
>> 0) & 0x7;
2210 uint8_t Rn
= (opcode
>> 3) & 0x7;
2211 uint32_t L
= opcode
& (1 << 11);
2212 uint32_t B
= opcode
& (1 << 12);
2219 instruction
->type
= ARM_LDR
;
2224 instruction
->type
= ARM_STR
;
2228 if ((opcode
&0xF000) == 0x8000)
2239 snprintf(instruction
->text
, 128,
2240 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2241 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2243 instruction
->info
.load_store
.Rd
= Rd
;
2244 instruction
->info
.load_store
.Rn
= Rn
;
2245 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2246 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2247 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2252 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2253 uint32_t address
, arm_instruction_t
*instruction
)
2255 uint32_t offset
= opcode
& 0xff;
2256 uint8_t Rd
= (opcode
>> 8) & 0x7;
2257 uint32_t L
= opcode
& (1 << 11);
2262 instruction
->type
= ARM_LDR
;
2267 instruction
->type
= ARM_STR
;
2271 snprintf(instruction
->text
, 128,
2272 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2273 address
, opcode
, mnemonic
, Rd
, offset
*4);
2275 instruction
->info
.load_store
.Rd
= Rd
;
2276 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2277 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2278 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2279 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2284 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2285 uint32_t address
, arm_instruction_t
*instruction
)
2287 uint32_t imm
= opcode
& 0xff;
2288 uint8_t Rd
= (opcode
>> 8) & 0x7;
2290 uint32_t SP
= opcode
& (1 << 11);
2293 instruction
->type
= ARM_ADD
;
2306 snprintf(instruction
->text
, 128,
2307 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2308 address
, opcode
, Rd
, reg_name
, imm
* 4);
2310 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2311 instruction
->info
.data_proc
.Rd
= Rd
;
2312 instruction
->info
.data_proc
.Rn
= Rn
;
2313 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2318 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2319 uint32_t address
, arm_instruction_t
*instruction
)
2321 uint32_t imm
= opcode
& 0x7f;
2322 uint8_t opc
= opcode
& (1 << 7);
2328 instruction
->type
= ARM_SUB
;
2333 instruction
->type
= ARM_ADD
;
2337 snprintf(instruction
->text
, 128,
2338 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2339 address
, opcode
, mnemonic
, imm
*4);
2341 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2342 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2343 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2344 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2349 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2350 uint32_t address
, arm_instruction_t
*instruction
)
2352 uint32_t imm
= opcode
& 0xff;
2354 instruction
->type
= ARM_BKPT
;
2356 snprintf(instruction
->text
, 128,
2357 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2358 address
, opcode
, imm
);
2363 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2364 uint32_t address
, arm_instruction_t
*instruction
)
2366 uint32_t reg_list
= opcode
& 0xff;
2367 uint32_t L
= opcode
& (1 << 11);
2368 uint32_t R
= opcode
& (1 << 8);
2369 uint8_t Rn
= (opcode
>> 8) & 7;
2370 uint8_t addr_mode
= 0 /* IA */;
2374 char ptr_name
[7] = "";
2377 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2378 * The STMIA and LDMIA opcodes are used for other instructions.
2381 if ((opcode
& 0xf000) == 0xc000)
2382 { /* generic load/store multiple */
2387 instruction
->type
= ARM_LDM
;
2389 if (opcode
& (1 << Rn
))
2394 instruction
->type
= ARM_STM
;
2397 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2404 instruction
->type
= ARM_LDM
;
2407 reg_list
|= (1 << 15) /*PC*/;
2411 instruction
->type
= ARM_STM
;
2413 addr_mode
= 3; /*DB*/
2415 reg_list
|= (1 << 14) /*LR*/;
2419 reg_names_p
= reg_names
;
2420 for (i
= 0; i
<= 15; i
++)
2422 if (reg_list
& (1 << i
))
2423 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2425 if (reg_names_p
> reg_names
)
2426 reg_names_p
[-2] = '\0';
2427 else /* invalid op : no registers */
2428 reg_names
[0] = '\0';
2430 snprintf(instruction
->text
, 128,
2431 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2432 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2434 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2435 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2436 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2441 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2442 uint32_t address
, arm_instruction_t
*instruction
)
2444 uint32_t offset
= opcode
& 0xff;
2445 uint8_t cond
= (opcode
>> 8) & 0xf;
2446 uint32_t target_address
;
2450 instruction
->type
= ARM_SWI
;
2451 snprintf(instruction
->text
, 128,
2452 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2453 address
, opcode
, offset
);
2456 else if (cond
== 0xe)
2458 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2459 snprintf(instruction
->text
, 128,
2460 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2465 /* sign extend 8-bit offset */
2466 if (offset
& 0x00000080)
2467 offset
= 0xffffff00 | offset
;
2469 target_address
= address
+ 4 + (offset
<< 1);
2471 snprintf(instruction
->text
, 128,
2472 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2474 arm_condition_strings
[cond
], target_address
);
2476 instruction
->type
= ARM_B
;
2477 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2478 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2483 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2484 arm_instruction_t
*instruction
)
2488 /* added in Thumb2 */
2489 offset
= (opcode
>> 3) & 0x1f;
2490 offset
|= (opcode
& 0x0200) >> 4;
2492 snprintf(instruction
->text
, 128,
2493 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2495 (opcode
& 0x0800) ? "N" : "",
2496 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2501 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2502 arm_instruction_t
*instruction
)
2504 /* added in ARMv6 */
2505 snprintf(instruction
->text
, 128,
2506 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2508 (opcode
& 0x0080) ? 'U' : 'S',
2509 (opcode
& 0x0040) ? 'B' : 'H',
2510 opcode
& 0x7, (opcode
>> 3) & 0x7);
2515 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2516 arm_instruction_t
*instruction
)
2518 /* added in ARMv6 */
2519 if ((opcode
& 0x0ff0) == 0x0650)
2520 snprintf(instruction
->text
, 128,
2521 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2523 (opcode
& 0x80) ? "BE" : "LE");
2524 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2525 snprintf(instruction
->text
, 128,
2526 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2528 (opcode
& 0x0010) ? 'D' : 'E',
2529 (opcode
& 0x0004) ? "A" : "",
2530 (opcode
& 0x0002) ? "I" : "",
2531 (opcode
& 0x0001) ? "F" : "");
2536 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2537 arm_instruction_t
*instruction
)
2541 /* added in ARMv6 */
2542 switch ((opcode
>> 6) & 3) {
2553 snprintf(instruction
->text
, 128,
2554 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2555 address
, opcode
, suffix
,
2556 opcode
& 0x7, (opcode
>> 3) & 0x7);
2561 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2562 arm_instruction_t
*instruction
)
2566 switch ((opcode
>> 4) & 0x0f) {
2583 hint
= "HINT (UNRECOGNIZED)";
2587 snprintf(instruction
->text
, 128,
2588 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2589 address
, opcode
, hint
);
2594 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2595 arm_instruction_t
*instruction
)
2597 unsigned cond
= (opcode
>> 4) & 0x0f;
2598 char *x
= "", *y
= "", *z
= "";
2601 z
= (opcode
& 0x02) ? "T" : "E";
2603 y
= (opcode
& 0x04) ? "T" : "E";
2605 x
= (opcode
& 0x08) ? "T" : "E";
2607 snprintf(instruction
->text
, 128,
2608 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2610 x
, y
, z
, arm_condition_strings
[cond
]);
2612 /* NOTE: strictly speaking, the next 1-4 instructions should
2613 * now be displayed with the relevant conditional suffix...
2619 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2621 /* clear fields, to avoid confusion */
2622 memset(instruction
, 0, sizeof(arm_instruction_t
));
2623 instruction
->opcode
= opcode
;
2624 instruction
->instruction_size
= 2;
2626 if ((opcode
& 0xe000) == 0x0000)
2628 /* add/substract register or immediate */
2629 if ((opcode
& 0x1800) == 0x1800)
2630 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2631 /* shift by immediate */
2633 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2636 /* Add/substract/compare/move immediate */
2637 if ((opcode
& 0xe000) == 0x2000)
2639 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2642 /* Data processing instructions */
2643 if ((opcode
& 0xf800) == 0x4000)
2645 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2648 /* Load from literal pool */
2649 if ((opcode
& 0xf800) == 0x4800)
2651 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2654 /* Load/Store register offset */
2655 if ((opcode
& 0xf000) == 0x5000)
2657 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2660 /* Load/Store immediate offset */
2661 if (((opcode
& 0xe000) == 0x6000)
2662 ||((opcode
& 0xf000) == 0x8000))
2664 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2667 /* Load/Store from/to stack */
2668 if ((opcode
& 0xf000) == 0x9000)
2670 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2674 if ((opcode
& 0xf000) == 0xa000)
2676 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2680 if ((opcode
& 0xf000) == 0xb000)
2682 switch ((opcode
>> 8) & 0x0f) {
2684 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2689 return evaluate_cb_thumb(opcode
, address
, instruction
);
2691 return evaluate_extend_thumb(opcode
, address
, instruction
);
2696 return evaluate_load_store_multiple_thumb(opcode
, address
,
2699 return evaluate_cps_thumb(opcode
, address
, instruction
);
2701 if ((opcode
& 0x00c0) == 0x0080)
2703 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2705 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2707 if (opcode
& 0x000f)
2708 return evaluate_ifthen_thumb(opcode
, address
,
2711 return evaluate_hint_thumb(opcode
, address
,
2715 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2716 snprintf(instruction
->text
, 128,
2717 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2722 /* Load/Store multiple */
2723 if ((opcode
& 0xf000) == 0xc000)
2725 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2728 /* Conditional branch + SWI */
2729 if ((opcode
& 0xf000) == 0xd000)
2731 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2734 if ((opcode
& 0xe000) == 0xe000)
2736 /* Undefined instructions */
2737 if ((opcode
& 0xf801) == 0xe801)
2739 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2740 snprintf(instruction
->text
, 128,
2741 "0x%8.8" PRIx32
" 0x%8.8x\t"
2742 "UNDEFINED INSTRUCTION",
2747 { /* Branch to offset */
2748 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2752 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2756 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2757 arm_instruction_t
*instruction
, char *cp
)
2760 unsigned b21
= 1 << 21;
2761 unsigned b22
= 1 << 22;
2763 /* instead of combining two smaller 16-bit branch instructions,
2764 * Thumb2 uses only one larger 32-bit instruction.
2766 offset
= opcode
& 0x7ff;
2767 offset
|= (opcode
& 0x03ff0000) >> 5;
2768 if (opcode
& (1 << 26)) {
2769 offset
|= 0xff << 23;
2770 if ((opcode
& (1 << 11)) == 0)
2772 if ((opcode
& (1 << 13)) == 0)
2775 if (opcode
& (1 << 11))
2777 if (opcode
& (1 << 13))
2785 address
+= offset
<< 1;
2787 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2788 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2789 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2790 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2791 (opcode
& (1 << 14)) ? "BL" : "B.W",
2797 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2798 arm_instruction_t
*instruction
, char *cp
)
2801 unsigned b17
= 1 << 17;
2802 unsigned b18
= 1 << 18;
2803 unsigned cond
= (opcode
>> 22) & 0x0f;
2805 offset
= opcode
& 0x7ff;
2806 offset
|= (opcode
& 0x003f0000) >> 5;
2807 if (opcode
& (1 << 26)) {
2808 offset
|= 0xffff << 19;
2809 if ((opcode
& (1 << 11)) == 0)
2811 if ((opcode
& (1 << 13)) == 0)
2814 if (opcode
& (1 << 11))
2816 if (opcode
& (1 << 13))
2823 address
+= offset
<< 1;
2825 instruction
->type
= ARM_B
;
2826 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2827 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2828 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2829 arm_condition_strings
[cond
],
2835 static const char *special_name(int number
)
2837 char *special
= "(RESERVED)";
2868 special
= "primask";
2871 special
= "basepri";
2874 special
= "basepri_max";
2877 special
= "faultmask";
2880 special
= "control";
2886 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2887 arm_instruction_t
*instruction
, char *cp
)
2889 const char *mnemonic
;
2891 if (opcode
& 0x0700) {
2892 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2893 strcpy(cp
, "UNDEFINED");
2897 if (opcode
& 0x00f0) {
2898 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2902 switch (opcode
& 0x0f) {
2907 mnemonic
= "YIELD.W";
2919 mnemonic
= "HINT.W (UNRECOGNIZED)";
2922 strcpy(cp
, mnemonic
);
2926 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2927 arm_instruction_t
*instruction
, char *cp
)
2929 const char *mnemonic
;
2931 switch ((opcode
>> 4) & 0x0f) {
2933 mnemonic
= "LEAVEX";
2936 mnemonic
= "ENTERX";
2951 return ERROR_INVALID_ARGUMENTS
;
2953 strcpy(cp
, mnemonic
);
2957 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2958 arm_instruction_t
*instruction
, char *cp
)
2960 /* permanently undefined */
2961 if ((opcode
& 0x07f07000) == 0x07f02000) {
2962 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2963 strcpy(cp
, "UNDEFINED");
2967 switch ((opcode
>> 12) & 0x5) {
2970 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2974 if (((opcode
>> 23) & 0x07) != 0x07)
2975 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2976 if (opcode
& (1 << 26))
2981 switch ((opcode
>> 20) & 0x7f) {
2984 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2985 (int) (opcode
>> 16) & 0x0f);
2988 return t2ev_hint(opcode
, address
, instruction
, cp
);
2990 return t2ev_misc(opcode
, address
, instruction
, cp
);
2992 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
2996 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
2997 special_name(opcode
& 0xff));
3002 return ERROR_INVALID_ARGUMENTS
;
3005 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3006 arm_instruction_t
*instruction
, char *cp
)
3008 char *mnemonic
= NULL
;
3009 int rn
= (opcode
>> 16) & 0xf;
3010 int rd
= (opcode
>> 8) & 0xf;
3011 unsigned immed
= opcode
& 0xff;
3017 /* ARMv7-M: A5.3.2 Modified immediate constants */
3018 func
= (opcode
>> 11) & 0x0e;
3021 if (opcode
& (1 << 26))
3024 /* "Modified" immediates */
3025 switch (func
>> 1) {
3032 immed
+= immed
<< 16;
3035 immed
+= immed
<< 8;
3036 immed
+= immed
<< 16;
3040 immed
= ror(immed
, func
);
3043 if (opcode
& (1 << 20))
3046 switch ((opcode
>> 21) & 0xf) {
3049 instruction
->type
= ARM_TST
;
3055 instruction
->type
= ARM_AND
;
3060 instruction
->type
= ARM_BIC
;
3065 instruction
->type
= ARM_MOV
;
3070 instruction
->type
= ARM_ORR
;
3076 instruction
->type
= ARM_MVN
;
3080 // instruction->type = ARM_ORN;
3086 instruction
->type
= ARM_TEQ
;
3092 instruction
->type
= ARM_EOR
;
3098 instruction
->type
= ARM_CMN
;
3104 instruction
->type
= ARM_ADD
;
3110 instruction
->type
= ARM_ADC
;
3115 instruction
->type
= ARM_SBC
;
3120 instruction
->type
= ARM_CMP
;
3126 instruction
->type
= ARM_SUB
;
3132 instruction
->type
= ARM_RSB
;
3137 return ERROR_INVALID_ARGUMENTS
;
3141 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3142 mnemonic
, suffix2
,rd
, immed
, immed
);
3144 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3145 mnemonic
, suffix
, suffix2
,
3146 rd
, rn
, immed
, immed
);
3151 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3152 arm_instruction_t
*instruction
, char *cp
)
3154 char *mnemonic
= NULL
;
3155 int rn
= (opcode
>> 16) & 0xf;
3156 int rd
= (opcode
>> 8) & 0xf;
3159 bool is_signed
= false;
3161 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3162 if (opcode
& (1 << 26))
3165 switch ((opcode
>> 20) & 0x1f) {
3174 immed
|= (opcode
>> 4) & 0xf000;
3175 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3183 /* move constant to top 16 bits of register */
3184 immed
|= (opcode
>> 4) & 0xf000;
3185 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3192 /* signed/unsigned saturated add */
3193 immed
= (opcode
>> 6) & 0x03;
3194 immed
|= (opcode
>> 10) & 0x1c;
3195 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3196 is_signed
? "S" : "U",
3197 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3198 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3199 immed
? immed
: 32);
3205 /* signed/unsigned bitfield extract */
3206 immed
= (opcode
>> 6) & 0x03;
3207 immed
|= (opcode
>> 10) & 0x1c;
3208 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3209 is_signed
? "S" : "U",
3211 (int) (opcode
& 0x1f) + 1);
3214 immed
= (opcode
>> 6) & 0x03;
3215 immed
|= (opcode
>> 10) & 0x1c;
3216 if (rn
== 0xf) /* bitfield clear */
3217 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3219 (int) (opcode
& 0x1f) + 1 - immed
);
3220 else /* bitfield insert */
3221 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3223 (int) (opcode
& 0x1f) + 1 - immed
);
3226 return ERROR_INVALID_ARGUMENTS
;
3229 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3230 rd
, rn
, immed
, immed
);
3234 address
= thumb_alignpc4(address
);
3239 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3240 * not hiding the pc-relative stuff will sometimes be useful.
3242 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3246 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3247 arm_instruction_t
*instruction
, char *cp
)
3249 unsigned op
= (opcode
>> 20) & 0xf;
3255 unsigned rn
= (opcode
>> 16) & 0x0f;
3256 unsigned rt
= (opcode
>> 12) & 0x0f;
3259 return ERROR_INVALID_ARGUMENTS
;
3261 if (opcode
& 0x0800)
3296 return ERROR_INVALID_ARGUMENTS
;
3299 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3300 size
, rt
, rn
, (int) opcode
& 0x0f,
3301 (int) (opcode
>> 4) & 0x03);
3305 immed
= opcode
& 0x0fff;
3306 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3307 size
, rt
, rn
, immed
, immed
);
3311 immed
= opcode
& 0x00ff;
3313 switch (opcode
& 0x700) {
3319 return ERROR_INVALID_ARGUMENTS
;
3322 /* two indexed modes will write back rn */
3323 if (opcode
& 0x100) {
3324 if (opcode
& 0x400) /* pre-indexed */
3326 else { /* post-indexed */
3332 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3333 size
, suffix
, rt
, rn
, p1
,
3334 (opcode
& 0x200) ? "" : "-",
3339 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3340 arm_instruction_t
*instruction
, char *cp
)
3342 int ra
= (opcode
>> 12) & 0xf;
3344 switch (opcode
& 0x007000f0) {
3347 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3348 (int) (opcode
>> 8) & 0xf,
3349 (int) (opcode
>> 16) & 0xf,
3350 (int) (opcode
>> 0) & 0xf);
3352 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3353 (int) (opcode
>> 8) & 0xf,
3354 (int) (opcode
>> 16) & 0xf,
3355 (int) (opcode
>> 0) & 0xf, ra
);
3358 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3359 (int) (opcode
>> 8) & 0xf,
3360 (int) (opcode
>> 16) & 0xf,
3361 (int) (opcode
>> 0) & 0xf, ra
);
3364 return ERROR_INVALID_ARGUMENTS
;
3369 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3370 arm_instruction_t
*instruction
, char *cp
)
3372 int op
= (opcode
>> 4) & 0xf;
3373 char *infix
= "MUL";
3375 op
+= (opcode
>> 16) & 0x70;
3383 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3384 (op
& 0x20) ? 'U' : 'S',
3386 (int) (opcode
>> 12) & 0xf,
3387 (int) (opcode
>> 8) & 0xf,
3388 (int) (opcode
>> 16) & 0xf,
3389 (int) (opcode
>> 0) & 0xf);
3393 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3394 (op
& 0x20) ? 'U' : 'S',
3395 (int) (opcode
>> 8) & 0xf,
3396 (int) (opcode
>> 16) & 0xf,
3397 (int) (opcode
>> 0) & 0xf);
3400 return ERROR_INVALID_ARGUMENTS
;
3406 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3407 arm_instruction_t
*instruction
, char *cp
)
3409 int rn
= (opcode
>> 16) & 0xf;
3410 int op
= (opcode
>> 22) & 0x6;
3411 int t
= (opcode
>> 21) & 1;
3412 unsigned registers
= opcode
& 0xffff;
3414 if (opcode
& (1 << 20))
3419 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3423 sprintf(cp
, "POP.W\t");
3425 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3429 sprintf(cp
, "PUSH.W\t");
3431 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3434 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3437 return ERROR_INVALID_ARGUMENTS
;
3442 for (t
= 0; registers
; t
++, registers
>>= 1) {
3443 if ((registers
& 1) == 0)
3446 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3455 /* load/store dual or exclusive, table branch */
3456 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3457 arm_instruction_t
*instruction
, char *cp
)
3459 unsigned op1op2
= (opcode
>> 20) & 0x3;
3460 unsigned op3
= (opcode
>> 4) & 0xf;
3462 unsigned rn
= (opcode
>> 16) & 0xf;
3463 unsigned rt
= (opcode
>> 12) & 0xf;
3464 unsigned rd
= (opcode
>> 8) & 0xf;
3465 unsigned imm
= opcode
& 0xff;
3469 op1op2
|= (opcode
>> 21) & 0xc;
3499 mnemonic
= "STREXB";
3502 mnemonic
= "STREXH";
3505 return ERROR_INVALID_ARGUMENTS
;
3513 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3516 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3519 mnemonic
= "LDREXB";
3522 mnemonic
= "LDREXH";
3525 return ERROR_INVALID_ARGUMENTS
;
3530 return ERROR_INVALID_ARGUMENTS
;
3535 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3536 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3538 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3539 mnemonic
, rd
, rt
, rn
);
3545 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3546 mnemonic
, rt
, rn
, imm
, imm
);
3548 sprintf(cp
, "%s\tr%u, [r%u]",
3553 /* two indexed modes will write back rn */
3554 if (opcode
& (1 << 21)) {
3555 if (opcode
& (1 << 24)) /* pre-indexed */
3557 else { /* post-indexed */
3564 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3565 mnemonic
, rt
, rd
, rn
, p1
,
3566 (opcode
& (1 << 23)) ? "" : "-",
3571 address
= thumb_alignpc4(address
);
3573 if (opcode
& (1 << 23))
3577 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3578 mnemonic
, rt
, rd
, address
);
3582 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3583 arm_instruction_t
*instruction
, char *cp
)
3585 int op
= (opcode
>> 21) & 0xf;
3586 int rd
= (opcode
>> 8) & 0xf;
3587 int rn
= (opcode
>> 16) & 0xf;
3588 int type
= (opcode
>> 4) & 0x3;
3589 int immed
= (opcode
>> 6) & 0x3;
3593 immed
|= (opcode
>> 10) & 0x1c;
3594 if (opcode
& (1 << 20))
3600 if (!(opcode
& (1 << 20)))
3601 return ERROR_INVALID_ARGUMENTS
;
3602 instruction
->type
= ARM_TST
;
3607 instruction
->type
= ARM_AND
;
3611 instruction
->type
= ARM_BIC
;
3616 instruction
->type
= ARM_MOV
;
3620 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3622 (int) (opcode
& 0xf));
3635 sprintf(cp
, "RRX%s\tr%d, r%d",
3637 (int) (opcode
& 0xf));
3645 instruction
->type
= ARM_ORR
;
3651 instruction
->type
= ARM_MVN
;
3656 // instruction->type = ARM_ORN;
3662 if (!(opcode
& (1 << 20)))
3663 return ERROR_INVALID_ARGUMENTS
;
3664 instruction
->type
= ARM_TEQ
;
3669 instruction
->type
= ARM_EOR
;
3674 if (!(opcode
& (1 << 20)))
3675 return ERROR_INVALID_ARGUMENTS
;
3676 instruction
->type
= ARM_CMN
;
3681 instruction
->type
= ARM_ADD
;
3685 instruction
->type
= ARM_ADC
;
3689 instruction
->type
= ARM_SBC
;
3694 if (!(opcode
& (1 << 21)))
3695 return ERROR_INVALID_ARGUMENTS
;
3696 instruction
->type
= ARM_CMP
;
3701 instruction
->type
= ARM_SUB
;
3705 instruction
->type
= ARM_RSB
;
3709 return ERROR_INVALID_ARGUMENTS
;
3712 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3713 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3736 strcpy(cp
, ", RRX");
3742 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3746 sprintf(cp
, "%s%s.W\tr%d, r%d",
3747 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3751 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3752 mnemonic
, suffix
, rd
,
3753 (int) (opcode
& 0xf), immed
? immed
: 32);
3757 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3758 arm_instruction_t
*instruction
, char *cp
)
3763 if (((opcode
>> 4) & 0xf) == 0) {
3764 switch ((opcode
>> 21) & 0x7) {
3778 return ERROR_INVALID_ARGUMENTS
;
3781 instruction
->type
= ARM_MOV
;
3782 if (opcode
& (1 << 20))
3784 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3786 (int) (opcode
>> 8) & 0xf,
3787 (int) (opcode
>> 16) & 0xf,
3788 (int) (opcode
>> 0) & 0xf);
3790 } else if (opcode
& (1 << 7)) {
3791 switch ((opcode
>> 20) & 0xf) {
3796 switch ((opcode
>> 4) & 0x3) {
3798 suffix
= ", ROR #8";
3801 suffix
= ", ROR #16";
3804 suffix
= ", ROR #24";
3807 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3808 (opcode
& (1 << 24)) ? 'U' : 'S',
3809 (opcode
& (1 << 26)) ? 'B' : 'H',
3810 (int) (opcode
>> 8) & 0xf,
3811 (int) (opcode
>> 0) & 0xf,
3818 if (opcode
& (1 << 6))
3819 return ERROR_INVALID_ARGUMENTS
;
3820 if (((opcode
>> 12) & 0xf) != 0xf)
3821 return ERROR_INVALID_ARGUMENTS
;
3822 if (!(opcode
& (1 << 20)))
3823 return ERROR_INVALID_ARGUMENTS
;
3825 switch (((opcode
>> 19) & 0x04)
3826 | ((opcode
>> 4) & 0x3)) {
3831 mnemonic
= "REV16.W";
3837 mnemonic
= "REVSH.W";
3843 return ERROR_INVALID_ARGUMENTS
;
3845 sprintf(cp
, "%s\tr%d, r%d",
3847 (int) (opcode
>> 8) & 0xf,
3848 (int) (opcode
>> 0) & 0xf);
3851 return ERROR_INVALID_ARGUMENTS
;
3858 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3859 arm_instruction_t
*instruction
, char *cp
)
3861 int rn
= (opcode
>> 16) & 0xf;
3864 instruction
->type
= ARM_LDR
;
3867 immed
= opcode
& 0x0fff;
3868 if ((opcode
& (1 << 23)) == 0)
3870 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3871 (int) (opcode
>> 12) & 0xf,
3872 thumb_alignpc4(address
) + immed
);
3876 if (opcode
& (1 << 23)) {
3877 immed
= opcode
& 0x0fff;
3878 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3879 (int) (opcode
>> 12) & 0xf,
3884 if (!(opcode
& (0x3f << 6))) {
3885 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3886 (int) (opcode
>> 12) & 0xf,
3888 (int) (opcode
>> 0) & 0xf,
3889 (int) (opcode
>> 4) & 0x3);
3894 if (((opcode
>> 8) & 0xf) == 0xe) {
3895 immed
= opcode
& 0x00ff;
3897 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3898 (int) (opcode
>> 12) & 0xf,
3903 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3904 char *p1
= "]", *p2
= "";
3906 if (!(opcode
& 0x0500))
3907 return ERROR_INVALID_ARGUMENTS
;
3909 immed
= opcode
& 0x00ff;
3911 /* two indexed modes will write back rn */
3912 if (opcode
& 0x100) {
3913 if (opcode
& 0x400) /* pre-indexed */
3915 else { /* post-indexed */
3921 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3922 (int) (opcode
>> 12) & 0xf,
3924 (opcode
& 0x200) ? "" : "-",
3929 return ERROR_INVALID_ARGUMENTS
;
3932 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3933 arm_instruction_t
*instruction
, char *cp
)
3935 int rn
= (opcode
>> 16) & 0xf;
3936 int rt
= (opcode
>> 12) & 0xf;
3937 int op2
= (opcode
>> 6) & 0x3f;
3939 char *p1
= "", *p2
= "]";
3942 switch ((opcode
>> 23) & 0x3) {
3944 if ((rn
& rt
) == 0xf) {
3946 immed
= opcode
& 0xfff;
3947 address
= thumb_alignpc4(address
);
3948 if (opcode
& (1 << 23))
3952 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
3956 if (rn
== 0x0f && rt
!= 0x0f) {
3958 immed
= opcode
& 0xfff;
3959 address
= thumb_alignpc4(address
);
3960 if (opcode
& (1 << 23))
3964 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
3970 if ((op2
& 0x3c) == 0x38) {
3971 immed
= opcode
& 0xff;
3972 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3973 rt
, rn
, immed
, immed
);
3976 if ((op2
& 0x3c) == 0x30) {
3978 immed
= opcode
& 0xff;
3981 p1
= (opcode
& (1 << 21)) ? "W" : "";
3982 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3983 p1
, rn
, immed
, immed
);
3988 immed
= opcode
& 0xff;
3989 if (!(opcode
& 0x200))
3992 /* two indexed modes will write back rn */
3993 if (opcode
& 0x100) {
3994 if (opcode
& 0x400) /* pre-indexed */
3996 else { /* post-indexed */
4002 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4003 mnemonic
, rt
, rn
, p1
,
4007 if ((op2
& 0x24) == 0x24) {
4009 goto ldrxb_immediate_t3
;
4012 int rm
= opcode
& 0xf;
4015 sprintf(cp
, "PLD\t");
4017 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4018 immed
= (opcode
>> 4) & 0x3;
4020 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4025 if ((rn
& rt
) == 0xf)
4028 immed
= opcode
& 0xfff;
4029 goto preload_immediate
;
4033 mnemonic
= "LDRB.W";
4034 immed
= opcode
& 0xfff;
4035 goto ldrxb_immediate_t2
;
4037 if ((rn
& rt
) == 0xf) {
4038 immed
= opcode
& 0xfff;
4039 address
= thumb_alignpc4(address
);
4040 if (opcode
& (1 << 23))
4044 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4047 if (rn
== 0xf && rt
!= 0xf) {
4049 immed
= opcode
& 0xfff;
4050 address
= thumb_alignpc4(address
);
4051 if (opcode
& (1 << 23))
4055 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4060 if ((op2
& 0x3c) == 0x38) {
4061 immed
= opcode
& 0xff;
4062 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4063 rt
, rn
, immed
, immed
);
4066 if ((op2
& 0x3c) == 0x30) {
4068 immed
= opcode
& 0xff;
4069 immed
= -immed
; // pli
4070 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4075 goto ldrxb_immediate_t3
;
4077 if ((op2
& 0x24) == 0x24) {
4079 goto ldrxb_immediate_t3
;
4082 int rm
= opcode
& 0xf;
4085 sprintf(cp
, "PLI\t");
4087 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4088 immed
= (opcode
>> 4) & 0x3;
4090 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4096 immed
= opcode
& 0xfff;
4097 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4103 immed
= opcode
& 0xfff;
4105 goto ldrxb_immediate_t2
;
4108 return ERROR_INVALID_ARGUMENTS
;
4111 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4112 arm_instruction_t
*instruction
, char *cp
)
4114 int rn
= (opcode
>> 16) & 0xf;
4115 int rt
= (opcode
>> 12) & 0xf;
4116 int op2
= (opcode
>> 6) & 0x3f;
4121 sprintf(cp
, "HINT (UNALLOCATED)");
4125 if (opcode
& (1 << 24))
4128 if ((opcode
& (1 << 23)) == 0) {
4131 immed
= opcode
& 0xfff;
4132 address
= thumb_alignpc4(address
);
4133 if (opcode
& (1 << 23))
4137 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4142 int rm
= opcode
& 0xf;
4144 immed
= (opcode
>> 4) & 0x3;
4145 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4146 sign
, rt
, rn
, rm
, immed
);
4149 if ((op2
& 0x3c) == 0x38) {
4150 immed
= opcode
& 0xff;
4151 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4152 sign
, rt
, rn
, immed
, immed
);
4155 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4156 char *p1
= "", *p2
= "]";
4158 immed
= opcode
& 0xff;
4159 if (!(opcode
& 0x200))
4162 /* two indexed modes will write back rn */
4163 if (opcode
& 0x100) {
4164 if (opcode
& 0x400) /* pre-indexed */
4166 else { /* post-indexed */
4171 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4172 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4179 immed
= opcode
& 0xfff;
4180 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4181 sign
, *sign
? "" : ".W",
4182 rt
, rn
, immed
, immed
);
4186 return ERROR_INVALID_ARGUMENTS
;
4190 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4191 * always set. That means eventual arm_simulate_step() support for Thumb2
4192 * will need work in this area.
4194 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
4201 /* clear low bit ... it's set on function pointers */
4204 /* clear fields, to avoid confusion */
4205 memset(instruction
, 0, sizeof(arm_instruction_t
));
4207 /* read first halfword, see if this is the only one */
4208 retval
= target_read_u16(target
, address
, &op
);
4209 if (retval
!= ERROR_OK
)
4212 switch (op
& 0xf800) {
4216 /* 32-bit instructions */
4217 instruction
->instruction_size
= 4;
4219 retval
= target_read_u16(target
, address
+ 2, &op
);
4220 if (retval
!= ERROR_OK
)
4223 instruction
->opcode
= opcode
;
4226 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4227 return thumb_evaluate_opcode(op
, address
, instruction
);
4230 snprintf(instruction
->text
, 128,
4231 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4233 cp
= strchr(instruction
->text
, 0);
4234 retval
= ERROR_FAIL
;
4236 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4237 if ((opcode
& 0x1a008000) == 0x10000000)
4238 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4240 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4241 else if ((opcode
& 0x1a008000) == 0x12000000)
4242 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4244 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4245 else if ((opcode
& 0x18008000) == 0x10008000)
4246 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4248 /* ARMv7-M: A5.3.5 Load/store multiple */
4249 else if ((opcode
& 0x1e400000) == 0x08000000)
4250 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4252 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4253 else if ((opcode
& 0x1e400000) == 0x08400000)
4254 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4256 /* ARMv7-M: A5.3.7 Load word */
4257 else if ((opcode
& 0x1f700000) == 0x18500000)
4258 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4260 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4261 else if ((opcode
& 0x1e700000) == 0x18300000)
4262 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4264 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4265 else if ((opcode
& 0x1e700000) == 0x18100000)
4266 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4268 /* ARMv7-M: A5.3.10 Store single data item */
4269 else if ((opcode
& 0x1f100000) == 0x18000000)
4270 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4272 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4273 else if ((opcode
& 0x1e000000) == 0x0a000000)
4274 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4276 /* ARMv7-M: A5.3.12 Data processing (register)
4277 * and A5.3.13 Miscellaneous operations
4279 else if ((opcode
& 0x1f000000) == 0x1a000000)
4280 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4282 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4283 else if ((opcode
& 0x1f800000) == 0x1b000000)
4284 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4286 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4287 else if ((opcode
& 0x1f800000) == 0x1b800000)
4288 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4290 if (retval
== ERROR_OK
)
4294 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4295 * instructions; not yet handled here.
4298 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4299 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4300 strcpy(cp
, "UNDEFINED OPCODE");
4304 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4307 strcpy(cp
, "(32-bit Thumb2 ...)");
4311 int arm_access_size(arm_instruction_t
*instruction
)
4313 if ((instruction
->type
== ARM_LDRB
)
4314 || (instruction
->type
== ARM_LDRBT
)
4315 || (instruction
->type
== ARM_LDRSB
)
4316 || (instruction
->type
== ARM_STRB
)
4317 || (instruction
->type
== ARM_STRBT
))
4321 else if ((instruction
->type
== ARM_LDRH
)
4322 || (instruction
->type
== ARM_LDRSH
)
4323 || (instruction
->type
== ARM_STRH
))
4327 else if ((instruction
->type
== ARM_LDR
)
4328 || (instruction
->type
== ARM_LDRT
)
4329 || (instruction
->type
== ARM_STR
)
4330 || (instruction
->type
== ARM_STRT
))
4334 else if ((instruction
->type
== ARM_LDRD
)
4335 || (instruction
->type
== ARM_STRD
))
4341 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)