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
;
2981 address
&= 0xfffffffc;
2985 instruction
->type
= ARM_BL
;
2988 return ERROR_COMMAND_SYNTAX_ERROR
;
2990 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2991 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2992 sprintf(cp
, "%s\t%#8.8" PRIx32
, inst
, address
);
2997 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2998 struct arm_instruction
*instruction
, char *cp
)
3001 unsigned b17
= 1 << 17;
3002 unsigned b18
= 1 << 18;
3003 unsigned cond
= (opcode
>> 22) & 0x0f;
3005 offset
= opcode
& 0x7ff;
3006 offset
|= (opcode
& 0x003f0000) >> 5;
3007 if (opcode
& (1 << 26)) {
3008 offset
|= 0x1fff << 19;
3009 if ((opcode
& (1 << 11)) == 0)
3011 if ((opcode
& (1 << 13)) == 0)
3014 if (opcode
& (1 << 11))
3016 if (opcode
& (1 << 13))
3023 address
+= offset
<< 1;
3025 instruction
->type
= ARM_B
;
3026 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
3027 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
3028 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
3029 arm_condition_strings
[cond
],
3035 static const char *special_name(int number
)
3037 char *special
= "(RESERVED)";
3068 special
= "primask";
3071 special
= "basepri";
3074 special
= "basepri_max";
3077 special
= "faultmask";
3080 special
= "control";
3086 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
3087 struct arm_instruction
*instruction
, char *cp
)
3089 const char *mnemonic
;
3091 if (opcode
& 0x0700) {
3092 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3093 strcpy(cp
, "UNDEFINED");
3097 if (opcode
& 0x00f0) {
3098 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
3102 switch (opcode
& 0x0f) {
3107 mnemonic
= "YIELD.W";
3119 mnemonic
= "HINT.W (UNRECOGNIZED)";
3122 strcpy(cp
, mnemonic
);
3126 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3127 struct arm_instruction
*instruction
, char *cp
)
3129 const char *mnemonic
;
3131 switch ((opcode
>> 4) & 0x0f) {
3133 mnemonic
= "LEAVEX";
3136 mnemonic
= "ENTERX";
3151 return ERROR_COMMAND_SYNTAX_ERROR
;
3153 strcpy(cp
, mnemonic
);
3157 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3158 struct arm_instruction
*instruction
, char *cp
)
3160 /* permanently undefined */
3161 if ((opcode
& 0x07f07000) == 0x07f02000) {
3162 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3163 strcpy(cp
, "UNDEFINED");
3167 switch ((opcode
>> 12) & 0x5) {
3171 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3173 if (((opcode
>> 23) & 0x07) != 0x07)
3174 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3175 if (opcode
& (1 << 26))
3180 switch ((opcode
>> 20) & 0x7f) {
3183 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3184 (int) (opcode
>> 16) & 0x0f);
3187 return t2ev_hint(opcode
, address
, instruction
, cp
);
3189 return t2ev_misc(opcode
, address
, instruction
, cp
);
3191 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3195 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3196 special_name(opcode
& 0xff));
3201 return ERROR_COMMAND_SYNTAX_ERROR
;
3204 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3205 struct arm_instruction
*instruction
, char *cp
)
3207 char *mnemonic
= NULL
;
3208 int rn
= (opcode
>> 16) & 0xf;
3209 int rd
= (opcode
>> 8) & 0xf;
3210 unsigned immed
= opcode
& 0xff;
3216 /* ARMv7-M: A5.3.2 Modified immediate constants */
3217 func
= (opcode
>> 11) & 0x0e;
3220 if (opcode
& (1 << 26))
3223 /* "Modified" immediates */
3224 switch (func
>> 1) {
3231 immed
+= immed
<< 16;
3234 immed
+= immed
<< 8;
3235 immed
+= immed
<< 16;
3239 immed
= ror(immed
, func
);
3242 if (opcode
& (1 << 20))
3245 switch ((opcode
>> 21) & 0xf) {
3248 instruction
->type
= ARM_TST
;
3254 instruction
->type
= ARM_AND
;
3259 instruction
->type
= ARM_BIC
;
3264 instruction
->type
= ARM_MOV
;
3269 instruction
->type
= ARM_ORR
;
3275 instruction
->type
= ARM_MVN
;
3279 /* instruction->type = ARM_ORN; */
3285 instruction
->type
= ARM_TEQ
;
3291 instruction
->type
= ARM_EOR
;
3297 instruction
->type
= ARM_CMN
;
3303 instruction
->type
= ARM_ADD
;
3309 instruction
->type
= ARM_ADC
;
3314 instruction
->type
= ARM_SBC
;
3319 instruction
->type
= ARM_CMP
;
3325 instruction
->type
= ARM_SUB
;
3331 instruction
->type
= ARM_RSB
;
3336 return ERROR_COMMAND_SYNTAX_ERROR
;
3340 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3341 mnemonic
, suffix2
, rd
, immed
, immed
);
3343 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3344 mnemonic
, suffix
, suffix2
,
3345 rd
, rn
, immed
, immed
);
3350 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3351 struct arm_instruction
*instruction
, char *cp
)
3353 char *mnemonic
= NULL
;
3354 int rn
= (opcode
>> 16) & 0xf;
3355 int rd
= (opcode
>> 8) & 0xf;
3358 bool is_signed
= false;
3360 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3361 if (opcode
& (1 << 26))
3364 switch ((opcode
>> 20) & 0x1f) {
3373 immed
|= (opcode
>> 4) & 0xf000;
3374 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3382 /* move constant to top 16 bits of register */
3383 immed
|= (opcode
>> 4) & 0xf000;
3384 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3392 /* signed/unsigned saturated add */
3393 immed
= (opcode
>> 6) & 0x03;
3394 immed
|= (opcode
>> 10) & 0x1c;
3395 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3396 is_signed
? "S" : "U",
3397 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3398 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3399 immed
? immed
: 32);
3405 /* signed/unsigned bitfield extract */
3406 immed
= (opcode
>> 6) & 0x03;
3407 immed
|= (opcode
>> 10) & 0x1c;
3408 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3409 is_signed
? "S" : "U",
3411 (int) (opcode
& 0x1f) + 1);
3414 immed
= (opcode
>> 6) & 0x03;
3415 immed
|= (opcode
>> 10) & 0x1c;
3416 if (rn
== 0xf) /* bitfield clear */
3417 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3419 (int) (opcode
& 0x1f) + 1 - immed
);
3420 else /* bitfield insert */
3421 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3423 (int) (opcode
& 0x1f) + 1 - immed
);
3426 return ERROR_COMMAND_SYNTAX_ERROR
;
3429 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3430 rd
, rn
, immed
, immed
);
3434 address
= thumb_alignpc4(address
);
3439 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3440 * not hiding the pc-relative stuff will sometimes be useful.
3442 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3446 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3447 struct arm_instruction
*instruction
, char *cp
)
3449 unsigned op
= (opcode
>> 20) & 0xf;
3455 unsigned rn
= (opcode
>> 16) & 0x0f;
3456 unsigned rt
= (opcode
>> 12) & 0x0f;
3459 return ERROR_COMMAND_SYNTAX_ERROR
;
3461 if (opcode
& 0x0800)
3496 return ERROR_COMMAND_SYNTAX_ERROR
;
3499 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3500 size
, rt
, rn
, (int) opcode
& 0x0f,
3501 (int) (opcode
>> 4) & 0x03);
3505 immed
= opcode
& 0x0fff;
3506 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3507 size
, rt
, rn
, immed
, immed
);
3511 immed
= opcode
& 0x00ff;
3513 switch (opcode
& 0x700) {
3519 return ERROR_COMMAND_SYNTAX_ERROR
;
3522 /* two indexed modes will write back rn */
3523 if (opcode
& 0x100) {
3524 if (opcode
& 0x400) /* pre-indexed */
3526 else { /* post-indexed */
3532 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3533 size
, suffix
, rt
, rn
, p1
,
3534 (opcode
& 0x200) ? "" : "-",
3539 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3540 struct arm_instruction
*instruction
, char *cp
)
3542 int ra
= (opcode
>> 12) & 0xf;
3544 switch (opcode
& 0x007000f0) {
3547 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3548 (int) (opcode
>> 8) & 0xf,
3549 (int) (opcode
>> 16) & 0xf,
3550 (int) (opcode
>> 0) & 0xf);
3552 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3553 (int) (opcode
>> 8) & 0xf,
3554 (int) (opcode
>> 16) & 0xf,
3555 (int) (opcode
>> 0) & 0xf, ra
);
3558 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3559 (int) (opcode
>> 8) & 0xf,
3560 (int) (opcode
>> 16) & 0xf,
3561 (int) (opcode
>> 0) & 0xf, ra
);
3564 return ERROR_COMMAND_SYNTAX_ERROR
;
3569 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3570 struct arm_instruction
*instruction
, char *cp
)
3572 int op
= (opcode
>> 4) & 0xf;
3573 char *infix
= "MUL";
3575 op
+= (opcode
>> 16) & 0x70;
3583 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3584 (op
& 0x20) ? 'U' : 'S',
3586 (int) (opcode
>> 12) & 0xf,
3587 (int) (opcode
>> 8) & 0xf,
3588 (int) (opcode
>> 16) & 0xf,
3589 (int) (opcode
>> 0) & 0xf);
3593 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3594 (op
& 0x20) ? 'U' : 'S',
3595 (int) (opcode
>> 8) & 0xf,
3596 (int) (opcode
>> 16) & 0xf,
3597 (int) (opcode
>> 0) & 0xf);
3600 return ERROR_COMMAND_SYNTAX_ERROR
;
3606 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3607 struct arm_instruction
*instruction
, char *cp
)
3609 int rn
= (opcode
>> 16) & 0xf;
3610 int op
= (opcode
>> 22) & 0x6;
3611 int t
= (opcode
>> 21) & 1;
3612 unsigned registers
= opcode
& 0xffff;
3615 if (opcode
& (1 << 20))
3623 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3625 (unsigned) (opcode
& 0x1f));
3631 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3632 (unsigned) ((opcode
>> 16) & 0xf),
3636 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3640 sprintf(cp
, "POP.W\t");
3642 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3646 sprintf(cp
, "PUSH.W\t");
3648 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3651 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3654 return ERROR_COMMAND_SYNTAX_ERROR
;
3659 for (t
= 0; registers
; t
++, registers
>>= 1) {
3660 if ((registers
& 1) == 0)
3663 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3672 /* load/store dual or exclusive, table branch */
3673 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3674 struct arm_instruction
*instruction
, char *cp
)
3676 unsigned op1op2
= (opcode
>> 20) & 0x3;
3677 unsigned op3
= (opcode
>> 4) & 0xf;
3679 unsigned rn
= (opcode
>> 16) & 0xf;
3680 unsigned rt
= (opcode
>> 12) & 0xf;
3681 unsigned rd
= (opcode
>> 8) & 0xf;
3682 unsigned imm
= opcode
& 0xff;
3686 op1op2
|= (opcode
>> 21) & 0xc;
3716 mnemonic
= "STREXB";
3719 mnemonic
= "STREXH";
3722 return ERROR_COMMAND_SYNTAX_ERROR
;
3730 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3733 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3736 mnemonic
= "LDREXB";
3739 mnemonic
= "LDREXH";
3742 return ERROR_COMMAND_SYNTAX_ERROR
;
3747 return ERROR_COMMAND_SYNTAX_ERROR
;
3752 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3753 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3755 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3756 mnemonic
, rd
, rt
, rn
);
3762 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3763 mnemonic
, rt
, rn
, imm
, imm
);
3765 sprintf(cp
, "%s\tr%u, [r%u]",
3770 /* two indexed modes will write back rn */
3771 if (opcode
& (1 << 21)) {
3772 if (opcode
& (1 << 24)) /* pre-indexed */
3774 else { /* post-indexed */
3781 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3782 mnemonic
, rt
, rd
, rn
, p1
,
3783 (opcode
& (1 << 23)) ? "" : "-",
3788 address
= thumb_alignpc4(address
);
3790 if (opcode
& (1 << 23))
3794 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3795 mnemonic
, rt
, rd
, address
);
3799 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3800 struct arm_instruction
*instruction
, char *cp
)
3802 int op
= (opcode
>> 21) & 0xf;
3803 int rd
= (opcode
>> 8) & 0xf;
3804 int rn
= (opcode
>> 16) & 0xf;
3805 int type
= (opcode
>> 4) & 0x3;
3806 int immed
= (opcode
>> 6) & 0x3;
3810 immed
|= (opcode
>> 10) & 0x1c;
3811 if (opcode
& (1 << 20))
3817 if (!(opcode
& (1 << 20)))
3818 return ERROR_COMMAND_SYNTAX_ERROR
;
3819 instruction
->type
= ARM_TST
;
3824 instruction
->type
= ARM_AND
;
3828 instruction
->type
= ARM_BIC
;
3833 instruction
->type
= ARM_MOV
;
3837 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3839 (int) (opcode
& 0xf));
3852 sprintf(cp
, "RRX%s\tr%d, r%d",
3854 (int) (opcode
& 0xf));
3862 instruction
->type
= ARM_ORR
;
3868 instruction
->type
= ARM_MVN
;
3873 /* instruction->type = ARM_ORN; */
3879 if (!(opcode
& (1 << 20)))
3880 return ERROR_COMMAND_SYNTAX_ERROR
;
3881 instruction
->type
= ARM_TEQ
;
3886 instruction
->type
= ARM_EOR
;
3891 if (!(opcode
& (1 << 20)))
3892 return ERROR_COMMAND_SYNTAX_ERROR
;
3893 instruction
->type
= ARM_CMN
;
3898 instruction
->type
= ARM_ADD
;
3902 instruction
->type
= ARM_ADC
;
3906 instruction
->type
= ARM_SBC
;
3911 if (!(opcode
& (1 << 21)))
3912 return ERROR_COMMAND_SYNTAX_ERROR
;
3913 instruction
->type
= ARM_CMP
;
3918 instruction
->type
= ARM_SUB
;
3922 instruction
->type
= ARM_RSB
;
3926 return ERROR_COMMAND_SYNTAX_ERROR
;
3929 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3930 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3953 strcpy(cp
, ", RRX");
3959 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3963 sprintf(cp
, "%s%s.W\tr%d, r%d",
3964 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3968 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3969 mnemonic
, suffix
, rd
,
3970 (int) (opcode
& 0xf), immed
? immed
: 32);
3974 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3975 struct arm_instruction
*instruction
, char *cp
)
3980 if (((opcode
>> 4) & 0xf) == 0) {
3981 switch ((opcode
>> 21) & 0x7) {
3995 return ERROR_COMMAND_SYNTAX_ERROR
;
3998 instruction
->type
= ARM_MOV
;
3999 if (opcode
& (1 << 20))
4001 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
4003 (int) (opcode
>> 8) & 0xf,
4004 (int) (opcode
>> 16) & 0xf,
4005 (int) (opcode
>> 0) & 0xf);
4007 } else if (opcode
& (1 << 7)) {
4008 switch ((opcode
>> 20) & 0xf) {
4013 switch ((opcode
>> 4) & 0x3) {
4015 suffix
= ", ROR #8";
4018 suffix
= ", ROR #16";
4021 suffix
= ", ROR #24";
4024 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
4025 (opcode
& (1 << 24)) ? 'U' : 'S',
4026 (opcode
& (1 << 26)) ? 'B' : 'H',
4027 (int) (opcode
>> 8) & 0xf,
4028 (int) (opcode
>> 0) & 0xf,
4035 if (opcode
& (1 << 6))
4036 return ERROR_COMMAND_SYNTAX_ERROR
;
4037 if (((opcode
>> 12) & 0xf) != 0xf)
4038 return ERROR_COMMAND_SYNTAX_ERROR
;
4039 if (!(opcode
& (1 << 20)))
4040 return ERROR_COMMAND_SYNTAX_ERROR
;
4042 switch (((opcode
>> 19) & 0x04)
4043 | ((opcode
>> 4) & 0x3)) {
4048 mnemonic
= "REV16.W";
4054 mnemonic
= "REVSH.W";
4060 return ERROR_COMMAND_SYNTAX_ERROR
;
4062 sprintf(cp
, "%s\tr%d, r%d",
4064 (int) (opcode
>> 8) & 0xf,
4065 (int) (opcode
>> 0) & 0xf);
4068 return ERROR_COMMAND_SYNTAX_ERROR
;
4075 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
4076 struct arm_instruction
*instruction
, char *cp
)
4078 int rn
= (opcode
>> 16) & 0xf;
4081 instruction
->type
= ARM_LDR
;
4084 immed
= opcode
& 0x0fff;
4085 if ((opcode
& (1 << 23)) == 0)
4087 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4088 (int) (opcode
>> 12) & 0xf,
4089 thumb_alignpc4(address
) + immed
);
4093 if (opcode
& (1 << 23)) {
4094 immed
= opcode
& 0x0fff;
4095 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4096 (int) (opcode
>> 12) & 0xf,
4101 if (!(opcode
& (0x3f << 6))) {
4102 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4103 (int) (opcode
>> 12) & 0xf,
4105 (int) (opcode
>> 0) & 0xf,
4106 (int) (opcode
>> 4) & 0x3);
4111 if (((opcode
>> 8) & 0xf) == 0xe) {
4112 immed
= opcode
& 0x00ff;
4114 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4115 (int) (opcode
>> 12) & 0xf,
4120 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4121 char *p1
= "]", *p2
= "";
4123 if (!(opcode
& 0x0500))
4124 return ERROR_COMMAND_SYNTAX_ERROR
;
4126 immed
= opcode
& 0x00ff;
4128 /* two indexed modes will write back rn */
4129 if (opcode
& 0x100) {
4130 if (opcode
& 0x400) /* pre-indexed */
4132 else { /* post-indexed */
4138 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4139 (int) (opcode
>> 12) & 0xf,
4141 (opcode
& 0x200) ? "" : "-",
4146 return ERROR_COMMAND_SYNTAX_ERROR
;
4149 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4150 struct arm_instruction
*instruction
, char *cp
)
4152 int rn
= (opcode
>> 16) & 0xf;
4153 int rt
= (opcode
>> 12) & 0xf;
4154 int op2
= (opcode
>> 6) & 0x3f;
4156 char *p1
= "", *p2
= "]";
4159 switch ((opcode
>> 23) & 0x3) {
4161 if ((rn
& rt
) == 0xf) {
4163 immed
= opcode
& 0xfff;
4164 address
= thumb_alignpc4(address
);
4165 if (opcode
& (1 << 23))
4169 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4173 if (rn
== 0x0f && rt
!= 0x0f) {
4175 immed
= opcode
& 0xfff;
4176 address
= thumb_alignpc4(address
);
4177 if (opcode
& (1 << 23))
4181 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4187 if ((op2
& 0x3c) == 0x38) {
4188 immed
= opcode
& 0xff;
4189 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4190 rt
, rn
, immed
, immed
);
4193 if ((op2
& 0x3c) == 0x30) {
4195 immed
= opcode
& 0xff;
4198 p1
= (opcode
& (1 << 21)) ? "W" : "";
4199 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4200 p1
, rn
, immed
, immed
);
4205 immed
= opcode
& 0xff;
4206 if (!(opcode
& 0x200))
4209 /* two indexed modes will write back rn */
4210 if (opcode
& 0x100) {
4211 if (opcode
& 0x400) /* pre-indexed */
4213 else { /* post-indexed */
4219 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4220 mnemonic
, rt
, rn
, p1
,
4224 if ((op2
& 0x24) == 0x24) {
4226 goto ldrxb_immediate_t3
;
4229 int rm
= opcode
& 0xf;
4232 sprintf(cp
, "PLD\t");
4234 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4235 immed
= (opcode
>> 4) & 0x3;
4237 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4242 if ((rn
& rt
) == 0xf)
4245 immed
= opcode
& 0xfff;
4246 goto preload_immediate
;
4250 mnemonic
= "LDRB.W";
4251 immed
= opcode
& 0xfff;
4252 goto ldrxb_immediate_t2
;
4254 if ((rn
& rt
) == 0xf) {
4255 immed
= opcode
& 0xfff;
4256 address
= thumb_alignpc4(address
);
4257 if (opcode
& (1 << 23))
4261 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4264 if (rn
== 0xf && rt
!= 0xf) {
4266 immed
= opcode
& 0xfff;
4267 address
= thumb_alignpc4(address
);
4268 if (opcode
& (1 << 23))
4272 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4277 if ((op2
& 0x3c) == 0x38) {
4278 immed
= opcode
& 0xff;
4279 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4280 rt
, rn
, immed
, immed
);
4283 if ((op2
& 0x3c) == 0x30) {
4285 immed
= opcode
& 0xff;
4286 immed
= -immed
; /* pli */
4287 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4292 goto ldrxb_immediate_t3
;
4294 if ((op2
& 0x24) == 0x24) {
4296 goto ldrxb_immediate_t3
;
4299 int rm
= opcode
& 0xf;
4302 sprintf(cp
, "PLI\t");
4304 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4305 immed
= (opcode
>> 4) & 0x3;
4307 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4313 immed
= opcode
& 0xfff;
4314 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4320 immed
= opcode
& 0xfff;
4322 goto ldrxb_immediate_t2
;
4325 return ERROR_COMMAND_SYNTAX_ERROR
;
4328 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4329 struct arm_instruction
*instruction
, char *cp
)
4331 int rn
= (opcode
>> 16) & 0xf;
4332 int rt
= (opcode
>> 12) & 0xf;
4333 int op2
= (opcode
>> 6) & 0x3f;
4338 sprintf(cp
, "HINT (UNALLOCATED)");
4342 if (opcode
& (1 << 24))
4345 if ((opcode
& (1 << 23)) == 0) {
4348 immed
= opcode
& 0xfff;
4349 address
= thumb_alignpc4(address
);
4350 if (opcode
& (1 << 23))
4354 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4359 int rm
= opcode
& 0xf;
4361 immed
= (opcode
>> 4) & 0x3;
4362 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4363 sign
, rt
, rn
, rm
, immed
);
4366 if ((op2
& 0x3c) == 0x38) {
4367 immed
= opcode
& 0xff;
4368 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4369 sign
, rt
, rn
, immed
, immed
);
4372 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4373 char *p1
= "", *p2
= "]";
4375 immed
= opcode
& 0xff;
4376 if (!(opcode
& 0x200))
4379 /* two indexed modes will write back rn */
4380 if (opcode
& 0x100) {
4381 if (opcode
& 0x400) /* pre-indexed */
4383 else { /* post-indexed */
4388 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4389 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4396 immed
= opcode
& 0xfff;
4397 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4398 sign
, *sign
? "" : ".W",
4399 rt
, rn
, immed
, immed
);
4403 return ERROR_COMMAND_SYNTAX_ERROR
;
4407 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4408 * always set. That means eventual arm_simulate_step() support for Thumb2
4409 * will need work in this area.
4411 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4418 /* clear low bit ... it's set on function pointers */
4421 /* clear fields, to avoid confusion */
4422 memset(instruction
, 0, sizeof(struct arm_instruction
));
4424 /* read first halfword, see if this is the only one */
4425 retval
= target_read_u16(target
, address
, &op
);
4426 if (retval
!= ERROR_OK
)
4429 switch (op
& 0xf800) {
4433 /* 32-bit instructions */
4434 instruction
->instruction_size
= 4;
4436 retval
= target_read_u16(target
, address
+ 2, &op
);
4437 if (retval
!= ERROR_OK
)
4440 instruction
->opcode
= opcode
;
4443 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4444 return thumb_evaluate_opcode(op
, address
, instruction
);
4447 snprintf(instruction
->text
, 128,
4448 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4450 cp
= strchr(instruction
->text
, 0);
4451 retval
= ERROR_FAIL
;
4453 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4454 if ((opcode
& 0x1a008000) == 0x10000000)
4455 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4457 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4458 else if ((opcode
& 0x1a008000) == 0x12000000)
4459 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4461 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4462 else if ((opcode
& 0x18008000) == 0x10008000)
4463 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4465 /* ARMv7-M: A5.3.5 Load/store multiple */
4466 else if ((opcode
& 0x1e400000) == 0x08000000)
4467 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4469 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4470 else if ((opcode
& 0x1e400000) == 0x08400000)
4471 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4473 /* ARMv7-M: A5.3.7 Load word */
4474 else if ((opcode
& 0x1f700000) == 0x18500000)
4475 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4477 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4478 else if ((opcode
& 0x1e700000) == 0x18300000)
4479 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4481 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4482 else if ((opcode
& 0x1e700000) == 0x18100000)
4483 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4485 /* ARMv7-M: A5.3.10 Store single data item */
4486 else if ((opcode
& 0x1f100000) == 0x18000000)
4487 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4489 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4490 else if ((opcode
& 0x1e000000) == 0x0a000000)
4491 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4493 /* ARMv7-M: A5.3.12 Data processing (register)
4494 * and A5.3.13 Miscellaneous operations
4496 else if ((opcode
& 0x1f000000) == 0x1a000000)
4497 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4499 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4500 else if ((opcode
& 0x1f800000) == 0x1b000000)
4501 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4503 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4504 else if ((opcode
& 0x1f800000) == 0x1b800000)
4505 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4507 if (retval
== ERROR_OK
)
4511 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4512 * instructions; not yet handled here.
4515 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4516 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4517 strcpy(cp
, "UNDEFINED OPCODE");
4521 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4524 strcpy(cp
, "(32-bit Thumb2 ...)");
4528 int arm_access_size(struct arm_instruction
*instruction
)
4530 if ((instruction
->type
== ARM_LDRB
)
4531 || (instruction
->type
== ARM_LDRBT
)
4532 || (instruction
->type
== ARM_LDRSB
)
4533 || (instruction
->type
== ARM_STRB
)
4534 || (instruction
->type
== ARM_STRBT
))
4536 else if ((instruction
->type
== ARM_LDRH
)
4537 || (instruction
->type
== ARM_LDRSH
)
4538 || (instruction
->type
== ARM_STRH
))
4540 else if ((instruction
->type
== ARM_LDR
)
4541 || (instruction
->type
== ARM_LDRT
)
4542 || (instruction
->type
== ARM_STR
)
4543 || (instruction
->type
== ARM_STRT
))
4545 else if ((instruction
->type
== ARM_LDRD
)
4546 || (instruction
->type
== ARM_STRD
))
4549 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)