1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 ***************************************************************************/
26 #include "arm_disassembler.h"
27 #include <helper/log.h>
30 * This disassembler supports two main functions for OpenOCD:
32 * - Various "disassemble" commands. OpenOCD can serve as a
33 * machine-language debugger, without help from GDB.
35 * - Single stepping. Not all ARM cores support hardware single
36 * stepping. To work without that support, the debugger must
37 * be able to decode instructions to find out where to put a
38 * "next instruction" breakpoint.
40 * In addition, interpretation of ETM trace data needs some of the
41 * decoding mechanisms.
43 * At this writing (September 2009) neither function is complete.
46 * * Old-style syntax (not UAL) is generally used
47 * * VFP instructions are not understood (ARMv5 and later)
48 * except as coprocessor 10/11 operations
49 * * Most ARM instructions through ARMv6 are decoded, but some
50 * of the post-ARMv4 opcodes may not be handled yet
51 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
52 * * NEON instructions are not understood (ARMv7-A)
54 * - Thumb/Thumb2 decoding
55 * * UAL syntax should be consistently used
56 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
57 * be handled properly. Accordingly, so should the subset
58 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
60 * * Conditional effects of Thumb2 "IT" (if-then) instructions
61 * are not handled: the affected instructions are not shown
62 * with their now-conditional suffixes.
63 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
64 * handled (minimally for coprocessor access).
65 * * SIMD instructions, and some other Thumb2 instructions
66 * from ARMv7-A, are not understood.
69 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
70 * * Opcodes changed by ThumbEE mode are not handled; these
71 * instructions wrongly decode as LDM and STM.
73 * - Jazelle decoding ... no support whatsoever for Jazelle mode
74 * or decoding. ARM encourages use of the more generic ThumbEE
75 * mode, instead of Jazelle mode, in current chips.
77 * - Single-step/emulation ... spotty support, which is only weakly
78 * tested. Thumb2 is not supported. (Arguably a full simulator
79 * is not needed to support just single stepping. Recognizing
80 * branch vs non-branch instructions suffices, except when the
81 * instruction faults and triggers a synchronous exception which
82 * can be intercepted using other means.)
84 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
85 * ARM v7-R edition" gives the most complete coverage of the various
86 * generations of ARM instructions. At this writing it is publicly
87 * accessible to anyone willing to create an account at the ARM
88 * web site; see http://www.arm.com/documentation/ for information.
90 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
91 * more details relevant to the Thumb2-only processors (such as
92 * the Cortex-M implementations).
95 /* textual represenation of the condition field
96 * ALways (default) is ommitted (empty string) */
97 static const char *arm_condition_strings
[] = {
98 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
101 /* make up for C's missing ROR */
102 static uint32_t ror(uint32_t value
, int places
)
104 return (value
>> places
) | (value
<< (32 - places
));
107 static int evaluate_unknown(uint32_t opcode
,
108 uint32_t address
, struct arm_instruction
*instruction
)
110 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
111 snprintf(instruction
->text
, 128,
112 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
113 "\tUNDEFINED INSTRUCTION", address
, opcode
);
117 static int evaluate_pld(uint32_t opcode
,
118 uint32_t address
, struct arm_instruction
*instruction
)
121 if ((opcode
& 0x0d70f000) == 0x0550f000) {
122 instruction
->type
= ARM_PLD
;
124 snprintf(instruction
->text
,
126 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...",
133 if ((opcode
& 0x07f000f0) == 0x05700040) {
134 instruction
->type
= ARM_DSB
;
137 switch (opcode
& 0x0000000f) {
166 snprintf(instruction
->text
,
168 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tDSB %s",
169 address
, opcode
, opt
);
174 if ((opcode
& 0x07f000f0) == 0x05700060) {
175 instruction
->type
= ARM_ISB
;
177 snprintf(instruction
->text
,
179 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tISB %s",
181 ((opcode
& 0x0000000f) == 0xf) ? "SY" : "UNK");
185 return evaluate_unknown(opcode
, address
, instruction
);
188 static int evaluate_srs(uint32_t opcode
,
189 uint32_t address
, struct arm_instruction
*instruction
)
191 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
192 const char *mode
= "";
194 switch ((opcode
>> 23) & 0x3) {
199 /* "IA" is default */
209 switch (opcode
& 0x0e500000) {
211 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
213 "\tSRS%s\tSP%s, #%d",
216 (unsigned)(opcode
& 0x1f));
219 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
224 (unsigned)((opcode
>> 16) & 0xf), wback
);
227 return evaluate_unknown(opcode
, address
, instruction
);
232 static int evaluate_swi(uint32_t opcode
,
233 uint32_t address
, struct arm_instruction
*instruction
)
235 instruction
->type
= ARM_SWI
;
237 snprintf(instruction
->text
, 128,
238 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
239 address
, opcode
, (opcode
& 0xffffff));
244 static int evaluate_blx_imm(uint32_t opcode
,
245 uint32_t address
, struct arm_instruction
*instruction
)
249 uint32_t target_address
;
251 instruction
->type
= ARM_BLX
;
252 immediate
= opcode
& 0x00ffffff;
254 /* sign extend 24-bit immediate */
255 if (immediate
& 0x00800000)
256 offset
= 0xff000000 | immediate
;
260 /* shift two bits left */
263 /* odd/event halfword */
264 if (opcode
& 0x01000000)
267 target_address
= address
+ 8 + offset
;
269 snprintf(instruction
->text
,
271 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"",
276 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
277 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
282 static int evaluate_b_bl(uint32_t opcode
,
283 uint32_t address
, struct arm_instruction
*instruction
)
288 uint32_t target_address
;
290 immediate
= opcode
& 0x00ffffff;
291 L
= (opcode
& 0x01000000) >> 24;
293 /* sign extend 24-bit immediate */
294 if (immediate
& 0x00800000)
295 offset
= 0xff000000 | immediate
;
299 /* shift two bits left */
302 target_address
= address
+ 8 + offset
;
305 instruction
->type
= ARM_BL
;
307 instruction
->type
= ARM_B
;
309 snprintf(instruction
->text
,
311 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
,
318 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
319 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
324 /* Coprocessor load/store and double register transfers
325 * both normal and extended instruction space (condition field b1111) */
326 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
327 uint32_t address
, struct arm_instruction
*instruction
)
329 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
332 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c500000)) {
333 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
336 cp_opcode
= (opcode
& 0xf0) >> 4;
337 Rd
= (opcode
& 0xf000) >> 12;
338 Rn
= (opcode
& 0xf0000) >> 16;
339 CRm
= (opcode
& 0xf);
342 if ((opcode
& 0x0ff00000) == 0x0c400000) {
343 instruction
->type
= ARM_MCRR
;
345 } else if ((opcode
& 0x0ff00000) == 0x0c500000) {
347 instruction
->type
= ARM_MRRC
;
350 LOG_ERROR("Unknown instruction");
354 snprintf(instruction
->text
, 128,
355 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
356 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
357 address
, opcode
, mnemonic
,
358 ((opcode
& 0xf0000000) == 0xf0000000)
359 ? "2" : COND(opcode
),
360 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
361 } else {/* LDC or STC */
362 uint8_t CRd
, Rn
, offset
;
365 char addressing_mode
[32];
367 CRd
= (opcode
& 0xf000) >> 12;
368 Rn
= (opcode
& 0xf0000) >> 16;
369 offset
= (opcode
& 0xff) << 2;
372 if (opcode
& 0x00100000) {
373 instruction
->type
= ARM_LDC
;
376 instruction
->type
= ARM_STC
;
380 U
= (opcode
& 0x00800000) >> 23;
382 /* addressing modes */
383 if ((opcode
& 0x01200000) == 0x01000000)/* offset */
384 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
385 Rn
, U
? "" : "-", offset
);
386 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
387 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
388 Rn
, U
? "" : "-", offset
);
389 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
390 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
391 Rn
, U
? "" : "-", offset
);
392 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
393 snprintf(addressing_mode
, 32, "[r%i], {%d}",
396 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
398 "\t%s%s%s p%i, c%i, %s",
399 address
, opcode
, mnemonic
,
400 ((opcode
& 0xf0000000) == 0xf0000000)
401 ? "2" : COND(opcode
),
402 (opcode
& (1 << 22)) ? "L" : "",
403 cp_num
, CRd
, addressing_mode
);
409 /* Coprocessor data processing instructions
410 * Coprocessor register transfer instructions
411 * both normal and extended instruction space (condition field b1111) */
412 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
413 uint32_t address
, struct arm_instruction
*instruction
)
417 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
419 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
420 cp_num
= (opcode
& 0xf00) >> 8;
421 CRd_Rd
= (opcode
& 0xf000) >> 12;
422 CRn
= (opcode
& 0xf0000) >> 16;
423 CRm
= (opcode
& 0xf);
424 opcode_2
= (opcode
& 0xe0) >> 5;
427 if (opcode
& 0x00000010) { /* bit 4 set -> MRC/MCR */
428 if (opcode
& 0x00100000) { /* bit 20 set -> MRC */
429 instruction
->type
= ARM_MRC
;
431 } else {/* bit 20 not set -> MCR */
432 instruction
->type
= ARM_MCR
;
436 opcode_1
= (opcode
& 0x00e00000) >> 21;
438 snprintf(instruction
->text
,
440 "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",
451 } else {/* bit 4 not set -> CDP */
452 instruction
->type
= ARM_CDP
;
455 opcode_1
= (opcode
& 0x00f00000) >> 20;
457 snprintf(instruction
->text
,
459 "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",
475 /* Load/store instructions */
476 static int evaluate_load_store(uint32_t opcode
,
477 uint32_t address
, struct arm_instruction
*instruction
)
479 uint8_t I
, P
, U
, B
, W
, L
;
481 char *operation
;/* "LDR" or "STR" */
482 char *suffix
; /* "", "B", "T", "BT" */
486 I
= (opcode
& 0x02000000) >> 25;
487 P
= (opcode
& 0x01000000) >> 24;
488 U
= (opcode
& 0x00800000) >> 23;
489 B
= (opcode
& 0x00400000) >> 22;
490 W
= (opcode
& 0x00200000) >> 21;
491 L
= (opcode
& 0x00100000) >> 20;
493 /* target register */
494 Rd
= (opcode
& 0xf000) >> 12;
497 Rn
= (opcode
& 0xf0000) >> 16;
499 instruction
->info
.load_store
.Rd
= Rd
;
500 instruction
->info
.load_store
.Rn
= Rn
;
501 instruction
->info
.load_store
.U
= U
;
503 /* determine operation */
509 /* determine instruction type and suffix */
511 if ((P
== 0) && (W
== 1)) {
513 instruction
->type
= ARM_LDRBT
;
515 instruction
->type
= ARM_STRBT
;
519 instruction
->type
= ARM_LDRB
;
521 instruction
->type
= ARM_STRB
;
525 if ((P
== 0) && (W
== 1)) {
527 instruction
->type
= ARM_LDRT
;
529 instruction
->type
= ARM_STRT
;
533 instruction
->type
= ARM_LDR
;
535 instruction
->type
= ARM_STR
;
540 if (!I
) { /* #+-<offset_12> */
541 uint32_t offset_12
= (opcode
& 0xfff);
543 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
545 snprintf(offset
, 32, "%s", "");
547 instruction
->info
.load_store
.offset_mode
= 0;
548 instruction
->info
.load_store
.offset
.offset
= offset_12
;
549 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
550 uint8_t shift_imm
, shift
;
553 shift_imm
= (opcode
& 0xf80) >> 7;
554 shift
= (opcode
& 0x60) >> 5;
557 /* LSR encodes a shift by 32 bit as 0x0 */
558 if ((shift
== 0x1) && (shift_imm
== 0x0))
561 /* ASR encodes a shift by 32 bit as 0x0 */
562 if ((shift
== 0x2) && (shift_imm
== 0x0))
565 /* ROR by 32 bit is actually a RRX */
566 if ((shift
== 0x3) && (shift_imm
== 0x0))
569 instruction
->info
.load_store
.offset_mode
= 1;
570 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
571 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
572 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
574 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
575 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
576 else { /* +-<Rm>, <Shift>, #<shift_imm> */
579 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
582 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
585 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
588 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
591 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
598 if (W
== 0) { /* offset */
599 snprintf(instruction
->text
,
601 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
611 instruction
->info
.load_store
.index_mode
= 0;
612 } else {/* pre-indexed */
613 snprintf(instruction
->text
,
615 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
625 instruction
->info
.load_store
.index_mode
= 1;
627 } else {/* post-indexed */
628 snprintf(instruction
->text
,
630 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
640 instruction
->info
.load_store
.index_mode
= 2;
646 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
648 unsigned rm
= (opcode
>> 0) & 0xf;
649 unsigned rd
= (opcode
>> 12) & 0xf;
650 unsigned rn
= (opcode
>> 16) & 0xf;
653 switch ((opcode
>> 24) & 0x3) {
658 sprintf(cp
, "UNDEFINED");
659 return ARM_UNDEFINED_INSTRUCTION
;
668 switch ((opcode
>> 10) & 0x3) {
684 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
685 (opcode
& (1 << 22)) ? 'U' : 'S',
690 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
691 (opcode
& (1 << 22)) ? 'U' : 'S',
698 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
704 switch ((opcode
>> 20) & 0x7) {
727 switch ((opcode
>> 5) & 0x7) {
756 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
757 (int) (opcode
>> 12) & 0xf,
758 (int) (opcode
>> 16) & 0xf,
759 (int) (opcode
>> 0) & 0xf);
763 /* these opcodes might be used someday */
764 sprintf(cp
, "UNDEFINED");
765 return ARM_UNDEFINED_INSTRUCTION
;
768 /* ARMv6 and later support "media" instructions (includes SIMD) */
769 static int evaluate_media(uint32_t opcode
, uint32_t address
,
770 struct arm_instruction
*instruction
)
772 char *cp
= instruction
->text
;
773 char *mnemonic
= NULL
;
776 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
780 /* parallel add/subtract */
781 if ((opcode
& 0x01800000) == 0x00000000) {
782 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
787 if ((opcode
& 0x01f00020) == 0x00800000) {
789 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
791 if (opcode
& (1 << 6)) {
800 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
802 (int) (opcode
>> 12) & 0xf,
803 (int) (opcode
>> 16) & 0xf,
804 (int) (opcode
>> 0) & 0xf,
810 if ((opcode
& 0x01a00020) == 0x00a00000) {
812 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
814 if (opcode
& (1 << 6)) {
821 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
822 (opcode
& (1 << 22)) ? 'U' : 'S',
824 (int) (opcode
>> 12) & 0xf,
825 (int) (opcode
>> 16) & 0x1f,
826 (int) (opcode
>> 0) & 0xf,
832 if ((opcode
& 0x018000f0) == 0x00800070) {
833 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
838 if ((opcode
& 0x01f00080) == 0x01000000) {
839 unsigned rn
= (opcode
>> 12) & 0xf;
842 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
843 (opcode
& (1 << 6)) ? 'S' : 'A',
844 (opcode
& (1 << 5)) ? "X" : "",
846 (int) (opcode
>> 16) & 0xf,
847 (int) (opcode
>> 0) & 0xf,
848 (int) (opcode
>> 8) & 0xf,
851 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
852 (opcode
& (1 << 6)) ? 'S' : 'A',
853 (opcode
& (1 << 5)) ? "X" : "",
855 (int) (opcode
>> 16) & 0xf,
856 (int) (opcode
>> 0) & 0xf,
857 (int) (opcode
>> 8) & 0xf);
860 if ((opcode
& 0x01f00000) == 0x01400000) {
861 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
862 (opcode
& (1 << 6)) ? 'S' : 'A',
863 (opcode
& (1 << 5)) ? "X" : "",
865 (int) (opcode
>> 12) & 0xf,
866 (int) (opcode
>> 16) & 0xf,
867 (int) (opcode
>> 0) & 0xf,
868 (int) (opcode
>> 8) & 0xf);
871 if ((opcode
& 0x01f00000) == 0x01500000) {
872 unsigned rn
= (opcode
>> 12) & 0xf;
874 switch (opcode
& 0xc0) {
886 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
887 (opcode
& (1 << 6)) ? 'S' : 'A',
888 (opcode
& (1 << 5)) ? "R" : "",
890 (int) (opcode
>> 16) & 0xf,
891 (int) (opcode
>> 0) & 0xf,
892 (int) (opcode
>> 8) & 0xf,
895 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
896 (opcode
& (1 << 5)) ? "R" : "",
898 (int) (opcode
>> 16) & 0xf,
899 (int) (opcode
>> 0) & 0xf,
900 (int) (opcode
>> 8) & 0xf);
904 /* simple matches against the remaining decode bits */
905 switch (opcode
& 0x01f000f0) {
908 /* parallel halfword saturate */
909 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
910 (opcode
& (1 << 22)) ? 'U' : 'S',
912 (int) (opcode
>> 12) & 0xf,
913 (int) (opcode
>> 16) & 0xf,
914 (int) (opcode
>> 0) & 0xf);
927 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
928 (int) (opcode
>> 12) & 0xf,
929 (int) (opcode
>> 16) & 0xf,
930 (int) (opcode
>> 0) & 0xf);
933 /* unsigned sum of absolute differences */
934 if (((opcode
>> 12) & 0xf) == 0xf)
935 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
936 (int) (opcode
>> 16) & 0xf,
937 (int) (opcode
>> 0) & 0xf,
938 (int) (opcode
>> 8) & 0xf);
940 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
941 (int) (opcode
>> 16) & 0xf,
942 (int) (opcode
>> 0) & 0xf,
943 (int) (opcode
>> 8) & 0xf,
944 (int) (opcode
>> 12) & 0xf);
948 unsigned rm
= (opcode
>> 0) & 0xf;
949 unsigned rd
= (opcode
>> 12) & 0xf;
951 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
956 /* these opcodes might be used someday */
957 sprintf(cp
, "UNDEFINED");
961 /* Miscellaneous load/store instructions */
962 static int evaluate_misc_load_store(uint32_t opcode
,
963 uint32_t address
, struct arm_instruction
*instruction
)
965 uint8_t P
, U
, I
, W
, L
, S
, H
;
967 char *operation
;/* "LDR" or "STR" */
968 char *suffix
; /* "H", "SB", "SH", "D" */
972 P
= (opcode
& 0x01000000) >> 24;
973 U
= (opcode
& 0x00800000) >> 23;
974 I
= (opcode
& 0x00400000) >> 22;
975 W
= (opcode
& 0x00200000) >> 21;
976 L
= (opcode
& 0x00100000) >> 20;
977 S
= (opcode
& 0x00000040) >> 6;
978 H
= (opcode
& 0x00000020) >> 5;
980 /* target register */
981 Rd
= (opcode
& 0xf000) >> 12;
984 Rn
= (opcode
& 0xf0000) >> 16;
986 instruction
->info
.load_store
.Rd
= Rd
;
987 instruction
->info
.load_store
.Rn
= Rn
;
988 instruction
->info
.load_store
.U
= U
;
990 /* determine instruction type and suffix */
995 instruction
->type
= ARM_LDRSH
;
999 instruction
->type
= ARM_LDRSB
;
1002 } else {/* there are no signed stores, so this is used to encode double-register
1007 instruction
->type
= ARM_STRD
;
1010 instruction
->type
= ARM_LDRD
;
1013 } else {/* unsigned */
1017 instruction
->type
= ARM_LDRH
;
1020 instruction
->type
= ARM_STRH
;
1024 if (I
) {/* Immediate offset/index (#+-<offset_8>)*/
1025 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
1026 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
1028 instruction
->info
.load_store
.offset_mode
= 0;
1029 instruction
->info
.load_store
.offset
.offset
= offset_8
;
1030 } else {/* Register offset/index (+-<Rm>) */
1032 Rm
= (opcode
& 0xf);
1033 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
1035 instruction
->info
.load_store
.offset_mode
= 1;
1036 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1037 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
1038 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
1042 if (W
== 0) { /* offset */
1043 snprintf(instruction
->text
,
1045 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
1055 instruction
->info
.load_store
.index_mode
= 0;
1056 } else {/* pre-indexed */
1057 snprintf(instruction
->text
,
1059 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1069 instruction
->info
.load_store
.index_mode
= 1;
1071 } else {/* post-indexed */
1072 snprintf(instruction
->text
,
1074 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1084 instruction
->info
.load_store
.index_mode
= 2;
1090 /* Load/store multiples instructions */
1091 static int evaluate_ldm_stm(uint32_t opcode
,
1092 uint32_t address
, struct arm_instruction
*instruction
)
1094 uint8_t P
, U
, S
, W
, L
, Rn
;
1095 uint32_t register_list
;
1096 char *addressing_mode
;
1103 P
= (opcode
& 0x01000000) >> 24;
1104 U
= (opcode
& 0x00800000) >> 23;
1105 S
= (opcode
& 0x00400000) >> 22;
1106 W
= (opcode
& 0x00200000) >> 21;
1107 L
= (opcode
& 0x00100000) >> 20;
1108 register_list
= (opcode
& 0xffff);
1109 Rn
= (opcode
& 0xf0000) >> 16;
1111 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1112 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1113 instruction
->info
.load_store_multiple
.S
= S
;
1114 instruction
->info
.load_store_multiple
.W
= W
;
1117 instruction
->type
= ARM_LDM
;
1120 instruction
->type
= ARM_STM
;
1126 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1127 addressing_mode
= "IB";
1129 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1130 addressing_mode
= "DB";
1134 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1135 /* "IA" is the default in UAL syntax */
1136 addressing_mode
= "";
1138 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1139 addressing_mode
= "DA";
1143 reg_list_p
= reg_list
;
1144 for (i
= 0; i
<= 15; i
++) {
1145 if ((register_list
>> i
) & 1) {
1148 reg_list_p
+= snprintf(reg_list_p
,
1149 (reg_list
+ 69 - reg_list_p
),
1153 reg_list_p
+= snprintf(reg_list_p
,
1154 (reg_list
+ 69 - reg_list_p
),
1160 snprintf(instruction
->text
, 128,
1161 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1162 "\t%s%s%s r%i%s, {%s}%s",
1164 mnemonic
, addressing_mode
, COND(opcode
),
1165 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1170 /* Multiplies, extra load/stores */
1171 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1172 uint32_t address
, struct arm_instruction
*instruction
)
1174 /* Multiply (accumulate) (long) and Swap/swap byte */
1175 if ((opcode
& 0x000000f0) == 0x00000090) {
1176 /* Multiply (accumulate) */
1177 if ((opcode
& 0x0f800000) == 0x00000000) {
1178 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1180 Rs
= (opcode
& 0xf00) >> 8;
1181 Rn
= (opcode
& 0xf000) >> 12;
1182 Rd
= (opcode
& 0xf0000) >> 16;
1183 S
= (opcode
& 0x00100000) >> 20;
1185 /* examine A bit (accumulate) */
1186 if (opcode
& 0x00200000) {
1187 instruction
->type
= ARM_MLA
;
1188 snprintf(instruction
->text
,
1190 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1200 instruction
->type
= ARM_MUL
;
1201 snprintf(instruction
->text
,
1203 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1216 /* Multiply (accumulate) long */
1217 if ((opcode
& 0x0f800000) == 0x00800000) {
1218 char *mnemonic
= NULL
;
1219 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1221 Rs
= (opcode
& 0xf00) >> 8;
1222 RdHi
= (opcode
& 0xf000) >> 12;
1223 RdLow
= (opcode
& 0xf0000) >> 16;
1224 S
= (opcode
& 0x00100000) >> 20;
1226 switch ((opcode
& 0x00600000) >> 21) {
1228 instruction
->type
= ARM_UMULL
;
1232 instruction
->type
= ARM_UMLAL
;
1236 instruction
->type
= ARM_SMULL
;
1240 instruction
->type
= ARM_SMLAL
;
1245 snprintf(instruction
->text
,
1247 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1261 /* Swap/swap byte */
1262 if ((opcode
& 0x0f800000) == 0x01000000) {
1265 Rd
= (opcode
& 0xf000) >> 12;
1266 Rn
= (opcode
& 0xf0000) >> 16;
1268 /* examine B flag */
1269 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1271 snprintf(instruction
->text
,
1273 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1276 (opcode
& 0x00400000) ? "SWPB" : "SWP",
1286 return evaluate_misc_load_store(opcode
, address
, instruction
);
1289 static int evaluate_mrs_msr(uint32_t opcode
,
1290 uint32_t address
, struct arm_instruction
*instruction
)
1292 int R
= (opcode
& 0x00400000) >> 22;
1293 char *PSR
= (R
) ? "SPSR" : "CPSR";
1295 /* Move register to status register (MSR) */
1296 if (opcode
& 0x00200000) {
1297 instruction
->type
= ARM_MSR
;
1299 /* immediate variant */
1300 if (opcode
& 0x02000000) {
1301 uint8_t immediate
= (opcode
& 0xff);
1302 uint8_t rotate
= (opcode
& 0xf00);
1304 snprintf(instruction
->text
,
1306 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1311 (opcode
& 0x10000) ? "c" : "",
1312 (opcode
& 0x20000) ? "x" : "",
1313 (opcode
& 0x40000) ? "s" : "",
1314 (opcode
& 0x80000) ? "f" : "",
1315 ror(immediate
, (rotate
* 2))
1317 } else {/* register variant */
1318 uint8_t Rm
= opcode
& 0xf;
1319 snprintf(instruction
->text
,
1321 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1326 (opcode
& 0x10000) ? "c" : "",
1327 (opcode
& 0x20000) ? "x" : "",
1328 (opcode
& 0x40000) ? "s" : "",
1329 (opcode
& 0x80000) ? "f" : "",
1334 } else {/* Move status register to register (MRS) */
1337 instruction
->type
= ARM_MRS
;
1338 Rd
= (opcode
& 0x0000f000) >> 12;
1340 snprintf(instruction
->text
,
1342 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1353 /* Miscellaneous instructions */
1354 static int evaluate_misc_instr(uint32_t opcode
,
1355 uint32_t address
, struct arm_instruction
*instruction
)
1358 if ((opcode
& 0x000000f0) == 0x00000000)
1359 evaluate_mrs_msr(opcode
, address
, instruction
);
1362 if ((opcode
& 0x006000f0) == 0x00200010) {
1364 instruction
->type
= ARM_BX
;
1367 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1368 address
, opcode
, COND(opcode
), Rm
);
1370 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1371 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1374 /* BXJ - "Jazelle" support (ARMv5-J) */
1375 if ((opcode
& 0x006000f0) == 0x00200020) {
1377 instruction
->type
= ARM_BX
;
1380 snprintf(instruction
->text
, 128,
1381 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1382 address
, opcode
, COND(opcode
), Rm
);
1384 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1385 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1389 if ((opcode
& 0x006000f0) == 0x00600010) {
1391 instruction
->type
= ARM_CLZ
;
1393 Rd
= (opcode
& 0xf000) >> 12;
1395 snprintf(instruction
->text
,
1397 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1406 if ((opcode
& 0x006000f0) == 0x00200030) {
1408 instruction
->type
= ARM_BLX
;
1411 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1412 address
, opcode
, COND(opcode
), Rm
);
1414 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1415 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1418 /* Enhanced DSP add/subtracts */
1419 if ((opcode
& 0x0000000f0) == 0x00000050) {
1421 char *mnemonic
= NULL
;
1423 Rd
= (opcode
& 0xf000) >> 12;
1424 Rn
= (opcode
& 0xf0000) >> 16;
1426 switch ((opcode
& 0x00600000) >> 21) {
1428 instruction
->type
= ARM_QADD
;
1432 instruction
->type
= ARM_QSUB
;
1436 instruction
->type
= ARM_QDADD
;
1440 instruction
->type
= ARM_QDSUB
;
1445 snprintf(instruction
->text
,
1447 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1457 /* exception return */
1458 if ((opcode
& 0x0000000f0) == 0x00000060) {
1459 if (((opcode
& 0x600000) >> 21) == 3)
1460 instruction
->type
= ARM_ERET
;
1461 snprintf(instruction
->text
,
1463 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tERET",
1468 /* exception generate instructions */
1469 if ((opcode
& 0x0000000f0) == 0x00000070) {
1470 uint32_t immediate
= 0;
1471 char *mnemonic
= NULL
;
1473 switch ((opcode
& 0x600000) >> 21) {
1475 instruction
->type
= ARM_BKPT
;
1477 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1480 instruction
->type
= ARM_HVC
;
1482 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1485 instruction
->type
= ARM_SMC
;
1487 immediate
= (opcode
& 0xf);
1491 snprintf(instruction
->text
,
1493 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s 0x%4.4" PRIx32
"",
1500 /* Enhanced DSP multiplies */
1501 if ((opcode
& 0x000000090) == 0x00000080) {
1502 int x
= (opcode
& 0x20) >> 5;
1503 int y
= (opcode
& 0x40) >> 6;
1506 if ((opcode
& 0x00600000) == 0x00000000) {
1507 uint8_t Rd
, Rm
, Rs
, Rn
;
1508 instruction
->type
= ARM_SMLAxy
;
1509 Rd
= (opcode
& 0xf0000) >> 16;
1510 Rm
= (opcode
& 0xf);
1511 Rs
= (opcode
& 0xf00) >> 8;
1512 Rn
= (opcode
& 0xf000) >> 12;
1514 snprintf(instruction
->text
,
1516 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1529 if ((opcode
& 0x00600000) == 0x00400000) {
1530 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1531 instruction
->type
= ARM_SMLAxy
;
1532 RdHi
= (opcode
& 0xf0000) >> 16;
1533 RdLow
= (opcode
& 0xf000) >> 12;
1534 Rm
= (opcode
& 0xf);
1535 Rs
= (opcode
& 0xf00) >> 8;
1537 snprintf(instruction
->text
,
1539 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1552 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0)) {
1553 uint8_t Rd
, Rm
, Rs
, Rn
;
1554 instruction
->type
= ARM_SMLAWy
;
1555 Rd
= (opcode
& 0xf0000) >> 16;
1556 Rm
= (opcode
& 0xf);
1557 Rs
= (opcode
& 0xf00) >> 8;
1558 Rn
= (opcode
& 0xf000) >> 12;
1560 snprintf(instruction
->text
,
1562 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1574 if ((opcode
& 0x00600000) == 0x00300000) {
1576 instruction
->type
= ARM_SMULxy
;
1577 Rd
= (opcode
& 0xf0000) >> 16;
1578 Rm
= (opcode
& 0xf);
1579 Rs
= (opcode
& 0xf00) >> 8;
1581 snprintf(instruction
->text
,
1583 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1595 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1)) {
1597 instruction
->type
= ARM_SMULWy
;
1598 Rd
= (opcode
& 0xf0000) >> 16;
1599 Rm
= (opcode
& 0xf);
1600 Rs
= (opcode
& 0xf00) >> 8;
1602 snprintf(instruction
->text
,
1604 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1618 static int evaluate_mov_imm(uint32_t opcode
,
1619 uint32_t address
, struct arm_instruction
*instruction
)
1625 Rd
= (opcode
& 0xf000) >> 12;
1626 T
= opcode
& 0x00400000;
1627 immediate
= (opcode
& 0xf0000) >> 4 | (opcode
& 0xfff);
1629 instruction
->type
= ARM_MOV
;
1630 instruction
->info
.data_proc
.Rd
= Rd
;
1632 snprintf(instruction
->text
,
1634 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMOV%s%s r%i, #0x%" PRIx16
,
1645 static int evaluate_data_proc(uint32_t opcode
,
1646 uint32_t address
, struct arm_instruction
*instruction
)
1648 uint8_t I
, op
, S
, Rn
, Rd
;
1649 char *mnemonic
= NULL
;
1650 char shifter_operand
[32];
1652 I
= (opcode
& 0x02000000) >> 25;
1653 op
= (opcode
& 0x01e00000) >> 21;
1654 S
= (opcode
& 0x00100000) >> 20;
1656 Rd
= (opcode
& 0xf000) >> 12;
1657 Rn
= (opcode
& 0xf0000) >> 16;
1659 instruction
->info
.data_proc
.Rd
= Rd
;
1660 instruction
->info
.data_proc
.Rn
= Rn
;
1661 instruction
->info
.data_proc
.S
= S
;
1665 instruction
->type
= ARM_AND
;
1669 instruction
->type
= ARM_EOR
;
1673 instruction
->type
= ARM_SUB
;
1677 instruction
->type
= ARM_RSB
;
1681 instruction
->type
= ARM_ADD
;
1685 instruction
->type
= ARM_ADC
;
1689 instruction
->type
= ARM_SBC
;
1693 instruction
->type
= ARM_RSC
;
1697 instruction
->type
= ARM_TST
;
1701 instruction
->type
= ARM_TEQ
;
1705 instruction
->type
= ARM_CMP
;
1709 instruction
->type
= ARM_CMN
;
1713 instruction
->type
= ARM_ORR
;
1717 instruction
->type
= ARM_MOV
;
1721 instruction
->type
= ARM_BIC
;
1725 instruction
->type
= ARM_MVN
;
1730 if (I
) {/* immediate shifter operand (#<immediate>)*/
1731 uint8_t immed_8
= opcode
& 0xff;
1732 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1735 immediate
= ror(immed_8
, rotate_imm
* 2);
1737 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1739 instruction
->info
.data_proc
.variant
= 0;
1740 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1741 } else {/* register-based shifter operand */
1743 shift
= (opcode
& 0x60) >> 5;
1744 Rm
= (opcode
& 0xf);
1746 if ((opcode
& 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1747 *#<shift_immediate>") */
1749 shift_imm
= (opcode
& 0xf80) >> 7;
1751 instruction
->info
.data_proc
.variant
= 1;
1752 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1753 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
=
1755 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1757 /* LSR encodes a shift by 32 bit as 0x0 */
1758 if ((shift
== 0x1) && (shift_imm
== 0x0))
1761 /* ASR encodes a shift by 32 bit as 0x0 */
1762 if ((shift
== 0x2) && (shift_imm
== 0x0))
1765 /* ROR by 32 bit is actually a RRX */
1766 if ((shift
== 0x3) && (shift_imm
== 0x0))
1769 if ((shift_imm
== 0x0) && (shift
== 0x0))
1770 snprintf(shifter_operand
, 32, "r%i", Rm
);
1772 if (shift
== 0x0) /* LSL */
1773 snprintf(shifter_operand
,
1778 else if (shift
== 0x1) /* LSR */
1779 snprintf(shifter_operand
,
1784 else if (shift
== 0x2) /* ASR */
1785 snprintf(shifter_operand
,
1790 else if (shift
== 0x3) /* ROR */
1791 snprintf(shifter_operand
,
1796 else if (shift
== 0x4) /* RRX */
1797 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1799 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1800 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1802 instruction
->info
.data_proc
.variant
= 2;
1803 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1804 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1805 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1807 if (shift
== 0x0) /* LSL */
1808 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1809 else if (shift
== 0x1) /* LSR */
1810 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1811 else if (shift
== 0x2) /* ASR */
1812 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1813 else if (shift
== 0x3) /* ROR */
1814 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1818 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1819 *<shifter_operand> */
1820 snprintf(instruction
->text
,
1822 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1831 } else if ((op
== 0xd) || (op
== 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1832 *<shifter_operand> */
1833 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1834 snprintf(instruction
->text
,
1836 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",
1840 snprintf(instruction
->text
,
1842 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1850 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1851 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1852 address
, opcode
, mnemonic
, COND(opcode
),
1853 Rn
, shifter_operand
);
1859 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1860 struct arm_instruction
*instruction
)
1862 /* clear fields, to avoid confusion */
1863 memset(instruction
, 0, sizeof(struct arm_instruction
));
1864 instruction
->opcode
= opcode
;
1865 instruction
->instruction_size
= 4;
1867 /* catch opcodes with condition field [31:28] = b1111 */
1868 if ((opcode
& 0xf0000000) == 0xf0000000) {
1869 /* Undefined instruction (or ARMv5E cache preload PLD) */
1870 if ((opcode
& 0x08000000) == 0x00000000)
1871 return evaluate_pld(opcode
, address
, instruction
);
1873 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1874 if ((opcode
& 0x0e000000) == 0x08000000)
1875 return evaluate_srs(opcode
, address
, instruction
);
1877 /* Branch and branch with link and change to Thumb */
1878 if ((opcode
& 0x0e000000) == 0x0a000000)
1879 return evaluate_blx_imm(opcode
, address
, instruction
);
1881 /* Extended coprocessor opcode space (ARMv5 and higher)
1882 * Coprocessor load/store and double register transfers */
1883 if ((opcode
& 0x0e000000) == 0x0c000000)
1884 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1886 /* Coprocessor data processing */
1887 if ((opcode
& 0x0f000100) == 0x0c000000)
1888 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1890 /* Coprocessor register transfers */
1891 if ((opcode
& 0x0f000010) == 0x0c000010)
1892 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1894 /* Undefined instruction */
1895 if ((opcode
& 0x0f000000) == 0x0f000000) {
1896 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1897 snprintf(instruction
->text
,
1899 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1906 /* catch opcodes with [27:25] = b000 */
1907 if ((opcode
& 0x0e000000) == 0x00000000) {
1908 /* Multiplies, extra load/stores */
1909 if ((opcode
& 0x00000090) == 0x00000090)
1910 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1912 /* Miscellaneous instructions */
1913 if ((opcode
& 0x0f900000) == 0x01000000)
1914 return evaluate_misc_instr(opcode
, address
, instruction
);
1916 return evaluate_data_proc(opcode
, address
, instruction
);
1919 /* catch opcodes with [27:25] = b001 */
1920 if ((opcode
& 0x0e000000) == 0x02000000) {
1921 /* 16-bit immediate load */
1922 if ((opcode
& 0x0fb00000) == 0x03000000)
1923 return evaluate_mov_imm(opcode
, address
, instruction
);
1925 /* Move immediate to status register */
1926 if ((opcode
& 0x0fb00000) == 0x03200000)
1927 return evaluate_mrs_msr(opcode
, address
, instruction
);
1929 return evaluate_data_proc(opcode
, address
, instruction
);
1933 /* catch opcodes with [27:25] = b010 */
1934 if ((opcode
& 0x0e000000) == 0x04000000) {
1935 /* Load/store immediate offset */
1936 return evaluate_load_store(opcode
, address
, instruction
);
1939 /* catch opcodes with [27:25] = b011 */
1940 if ((opcode
& 0x0e000000) == 0x06000000) {
1941 /* Load/store register offset */
1942 if ((opcode
& 0x00000010) == 0x00000000)
1943 return evaluate_load_store(opcode
, address
, instruction
);
1945 /* Architecturally Undefined instruction
1946 * ... don't expect these to ever be used
1948 if ((opcode
& 0x07f000f0) == 0x07f000f0) {
1949 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1950 snprintf(instruction
->text
, 128,
1951 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1956 /* "media" instructions */
1957 return evaluate_media(opcode
, address
, instruction
);
1960 /* catch opcodes with [27:25] = b100 */
1961 if ((opcode
& 0x0e000000) == 0x08000000) {
1962 /* Load/store multiple */
1963 return evaluate_ldm_stm(opcode
, address
, instruction
);
1966 /* catch opcodes with [27:25] = b101 */
1967 if ((opcode
& 0x0e000000) == 0x0a000000) {
1968 /* Branch and branch with link */
1969 return evaluate_b_bl(opcode
, address
, instruction
);
1972 /* catch opcodes with [27:25] = b110 */
1973 if ((opcode
& 0x0e000000) == 0x0c000000) {
1974 /* Coprocessor load/store and double register transfers */
1975 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1978 /* catch opcodes with [27:25] = b111 */
1979 if ((opcode
& 0x0e000000) == 0x0e000000) {
1980 /* Software interrupt */
1981 if ((opcode
& 0x0f000000) == 0x0f000000)
1982 return evaluate_swi(opcode
, address
, instruction
);
1984 /* Coprocessor data processing */
1985 if ((opcode
& 0x0f000010) == 0x0e000000)
1986 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1988 /* Coprocessor register transfers */
1989 if ((opcode
& 0x0f000010) == 0x0e000010)
1990 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1993 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1998 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1999 uint32_t address
, struct arm_instruction
*instruction
)
2001 uint32_t offset
= opcode
& 0x7ff;
2002 uint32_t opc
= (opcode
>> 11) & 0x3;
2003 uint32_t target_address
;
2004 char *mnemonic
= NULL
;
2006 /* sign extend 11-bit offset */
2007 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
2008 offset
= 0xfffff800 | offset
;
2010 target_address
= address
+ 4 + (offset
<< 1);
2013 /* unconditional branch */
2015 instruction
->type
= ARM_B
;
2020 instruction
->type
= ARM_BLX
;
2022 target_address
&= 0xfffffffc;
2026 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
2027 mnemonic
= "prefix";
2028 target_address
= offset
<< 12;
2032 instruction
->type
= ARM_BL
;
2037 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
2038 * these are effectively 32-bit instructions even in Thumb1. For
2039 * disassembly, it's simplest to always use the Thumb2 decoder.
2041 * But some cores will evidently handle them as two instructions,
2042 * where exceptions may occur between the two. The ETMv3.2+ ID
2043 * register has a bit which exposes this behavior.
2046 snprintf(instruction
->text
, 128,
2047 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
2048 address
, opcode
, mnemonic
, target_address
);
2050 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2051 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2056 static int evaluate_add_sub_thumb(uint16_t opcode
,
2057 uint32_t address
, struct arm_instruction
*instruction
)
2059 uint8_t Rd
= (opcode
>> 0) & 0x7;
2060 uint8_t Rn
= (opcode
>> 3) & 0x7;
2061 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
2062 uint32_t opc
= opcode
& (1 << 9);
2063 uint32_t reg_imm
= opcode
& (1 << 10);
2067 instruction
->type
= ARM_SUB
;
2070 /* REVISIT: if reg_imm == 0, display as "MOVS" */
2071 instruction
->type
= ARM_ADD
;
2075 instruction
->info
.data_proc
.Rd
= Rd
;
2076 instruction
->info
.data_proc
.Rn
= Rn
;
2077 instruction
->info
.data_proc
.S
= 1;
2080 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2081 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
2082 snprintf(instruction
->text
, 128,
2083 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
2084 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2086 instruction
->info
.data_proc
.variant
= 1;/*immediate shift*/
2087 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
2088 snprintf(instruction
->text
, 128,
2089 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
2090 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2096 static int evaluate_shift_imm_thumb(uint16_t opcode
,
2097 uint32_t address
, struct arm_instruction
*instruction
)
2099 uint8_t Rd
= (opcode
>> 0) & 0x7;
2100 uint8_t Rm
= (opcode
>> 3) & 0x7;
2101 uint8_t imm
= (opcode
>> 6) & 0x1f;
2102 uint8_t opc
= (opcode
>> 11) & 0x3;
2103 char *mnemonic
= NULL
;
2107 instruction
->type
= ARM_MOV
;
2109 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
2112 instruction
->type
= ARM_MOV
;
2114 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
2117 instruction
->type
= ARM_MOV
;
2119 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
2123 if ((imm
== 0) && (opc
!= 0))
2126 instruction
->info
.data_proc
.Rd
= Rd
;
2127 instruction
->info
.data_proc
.Rn
= -1;
2128 instruction
->info
.data_proc
.S
= 1;
2130 instruction
->info
.data_proc
.variant
= 1;/*immediate_shift*/
2131 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2132 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
2134 snprintf(instruction
->text
, 128,
2135 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2136 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
2141 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
2142 uint32_t address
, struct arm_instruction
*instruction
)
2144 uint8_t imm
= opcode
& 0xff;
2145 uint8_t Rd
= (opcode
>> 8) & 0x7;
2146 uint32_t opc
= (opcode
>> 11) & 0x3;
2147 char *mnemonic
= NULL
;
2149 instruction
->info
.data_proc
.Rd
= Rd
;
2150 instruction
->info
.data_proc
.Rn
= Rd
;
2151 instruction
->info
.data_proc
.S
= 1;
2152 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2153 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
2157 instruction
->type
= ARM_MOV
;
2159 instruction
->info
.data_proc
.Rn
= -1;
2162 instruction
->type
= ARM_CMP
;
2164 instruction
->info
.data_proc
.Rd
= -1;
2167 instruction
->type
= ARM_ADD
;
2171 instruction
->type
= ARM_SUB
;
2176 snprintf(instruction
->text
, 128,
2177 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
2178 address
, opcode
, mnemonic
, Rd
, imm
);
2183 static int evaluate_data_proc_thumb(uint16_t opcode
,
2184 uint32_t address
, struct arm_instruction
*instruction
)
2186 uint8_t high_reg
, op
, Rm
, Rd
, H1
, H2
;
2187 char *mnemonic
= NULL
;
2190 high_reg
= (opcode
& 0x0400) >> 10;
2191 op
= (opcode
& 0x03C0) >> 6;
2193 Rd
= (opcode
& 0x0007);
2194 Rm
= (opcode
& 0x0038) >> 3;
2195 H1
= (opcode
& 0x0080) >> 7;
2196 H2
= (opcode
& 0x0040) >> 6;
2198 instruction
->info
.data_proc
.Rd
= Rd
;
2199 instruction
->info
.data_proc
.Rn
= Rd
;
2200 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2201 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2202 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2211 instruction
->type
= ARM_ADD
;
2215 instruction
->type
= ARM_CMP
;
2219 instruction
->type
= ARM_MOV
;
2225 if ((opcode
& 0x7) == 0x0) {
2226 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2228 instruction
->type
= ARM_BLX
;
2229 snprintf(instruction
->text
, 128,
2231 " 0x%4.4x \tBLX\tr%i",
2232 address
, opcode
, Rm
);
2234 instruction
->type
= ARM_BX
;
2235 snprintf(instruction
->text
, 128,
2237 " 0x%4.4x \tBX\tr%i",
2238 address
, opcode
, Rm
);
2241 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2242 snprintf(instruction
->text
, 128,
2245 "UNDEFINED INSTRUCTION",
2254 instruction
->type
= ARM_AND
;
2258 instruction
->type
= ARM_EOR
;
2262 instruction
->type
= ARM_MOV
;
2264 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2265 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2266 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2267 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2270 instruction
->type
= ARM_MOV
;
2272 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2273 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2274 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2275 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2278 instruction
->type
= ARM_MOV
;
2280 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2281 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2282 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2283 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2286 instruction
->type
= ARM_ADC
;
2290 instruction
->type
= ARM_SBC
;
2294 instruction
->type
= ARM_MOV
;
2296 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2297 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2298 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2299 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2302 instruction
->type
= ARM_TST
;
2306 instruction
->type
= ARM_RSB
;
2308 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2309 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2310 instruction
->info
.data_proc
.Rn
= Rm
;
2313 instruction
->type
= ARM_CMP
;
2317 instruction
->type
= ARM_CMN
;
2321 instruction
->type
= ARM_ORR
;
2325 instruction
->type
= ARM_MUL
;
2329 instruction
->type
= ARM_BIC
;
2333 instruction
->type
= ARM_MVN
;
2340 snprintf(instruction
->text
, 128,
2341 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2343 address
, opcode
, mnemonic
, Rd
, Rm
);
2345 snprintf(instruction
->text
, 128,
2346 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2347 address
, opcode
, mnemonic
, Rd
, Rm
);
2352 /* PC-relative data addressing is word-aligned even with Thumb */
2353 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2355 return (addr
+ 4) & ~3;
2358 static int evaluate_load_literal_thumb(uint16_t opcode
,
2359 uint32_t address
, struct arm_instruction
*instruction
)
2362 uint8_t Rd
= (opcode
>> 8) & 0x7;
2364 instruction
->type
= ARM_LDR
;
2365 immediate
= opcode
& 0x000000ff;
2368 instruction
->info
.load_store
.Rd
= Rd
;
2369 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2370 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2371 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2372 instruction
->info
.load_store
.offset
.offset
= immediate
;
2374 snprintf(instruction
->text
, 128,
2375 "0x%8.8" PRIx32
" 0x%4.4x \t"
2376 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2377 address
, opcode
, Rd
, immediate
,
2378 thumb_alignpc4(address
) + immediate
);
2383 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2384 uint32_t address
, struct arm_instruction
*instruction
)
2386 uint8_t Rd
= (opcode
>> 0) & 0x7;
2387 uint8_t Rn
= (opcode
>> 3) & 0x7;
2388 uint8_t Rm
= (opcode
>> 6) & 0x7;
2389 uint8_t opc
= (opcode
>> 9) & 0x7;
2390 char *mnemonic
= NULL
;
2394 instruction
->type
= ARM_STR
;
2398 instruction
->type
= ARM_STRH
;
2402 instruction
->type
= ARM_STRB
;
2406 instruction
->type
= ARM_LDRSB
;
2410 instruction
->type
= ARM_LDR
;
2414 instruction
->type
= ARM_LDRH
;
2418 instruction
->type
= ARM_LDRB
;
2422 instruction
->type
= ARM_LDRSH
;
2427 snprintf(instruction
->text
, 128,
2428 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2429 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2431 instruction
->info
.load_store
.Rd
= Rd
;
2432 instruction
->info
.load_store
.Rn
= Rn
;
2433 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2434 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2435 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2440 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2441 uint32_t address
, struct arm_instruction
*instruction
)
2443 uint32_t offset
= (opcode
>> 6) & 0x1f;
2444 uint8_t Rd
= (opcode
>> 0) & 0x7;
2445 uint8_t Rn
= (opcode
>> 3) & 0x7;
2446 uint32_t L
= opcode
& (1 << 11);
2447 uint32_t B
= opcode
& (1 << 12);
2453 instruction
->type
= ARM_LDR
;
2456 instruction
->type
= ARM_STR
;
2460 if ((opcode
&0xF000) == 0x8000) {
2468 snprintf(instruction
->text
, 128,
2469 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2470 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2472 instruction
->info
.load_store
.Rd
= Rd
;
2473 instruction
->info
.load_store
.Rn
= Rn
;
2474 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2475 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2476 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2481 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2482 uint32_t address
, struct arm_instruction
*instruction
)
2484 uint32_t offset
= opcode
& 0xff;
2485 uint8_t Rd
= (opcode
>> 8) & 0x7;
2486 uint32_t L
= opcode
& (1 << 11);
2490 instruction
->type
= ARM_LDR
;
2493 instruction
->type
= ARM_STR
;
2497 snprintf(instruction
->text
, 128,
2498 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2499 address
, opcode
, mnemonic
, Rd
, offset
*4);
2501 instruction
->info
.load_store
.Rd
= Rd
;
2502 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2503 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2504 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2505 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2510 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2511 uint32_t address
, struct arm_instruction
*instruction
)
2513 uint32_t imm
= opcode
& 0xff;
2514 uint8_t Rd
= (opcode
>> 8) & 0x7;
2516 uint32_t SP
= opcode
& (1 << 11);
2517 const char *reg_name
;
2519 instruction
->type
= ARM_ADD
;
2529 snprintf(instruction
->text
, 128,
2530 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2531 address
, opcode
, Rd
, reg_name
, imm
* 4);
2533 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2534 instruction
->info
.data_proc
.Rd
= Rd
;
2535 instruction
->info
.data_proc
.Rn
= Rn
;
2536 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2541 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2542 uint32_t address
, struct arm_instruction
*instruction
)
2544 uint32_t imm
= opcode
& 0x7f;
2545 uint8_t opc
= opcode
& (1 << 7);
2550 instruction
->type
= ARM_SUB
;
2553 instruction
->type
= ARM_ADD
;
2557 snprintf(instruction
->text
, 128,
2558 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2559 address
, opcode
, mnemonic
, imm
*4);
2561 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2562 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2563 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2564 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2569 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2570 uint32_t address
, struct arm_instruction
*instruction
)
2572 uint32_t imm
= opcode
& 0xff;
2574 instruction
->type
= ARM_BKPT
;
2576 snprintf(instruction
->text
, 128,
2577 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2578 address
, opcode
, imm
);
2583 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2584 uint32_t address
, struct arm_instruction
*instruction
)
2586 uint32_t reg_list
= opcode
& 0xff;
2587 uint32_t L
= opcode
& (1 << 11);
2588 uint32_t R
= opcode
& (1 << 8);
2589 uint8_t Rn
= (opcode
>> 8) & 7;
2590 uint8_t addr_mode
= 0 /* IA */;
2594 char ptr_name
[7] = "";
2597 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2598 * The STMIA and LDMIA opcodes are used for other instructions.
2601 if ((opcode
& 0xf000) == 0xc000) { /* generic load/store multiple */
2605 instruction
->type
= ARM_LDM
;
2607 if (opcode
& (1 << Rn
))
2610 instruction
->type
= ARM_STM
;
2613 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2614 } else {/* push/pop */
2617 instruction
->type
= ARM_LDM
;
2620 reg_list
|= (1 << 15) /*PC*/;
2622 instruction
->type
= ARM_STM
;
2624 addr_mode
= 3; /*DB*/
2626 reg_list
|= (1 << 14) /*LR*/;
2630 reg_names_p
= reg_names
;
2631 for (i
= 0; i
<= 15; i
++) {
2632 if (reg_list
& (1 << i
))
2633 reg_names_p
+= snprintf(reg_names_p
,
2634 (reg_names
+ 40 - reg_names_p
),
2638 if (reg_names_p
> reg_names
)
2639 reg_names_p
[-2] = '\0';
2640 else /* invalid op : no registers */
2641 reg_names
[0] = '\0';
2643 snprintf(instruction
->text
, 128,
2644 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2645 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2647 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2648 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2649 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2654 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2655 uint32_t address
, struct arm_instruction
*instruction
)
2657 uint32_t offset
= opcode
& 0xff;
2658 uint8_t cond
= (opcode
>> 8) & 0xf;
2659 uint32_t target_address
;
2662 instruction
->type
= ARM_SWI
;
2663 snprintf(instruction
->text
, 128,
2664 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2665 address
, opcode
, offset
);
2667 } else if (cond
== 0xe) {
2668 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2669 snprintf(instruction
->text
, 128,
2670 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2675 /* sign extend 8-bit offset */
2676 if (offset
& 0x00000080)
2677 offset
= 0xffffff00 | offset
;
2679 target_address
= address
+ 4 + (offset
<< 1);
2681 snprintf(instruction
->text
, 128,
2682 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2684 arm_condition_strings
[cond
], target_address
);
2686 instruction
->type
= ARM_B
;
2687 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2688 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2693 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2694 struct arm_instruction
*instruction
)
2698 /* added in Thumb2 */
2699 offset
= (opcode
>> 3) & 0x1f;
2700 offset
|= (opcode
& 0x0200) >> 4;
2702 snprintf(instruction
->text
, 128,
2703 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2705 (opcode
& 0x0800) ? "N" : "",
2706 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2711 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2712 struct arm_instruction
*instruction
)
2714 /* added in ARMv6 */
2715 snprintf(instruction
->text
, 128,
2716 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2718 (opcode
& 0x0080) ? 'U' : 'S',
2719 (opcode
& 0x0040) ? 'B' : 'H',
2720 opcode
& 0x7, (opcode
>> 3) & 0x7);
2725 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2726 struct arm_instruction
*instruction
)
2728 /* added in ARMv6 */
2729 if ((opcode
& 0x0ff0) == 0x0650)
2730 snprintf(instruction
->text
, 128,
2731 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2733 (opcode
& 0x80) ? "BE" : "LE");
2734 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2735 snprintf(instruction
->text
, 128,
2736 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2738 (opcode
& 0x0010) ? 'D' : 'E',
2739 (opcode
& 0x0004) ? "A" : "",
2740 (opcode
& 0x0002) ? "I" : "",
2741 (opcode
& 0x0001) ? "F" : "");
2746 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2747 struct arm_instruction
*instruction
)
2751 /* added in ARMv6 */
2752 switch ((opcode
>> 6) & 3) {
2763 snprintf(instruction
->text
, 128,
2764 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2765 address
, opcode
, suffix
,
2766 opcode
& 0x7, (opcode
>> 3) & 0x7);
2771 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2772 struct arm_instruction
*instruction
)
2776 switch ((opcode
>> 4) & 0x0f) {
2793 hint
= "HINT (UNRECOGNIZED)";
2797 snprintf(instruction
->text
, 128,
2798 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2799 address
, opcode
, hint
);
2804 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2805 struct arm_instruction
*instruction
)
2807 unsigned cond
= (opcode
>> 4) & 0x0f;
2808 char *x
= "", *y
= "", *z
= "";
2811 z
= (opcode
& 0x02) ? "T" : "E";
2813 y
= (opcode
& 0x04) ? "T" : "E";
2815 x
= (opcode
& 0x08) ? "T" : "E";
2817 snprintf(instruction
->text
, 128,
2818 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2820 x
, y
, z
, arm_condition_strings
[cond
]);
2822 /* NOTE: strictly speaking, the next 1-4 instructions should
2823 * now be displayed with the relevant conditional suffix...
2829 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2831 /* clear fields, to avoid confusion */
2832 memset(instruction
, 0, sizeof(struct arm_instruction
));
2833 instruction
->opcode
= opcode
;
2834 instruction
->instruction_size
= 2;
2836 if ((opcode
& 0xe000) == 0x0000) {
2837 /* add/substract register or immediate */
2838 if ((opcode
& 0x1800) == 0x1800)
2839 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2840 /* shift by immediate */
2842 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2845 /* Add/substract/compare/move immediate */
2846 if ((opcode
& 0xe000) == 0x2000)
2847 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2849 /* Data processing instructions */
2850 if ((opcode
& 0xf800) == 0x4000)
2851 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2853 /* Load from literal pool */
2854 if ((opcode
& 0xf800) == 0x4800)
2855 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2857 /* Load/Store register offset */
2858 if ((opcode
& 0xf000) == 0x5000)
2859 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2861 /* Load/Store immediate offset */
2862 if (((opcode
& 0xe000) == 0x6000)
2863 || ((opcode
& 0xf000) == 0x8000))
2864 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2866 /* Load/Store from/to stack */
2867 if ((opcode
& 0xf000) == 0x9000)
2868 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2871 if ((opcode
& 0xf000) == 0xa000)
2872 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2875 if ((opcode
& 0xf000) == 0xb000) {
2876 switch ((opcode
>> 8) & 0x0f) {
2878 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2883 return evaluate_cb_thumb(opcode
, address
, instruction
);
2885 return evaluate_extend_thumb(opcode
, address
, instruction
);
2890 return evaluate_load_store_multiple_thumb(opcode
, address
,
2893 return evaluate_cps_thumb(opcode
, address
, instruction
);
2895 if ((opcode
& 0x00c0) == 0x0080)
2897 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2899 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2901 if (opcode
& 0x000f)
2902 return evaluate_ifthen_thumb(opcode
, address
,
2905 return evaluate_hint_thumb(opcode
, address
,
2909 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2910 snprintf(instruction
->text
, 128,
2911 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2916 /* Load/Store multiple */
2917 if ((opcode
& 0xf000) == 0xc000)
2918 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2920 /* Conditional branch + SWI */
2921 if ((opcode
& 0xf000) == 0xd000)
2922 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2924 if ((opcode
& 0xe000) == 0xe000) {
2925 /* Undefined instructions */
2926 if ((opcode
& 0xf801) == 0xe801) {
2927 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2928 snprintf(instruction
->text
, 128,
2929 "0x%8.8" PRIx32
" 0x%8.8x\t"
2930 "UNDEFINED INSTRUCTION",
2933 } else /* Branch to offset */
2934 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2937 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2941 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2942 struct arm_instruction
*instruction
, char *cp
)
2945 unsigned b21
= 1 << 21;
2946 unsigned b22
= 1 << 22;
2948 /* instead of combining two smaller 16-bit branch instructions,
2949 * Thumb2 uses only one larger 32-bit instruction.
2951 offset
= opcode
& 0x7ff;
2952 offset
|= (opcode
& 0x03ff0000) >> 5;
2953 if (opcode
& (1 << 26)) {
2954 offset
|= 0xff << 23;
2955 if ((opcode
& (1 << 11)) == 0)
2957 if ((opcode
& (1 << 13)) == 0)
2960 if (opcode
& (1 << 11))
2962 if (opcode
& (1 << 13))
2970 address
+= offset
<< 1;
2973 switch ((opcode
>> 12) & 0x5) {
2976 instruction
->type
= ARM_B
;
2980 instruction
->type
= ARM_BLX
;
2984 instruction
->type
= ARM_BL
;
2987 return ERROR_COMMAND_SYNTAX_ERROR
;
2989 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2990 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2991 sprintf(cp
, "%s\t%#8.8" PRIx32
, inst
, address
);
2996 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2997 struct arm_instruction
*instruction
, char *cp
)
3000 unsigned b17
= 1 << 17;
3001 unsigned b18
= 1 << 18;
3002 unsigned cond
= (opcode
>> 22) & 0x0f;
3004 offset
= opcode
& 0x7ff;
3005 offset
|= (opcode
& 0x003f0000) >> 5;
3006 if (opcode
& (1 << 26)) {
3007 offset
|= 0x1fff << 19;
3008 if ((opcode
& (1 << 11)) == 0)
3010 if ((opcode
& (1 << 13)) == 0)
3013 if (opcode
& (1 << 11))
3015 if (opcode
& (1 << 13))
3022 address
+= offset
<< 1;
3024 instruction
->type
= ARM_B
;
3025 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
3026 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
3027 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
3028 arm_condition_strings
[cond
],
3034 static const char *special_name(int number
)
3036 char *special
= "(RESERVED)";
3067 special
= "primask";
3070 special
= "basepri";
3073 special
= "basepri_max";
3076 special
= "faultmask";
3079 special
= "control";
3085 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
3086 struct arm_instruction
*instruction
, char *cp
)
3088 const char *mnemonic
;
3090 if (opcode
& 0x0700) {
3091 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3092 strcpy(cp
, "UNDEFINED");
3096 if (opcode
& 0x00f0) {
3097 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
3101 switch (opcode
& 0x0f) {
3106 mnemonic
= "YIELD.W";
3118 mnemonic
= "HINT.W (UNRECOGNIZED)";
3121 strcpy(cp
, mnemonic
);
3125 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3126 struct arm_instruction
*instruction
, char *cp
)
3128 const char *mnemonic
;
3130 switch ((opcode
>> 4) & 0x0f) {
3132 mnemonic
= "LEAVEX";
3135 mnemonic
= "ENTERX";
3150 return ERROR_COMMAND_SYNTAX_ERROR
;
3152 strcpy(cp
, mnemonic
);
3156 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3157 struct arm_instruction
*instruction
, char *cp
)
3159 /* permanently undefined */
3160 if ((opcode
& 0x07f07000) == 0x07f02000) {
3161 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3162 strcpy(cp
, "UNDEFINED");
3166 switch ((opcode
>> 12) & 0x5) {
3170 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3172 if (((opcode
>> 23) & 0x07) != 0x07)
3173 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3174 if (opcode
& (1 << 26))
3179 switch ((opcode
>> 20) & 0x7f) {
3182 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3183 (int) (opcode
>> 16) & 0x0f);
3186 return t2ev_hint(opcode
, address
, instruction
, cp
);
3188 return t2ev_misc(opcode
, address
, instruction
, cp
);
3190 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3194 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3195 special_name(opcode
& 0xff));
3200 return ERROR_COMMAND_SYNTAX_ERROR
;
3203 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3204 struct arm_instruction
*instruction
, char *cp
)
3206 char *mnemonic
= NULL
;
3207 int rn
= (opcode
>> 16) & 0xf;
3208 int rd
= (opcode
>> 8) & 0xf;
3209 unsigned immed
= opcode
& 0xff;
3215 /* ARMv7-M: A5.3.2 Modified immediate constants */
3216 func
= (opcode
>> 11) & 0x0e;
3219 if (opcode
& (1 << 26))
3222 /* "Modified" immediates */
3223 switch (func
>> 1) {
3230 immed
+= immed
<< 16;
3233 immed
+= immed
<< 8;
3234 immed
+= immed
<< 16;
3238 immed
= ror(immed
, func
);
3241 if (opcode
& (1 << 20))
3244 switch ((opcode
>> 21) & 0xf) {
3247 instruction
->type
= ARM_TST
;
3253 instruction
->type
= ARM_AND
;
3258 instruction
->type
= ARM_BIC
;
3263 instruction
->type
= ARM_MOV
;
3268 instruction
->type
= ARM_ORR
;
3274 instruction
->type
= ARM_MVN
;
3278 /* instruction->type = ARM_ORN; */
3284 instruction
->type
= ARM_TEQ
;
3290 instruction
->type
= ARM_EOR
;
3296 instruction
->type
= ARM_CMN
;
3302 instruction
->type
= ARM_ADD
;
3308 instruction
->type
= ARM_ADC
;
3313 instruction
->type
= ARM_SBC
;
3318 instruction
->type
= ARM_CMP
;
3324 instruction
->type
= ARM_SUB
;
3330 instruction
->type
= ARM_RSB
;
3335 return ERROR_COMMAND_SYNTAX_ERROR
;
3339 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3340 mnemonic
, suffix2
, rd
, immed
, immed
);
3342 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3343 mnemonic
, suffix
, suffix2
,
3344 rd
, rn
, immed
, immed
);
3349 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3350 struct arm_instruction
*instruction
, char *cp
)
3352 char *mnemonic
= NULL
;
3353 int rn
= (opcode
>> 16) & 0xf;
3354 int rd
= (opcode
>> 8) & 0xf;
3357 bool is_signed
= false;
3359 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3360 if (opcode
& (1 << 26))
3363 switch ((opcode
>> 20) & 0x1f) {
3372 immed
|= (opcode
>> 4) & 0xf000;
3373 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3381 /* move constant to top 16 bits of register */
3382 immed
|= (opcode
>> 4) & 0xf000;
3383 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3391 /* signed/unsigned saturated add */
3392 immed
= (opcode
>> 6) & 0x03;
3393 immed
|= (opcode
>> 10) & 0x1c;
3394 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3395 is_signed
? "S" : "U",
3396 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3397 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3398 immed
? immed
: 32);
3404 /* signed/unsigned bitfield extract */
3405 immed
= (opcode
>> 6) & 0x03;
3406 immed
|= (opcode
>> 10) & 0x1c;
3407 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3408 is_signed
? "S" : "U",
3410 (int) (opcode
& 0x1f) + 1);
3413 immed
= (opcode
>> 6) & 0x03;
3414 immed
|= (opcode
>> 10) & 0x1c;
3415 if (rn
== 0xf) /* bitfield clear */
3416 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3418 (int) (opcode
& 0x1f) + 1 - immed
);
3419 else /* bitfield insert */
3420 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3422 (int) (opcode
& 0x1f) + 1 - immed
);
3425 return ERROR_COMMAND_SYNTAX_ERROR
;
3428 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3429 rd
, rn
, immed
, immed
);
3433 address
= thumb_alignpc4(address
);
3438 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3439 * not hiding the pc-relative stuff will sometimes be useful.
3441 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3445 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3446 struct arm_instruction
*instruction
, char *cp
)
3448 unsigned op
= (opcode
>> 20) & 0xf;
3454 unsigned rn
= (opcode
>> 16) & 0x0f;
3455 unsigned rt
= (opcode
>> 12) & 0x0f;
3458 return ERROR_COMMAND_SYNTAX_ERROR
;
3460 if (opcode
& 0x0800)
3495 return ERROR_COMMAND_SYNTAX_ERROR
;
3498 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3499 size
, rt
, rn
, (int) opcode
& 0x0f,
3500 (int) (opcode
>> 4) & 0x03);
3504 immed
= opcode
& 0x0fff;
3505 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3506 size
, rt
, rn
, immed
, immed
);
3510 immed
= opcode
& 0x00ff;
3512 switch (opcode
& 0x700) {
3518 return ERROR_COMMAND_SYNTAX_ERROR
;
3521 /* two indexed modes will write back rn */
3522 if (opcode
& 0x100) {
3523 if (opcode
& 0x400) /* pre-indexed */
3525 else { /* post-indexed */
3531 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3532 size
, suffix
, rt
, rn
, p1
,
3533 (opcode
& 0x200) ? "" : "-",
3538 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3539 struct arm_instruction
*instruction
, char *cp
)
3541 int ra
= (opcode
>> 12) & 0xf;
3543 switch (opcode
& 0x007000f0) {
3546 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3547 (int) (opcode
>> 8) & 0xf,
3548 (int) (opcode
>> 16) & 0xf,
3549 (int) (opcode
>> 0) & 0xf);
3551 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3552 (int) (opcode
>> 8) & 0xf,
3553 (int) (opcode
>> 16) & 0xf,
3554 (int) (opcode
>> 0) & 0xf, ra
);
3557 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3558 (int) (opcode
>> 8) & 0xf,
3559 (int) (opcode
>> 16) & 0xf,
3560 (int) (opcode
>> 0) & 0xf, ra
);
3563 return ERROR_COMMAND_SYNTAX_ERROR
;
3568 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3569 struct arm_instruction
*instruction
, char *cp
)
3571 int op
= (opcode
>> 4) & 0xf;
3572 char *infix
= "MUL";
3574 op
+= (opcode
>> 16) & 0x70;
3582 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3583 (op
& 0x20) ? 'U' : 'S',
3585 (int) (opcode
>> 12) & 0xf,
3586 (int) (opcode
>> 8) & 0xf,
3587 (int) (opcode
>> 16) & 0xf,
3588 (int) (opcode
>> 0) & 0xf);
3592 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3593 (op
& 0x20) ? 'U' : 'S',
3594 (int) (opcode
>> 8) & 0xf,
3595 (int) (opcode
>> 16) & 0xf,
3596 (int) (opcode
>> 0) & 0xf);
3599 return ERROR_COMMAND_SYNTAX_ERROR
;
3605 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3606 struct arm_instruction
*instruction
, char *cp
)
3608 int rn
= (opcode
>> 16) & 0xf;
3609 int op
= (opcode
>> 22) & 0x6;
3610 int t
= (opcode
>> 21) & 1;
3611 unsigned registers
= opcode
& 0xffff;
3614 if (opcode
& (1 << 20))
3622 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3624 (unsigned) (opcode
& 0x1f));
3630 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3631 (unsigned) ((opcode
>> 16) & 0xf),
3635 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3639 sprintf(cp
, "POP.W\t");
3641 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3645 sprintf(cp
, "PUSH.W\t");
3647 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3650 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3653 return ERROR_COMMAND_SYNTAX_ERROR
;
3658 for (t
= 0; registers
; t
++, registers
>>= 1) {
3659 if ((registers
& 1) == 0)
3662 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3671 /* load/store dual or exclusive, table branch */
3672 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3673 struct arm_instruction
*instruction
, char *cp
)
3675 unsigned op1op2
= (opcode
>> 20) & 0x3;
3676 unsigned op3
= (opcode
>> 4) & 0xf;
3678 unsigned rn
= (opcode
>> 16) & 0xf;
3679 unsigned rt
= (opcode
>> 12) & 0xf;
3680 unsigned rd
= (opcode
>> 8) & 0xf;
3681 unsigned imm
= opcode
& 0xff;
3685 op1op2
|= (opcode
>> 21) & 0xc;
3715 mnemonic
= "STREXB";
3718 mnemonic
= "STREXH";
3721 return ERROR_COMMAND_SYNTAX_ERROR
;
3729 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3732 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3735 mnemonic
= "LDREXB";
3738 mnemonic
= "LDREXH";
3741 return ERROR_COMMAND_SYNTAX_ERROR
;
3746 return ERROR_COMMAND_SYNTAX_ERROR
;
3751 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3752 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3754 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3755 mnemonic
, rd
, rt
, rn
);
3761 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3762 mnemonic
, rt
, rn
, imm
, imm
);
3764 sprintf(cp
, "%s\tr%u, [r%u]",
3769 /* two indexed modes will write back rn */
3770 if (opcode
& (1 << 21)) {
3771 if (opcode
& (1 << 24)) /* pre-indexed */
3773 else { /* post-indexed */
3780 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3781 mnemonic
, rt
, rd
, rn
, p1
,
3782 (opcode
& (1 << 23)) ? "" : "-",
3787 address
= thumb_alignpc4(address
);
3789 if (opcode
& (1 << 23))
3793 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3794 mnemonic
, rt
, rd
, address
);
3798 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3799 struct arm_instruction
*instruction
, char *cp
)
3801 int op
= (opcode
>> 21) & 0xf;
3802 int rd
= (opcode
>> 8) & 0xf;
3803 int rn
= (opcode
>> 16) & 0xf;
3804 int type
= (opcode
>> 4) & 0x3;
3805 int immed
= (opcode
>> 6) & 0x3;
3809 immed
|= (opcode
>> 10) & 0x1c;
3810 if (opcode
& (1 << 20))
3816 if (!(opcode
& (1 << 20)))
3817 return ERROR_COMMAND_SYNTAX_ERROR
;
3818 instruction
->type
= ARM_TST
;
3823 instruction
->type
= ARM_AND
;
3827 instruction
->type
= ARM_BIC
;
3832 instruction
->type
= ARM_MOV
;
3836 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3838 (int) (opcode
& 0xf));
3851 sprintf(cp
, "RRX%s\tr%d, r%d",
3853 (int) (opcode
& 0xf));
3861 instruction
->type
= ARM_ORR
;
3867 instruction
->type
= ARM_MVN
;
3872 /* instruction->type = ARM_ORN; */
3878 if (!(opcode
& (1 << 20)))
3879 return ERROR_COMMAND_SYNTAX_ERROR
;
3880 instruction
->type
= ARM_TEQ
;
3885 instruction
->type
= ARM_EOR
;
3890 if (!(opcode
& (1 << 20)))
3891 return ERROR_COMMAND_SYNTAX_ERROR
;
3892 instruction
->type
= ARM_CMN
;
3897 instruction
->type
= ARM_ADD
;
3901 instruction
->type
= ARM_ADC
;
3905 instruction
->type
= ARM_SBC
;
3910 if (!(opcode
& (1 << 21)))
3911 return ERROR_COMMAND_SYNTAX_ERROR
;
3912 instruction
->type
= ARM_CMP
;
3917 instruction
->type
= ARM_SUB
;
3921 instruction
->type
= ARM_RSB
;
3925 return ERROR_COMMAND_SYNTAX_ERROR
;
3928 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3929 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3952 strcpy(cp
, ", RRX");
3958 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3962 sprintf(cp
, "%s%s.W\tr%d, r%d",
3963 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3967 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3968 mnemonic
, suffix
, rd
,
3969 (int) (opcode
& 0xf), immed
? immed
: 32);
3973 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3974 struct arm_instruction
*instruction
, char *cp
)
3979 if (((opcode
>> 4) & 0xf) == 0) {
3980 switch ((opcode
>> 21) & 0x7) {
3994 return ERROR_COMMAND_SYNTAX_ERROR
;
3997 instruction
->type
= ARM_MOV
;
3998 if (opcode
& (1 << 20))
4000 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
4002 (int) (opcode
>> 8) & 0xf,
4003 (int) (opcode
>> 16) & 0xf,
4004 (int) (opcode
>> 0) & 0xf);
4006 } else if (opcode
& (1 << 7)) {
4007 switch ((opcode
>> 20) & 0xf) {
4012 switch ((opcode
>> 4) & 0x3) {
4014 suffix
= ", ROR #8";
4017 suffix
= ", ROR #16";
4020 suffix
= ", ROR #24";
4023 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
4024 (opcode
& (1 << 24)) ? 'U' : 'S',
4025 (opcode
& (1 << 26)) ? 'B' : 'H',
4026 (int) (opcode
>> 8) & 0xf,
4027 (int) (opcode
>> 0) & 0xf,
4034 if (opcode
& (1 << 6))
4035 return ERROR_COMMAND_SYNTAX_ERROR
;
4036 if (((opcode
>> 12) & 0xf) != 0xf)
4037 return ERROR_COMMAND_SYNTAX_ERROR
;
4038 if (!(opcode
& (1 << 20)))
4039 return ERROR_COMMAND_SYNTAX_ERROR
;
4041 switch (((opcode
>> 19) & 0x04)
4042 | ((opcode
>> 4) & 0x3)) {
4047 mnemonic
= "REV16.W";
4053 mnemonic
= "REVSH.W";
4059 return ERROR_COMMAND_SYNTAX_ERROR
;
4061 sprintf(cp
, "%s\tr%d, r%d",
4063 (int) (opcode
>> 8) & 0xf,
4064 (int) (opcode
>> 0) & 0xf);
4067 return ERROR_COMMAND_SYNTAX_ERROR
;
4074 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
4075 struct arm_instruction
*instruction
, char *cp
)
4077 int rn
= (opcode
>> 16) & 0xf;
4080 instruction
->type
= ARM_LDR
;
4083 immed
= opcode
& 0x0fff;
4084 if ((opcode
& (1 << 23)) == 0)
4086 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4087 (int) (opcode
>> 12) & 0xf,
4088 thumb_alignpc4(address
) + immed
);
4092 if (opcode
& (1 << 23)) {
4093 immed
= opcode
& 0x0fff;
4094 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4095 (int) (opcode
>> 12) & 0xf,
4100 if (!(opcode
& (0x3f << 6))) {
4101 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4102 (int) (opcode
>> 12) & 0xf,
4104 (int) (opcode
>> 0) & 0xf,
4105 (int) (opcode
>> 4) & 0x3);
4110 if (((opcode
>> 8) & 0xf) == 0xe) {
4111 immed
= opcode
& 0x00ff;
4113 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4114 (int) (opcode
>> 12) & 0xf,
4119 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4120 char *p1
= "]", *p2
= "";
4122 if (!(opcode
& 0x0500))
4123 return ERROR_COMMAND_SYNTAX_ERROR
;
4125 immed
= opcode
& 0x00ff;
4127 /* two indexed modes will write back rn */
4128 if (opcode
& 0x100) {
4129 if (opcode
& 0x400) /* pre-indexed */
4131 else { /* post-indexed */
4137 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4138 (int) (opcode
>> 12) & 0xf,
4140 (opcode
& 0x200) ? "" : "-",
4145 return ERROR_COMMAND_SYNTAX_ERROR
;
4148 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4149 struct arm_instruction
*instruction
, char *cp
)
4151 int rn
= (opcode
>> 16) & 0xf;
4152 int rt
= (opcode
>> 12) & 0xf;
4153 int op2
= (opcode
>> 6) & 0x3f;
4155 char *p1
= "", *p2
= "]";
4158 switch ((opcode
>> 23) & 0x3) {
4160 if ((rn
& rt
) == 0xf) {
4162 immed
= opcode
& 0xfff;
4163 address
= thumb_alignpc4(address
);
4164 if (opcode
& (1 << 23))
4168 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4172 if (rn
== 0x0f && rt
!= 0x0f) {
4174 immed
= opcode
& 0xfff;
4175 address
= thumb_alignpc4(address
);
4176 if (opcode
& (1 << 23))
4180 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4186 if ((op2
& 0x3c) == 0x38) {
4187 immed
= opcode
& 0xff;
4188 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4189 rt
, rn
, immed
, immed
);
4192 if ((op2
& 0x3c) == 0x30) {
4194 immed
= opcode
& 0xff;
4197 p1
= (opcode
& (1 << 21)) ? "W" : "";
4198 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4199 p1
, rn
, immed
, immed
);
4204 immed
= opcode
& 0xff;
4205 if (!(opcode
& 0x200))
4208 /* two indexed modes will write back rn */
4209 if (opcode
& 0x100) {
4210 if (opcode
& 0x400) /* pre-indexed */
4212 else { /* post-indexed */
4218 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4219 mnemonic
, rt
, rn
, p1
,
4223 if ((op2
& 0x24) == 0x24) {
4225 goto ldrxb_immediate_t3
;
4228 int rm
= opcode
& 0xf;
4231 sprintf(cp
, "PLD\t");
4233 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4234 immed
= (opcode
>> 4) & 0x3;
4236 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4241 if ((rn
& rt
) == 0xf)
4244 immed
= opcode
& 0xfff;
4245 goto preload_immediate
;
4249 mnemonic
= "LDRB.W";
4250 immed
= opcode
& 0xfff;
4251 goto ldrxb_immediate_t2
;
4253 if ((rn
& rt
) == 0xf) {
4254 immed
= opcode
& 0xfff;
4255 address
= thumb_alignpc4(address
);
4256 if (opcode
& (1 << 23))
4260 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4263 if (rn
== 0xf && rt
!= 0xf) {
4265 immed
= opcode
& 0xfff;
4266 address
= thumb_alignpc4(address
);
4267 if (opcode
& (1 << 23))
4271 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4276 if ((op2
& 0x3c) == 0x38) {
4277 immed
= opcode
& 0xff;
4278 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4279 rt
, rn
, immed
, immed
);
4282 if ((op2
& 0x3c) == 0x30) {
4284 immed
= opcode
& 0xff;
4285 immed
= -immed
; /* pli */
4286 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4291 goto ldrxb_immediate_t3
;
4293 if ((op2
& 0x24) == 0x24) {
4295 goto ldrxb_immediate_t3
;
4298 int rm
= opcode
& 0xf;
4301 sprintf(cp
, "PLI\t");
4303 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4304 immed
= (opcode
>> 4) & 0x3;
4306 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4312 immed
= opcode
& 0xfff;
4313 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4319 immed
= opcode
& 0xfff;
4321 goto ldrxb_immediate_t2
;
4324 return ERROR_COMMAND_SYNTAX_ERROR
;
4327 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4328 struct arm_instruction
*instruction
, char *cp
)
4330 int rn
= (opcode
>> 16) & 0xf;
4331 int rt
= (opcode
>> 12) & 0xf;
4332 int op2
= (opcode
>> 6) & 0x3f;
4337 sprintf(cp
, "HINT (UNALLOCATED)");
4341 if (opcode
& (1 << 24))
4344 if ((opcode
& (1 << 23)) == 0) {
4347 immed
= opcode
& 0xfff;
4348 address
= thumb_alignpc4(address
);
4349 if (opcode
& (1 << 23))
4353 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4358 int rm
= opcode
& 0xf;
4360 immed
= (opcode
>> 4) & 0x3;
4361 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4362 sign
, rt
, rn
, rm
, immed
);
4365 if ((op2
& 0x3c) == 0x38) {
4366 immed
= opcode
& 0xff;
4367 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4368 sign
, rt
, rn
, immed
, immed
);
4371 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4372 char *p1
= "", *p2
= "]";
4374 immed
= opcode
& 0xff;
4375 if (!(opcode
& 0x200))
4378 /* two indexed modes will write back rn */
4379 if (opcode
& 0x100) {
4380 if (opcode
& 0x400) /* pre-indexed */
4382 else { /* post-indexed */
4387 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4388 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4395 immed
= opcode
& 0xfff;
4396 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4397 sign
, *sign
? "" : ".W",
4398 rt
, rn
, immed
, immed
);
4402 return ERROR_COMMAND_SYNTAX_ERROR
;
4406 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4407 * always set. That means eventual arm_simulate_step() support for Thumb2
4408 * will need work in this area.
4410 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4417 /* clear low bit ... it's set on function pointers */
4420 /* clear fields, to avoid confusion */
4421 memset(instruction
, 0, sizeof(struct arm_instruction
));
4423 /* read first halfword, see if this is the only one */
4424 retval
= target_read_u16(target
, address
, &op
);
4425 if (retval
!= ERROR_OK
)
4428 switch (op
& 0xf800) {
4432 /* 32-bit instructions */
4433 instruction
->instruction_size
= 4;
4435 retval
= target_read_u16(target
, address
+ 2, &op
);
4436 if (retval
!= ERROR_OK
)
4439 instruction
->opcode
= opcode
;
4442 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4443 return thumb_evaluate_opcode(op
, address
, instruction
);
4446 snprintf(instruction
->text
, 128,
4447 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4449 cp
= strchr(instruction
->text
, 0);
4450 retval
= ERROR_FAIL
;
4452 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4453 if ((opcode
& 0x1a008000) == 0x10000000)
4454 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4456 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4457 else if ((opcode
& 0x1a008000) == 0x12000000)
4458 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4460 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4461 else if ((opcode
& 0x18008000) == 0x10008000)
4462 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4464 /* ARMv7-M: A5.3.5 Load/store multiple */
4465 else if ((opcode
& 0x1e400000) == 0x08000000)
4466 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4468 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4469 else if ((opcode
& 0x1e400000) == 0x08400000)
4470 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4472 /* ARMv7-M: A5.3.7 Load word */
4473 else if ((opcode
& 0x1f700000) == 0x18500000)
4474 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4476 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4477 else if ((opcode
& 0x1e700000) == 0x18300000)
4478 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4480 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4481 else if ((opcode
& 0x1e700000) == 0x18100000)
4482 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4484 /* ARMv7-M: A5.3.10 Store single data item */
4485 else if ((opcode
& 0x1f100000) == 0x18000000)
4486 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4488 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4489 else if ((opcode
& 0x1e000000) == 0x0a000000)
4490 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4492 /* ARMv7-M: A5.3.12 Data processing (register)
4493 * and A5.3.13 Miscellaneous operations
4495 else if ((opcode
& 0x1f000000) == 0x1a000000)
4496 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4498 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4499 else if ((opcode
& 0x1f800000) == 0x1b000000)
4500 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4502 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4503 else if ((opcode
& 0x1f800000) == 0x1b800000)
4504 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4506 if (retval
== ERROR_OK
)
4510 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4511 * instructions; not yet handled here.
4514 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4515 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4516 strcpy(cp
, "UNDEFINED OPCODE");
4520 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4523 strcpy(cp
, "(32-bit Thumb2 ...)");
4527 int arm_access_size(struct arm_instruction
*instruction
)
4529 if ((instruction
->type
== ARM_LDRB
)
4530 || (instruction
->type
== ARM_LDRBT
)
4531 || (instruction
->type
== ARM_LDRSB
)
4532 || (instruction
->type
== ARM_STRB
)
4533 || (instruction
->type
== ARM_STRBT
))
4535 else if ((instruction
->type
== ARM_LDRH
)
4536 || (instruction
->type
== ARM_LDRSH
)
4537 || (instruction
->type
== ARM_STRH
))
4539 else if ((instruction
->type
== ARM_LDR
)
4540 || (instruction
->type
== ARM_LDRT
)
4541 || (instruction
->type
== ARM_STR
)
4542 || (instruction
->type
== ARM_STRT
))
4544 else if ((instruction
->type
== ARM_LDRD
)
4545 || (instruction
->type
== ARM_STRD
))
4548 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction",
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)