1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
27 #include "arm_disassembler.h"
28 #include <helper/log.h>
32 * This disassembler supports two main functions for OpenOCD:
34 * - Various "disassemble" commands. OpenOCD can serve as a
35 * machine-language debugger, without help from GDB.
37 * - Single stepping. Not all ARM cores support hardware single
38 * stepping. To work without that support, the debugger must
39 * be able to decode instructions to find out where to put a
40 * "next instruction" breakpoint.
42 * In addition, interpretation of ETM trace data needs some of the
43 * decoding mechanisms.
45 * At this writing (September 2009) neither function is complete.
48 * * Old-style syntax (not UAL) is generally used
49 * * VFP instructions are not understood (ARMv5 and later)
50 * except as coprocessor 10/11 operations
51 * * Most ARM instructions through ARMv6 are decoded, but some
52 * of the post-ARMv4 opcodes may not be handled yet
53 * * NEON instructions are not understood (ARMv7-A)
55 * - Thumb/Thumb2 decoding
56 * * UAL syntax should be consistently used
57 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
58 * be handled properly. Accordingly, so should the subset
59 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
61 * * Conditional effects of Thumb2 "IT" (if-then) instructions
62 * are not handled: the affected instructions are not shown
63 * with their now-conditional suffixes.
64 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
65 * handled (minimally for coprocessor access).
66 * * SIMD instructions, and some other Thumb2 instructions
67 * from ARMv7-A, are not understood.
70 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
71 * * Opcodes changed by ThumbEE mode are not handled; these
72 * instructions wrongly decode as LDM and STM.
74 * - Jazelle decoding ... no support whatsoever for Jazelle mode
75 * or decoding. ARM encourages use of the more generic ThumbEE
76 * mode, instead of Jazelle mode, in current chips.
78 * - Single-step/emulation ... spotty support, which is only weakly
79 * tested. Thumb2 is not supported. (Arguably a full simulator
80 * is not needed to support just single stepping. Recognizing
81 * branch vs non-branch instructions suffices, except when the
82 * instruction faults and triggers a synchronous exception which
83 * can be intercepted using other means.)
85 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
86 * ARM v7-R edition" gives the most complete coverage of the various
87 * generations of ARM instructions. At this writing it is publicly
88 * accessible to anyone willing to create an account at the ARM
89 * web site; see http://www.arm.com/documentation/ for information.
91 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
92 * more details relevant to the Thumb2-only processors (such as
93 * the Cortex-M implementations).
96 /* textual represenation of the condition field */
97 /* ALways (default) is ommitted (empty string) */
98 static const char *arm_condition_strings
[] =
100 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
103 /* make up for C's missing ROR */
104 static uint32_t ror(uint32_t value
, int places
)
106 return (value
>> places
) | (value
<< (32 - places
));
109 static int evaluate_unknown(uint32_t opcode
,
110 uint32_t address
, struct arm_instruction
*instruction
)
112 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
113 snprintf(instruction
->text
, 128,
114 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
115 "\tUNDEFINED INSTRUCTION", address
, opcode
);
119 static int evaluate_pld(uint32_t opcode
,
120 uint32_t address
, struct arm_instruction
*instruction
)
123 if ((opcode
& 0x0d70f000) == 0x0550f000)
125 instruction
->type
= ARM_PLD
;
127 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
131 return evaluate_unknown(opcode
, address
, instruction
);
134 static int evaluate_srs(uint32_t opcode
,
135 uint32_t address
, struct arm_instruction
*instruction
)
137 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
138 const char *mode
= "";
140 switch ((opcode
>> 23) & 0x3) {
145 /* "IA" is default */
155 switch (opcode
& 0x0e500000) {
157 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
159 "\tSRS%s\tSP%s, #%d",
162 (unsigned)(opcode
& 0x1f));
165 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
170 (unsigned)((opcode
>> 16) & 0xf), wback
);
173 return evaluate_unknown(opcode
, address
, instruction
);
178 static int evaluate_swi(uint32_t opcode
,
179 uint32_t address
, struct arm_instruction
*instruction
)
181 instruction
->type
= ARM_SWI
;
183 snprintf(instruction
->text
, 128,
184 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
185 address
, opcode
, (opcode
& 0xffffff));
190 static int evaluate_blx_imm(uint32_t opcode
,
191 uint32_t address
, struct arm_instruction
*instruction
)
195 uint32_t target_address
;
197 instruction
->type
= ARM_BLX
;
198 immediate
= opcode
& 0x00ffffff;
200 /* sign extend 24-bit immediate */
201 if (immediate
& 0x00800000)
202 offset
= 0xff000000 | immediate
;
206 /* shift two bits left */
209 /* odd/event halfword */
210 if (opcode
& 0x01000000)
213 target_address
= address
+ 8 + offset
;
215 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
217 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
218 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
223 static int evaluate_b_bl(uint32_t opcode
,
224 uint32_t address
, struct arm_instruction
*instruction
)
229 uint32_t target_address
;
231 immediate
= opcode
& 0x00ffffff;
232 L
= (opcode
& 0x01000000) >> 24;
234 /* sign extend 24-bit immediate */
235 if (immediate
& 0x00800000)
236 offset
= 0xff000000 | immediate
;
240 /* shift two bits left */
243 target_address
= address
+ 8 + offset
;
246 instruction
->type
= ARM_BL
;
248 instruction
->type
= ARM_B
;
250 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
251 (L
) ? "L" : "", COND(opcode
), target_address
);
253 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
254 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
259 /* Coprocessor load/store and double register transfers */
260 /* both normal and extended instruction space (condition field b1111) */
261 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
262 uint32_t address
, struct arm_instruction
*instruction
)
264 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
267 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
269 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
272 cp_opcode
= (opcode
& 0xf0) >> 4;
273 Rd
= (opcode
& 0xf000) >> 12;
274 Rn
= (opcode
& 0xf0000) >> 16;
275 CRm
= (opcode
& 0xf);
278 if ((opcode
& 0x0ff00000) == 0x0c400000)
280 instruction
->type
= ARM_MCRR
;
285 if ((opcode
& 0x0ff00000) == 0x0c500000)
287 instruction
->type
= ARM_MRRC
;
291 snprintf(instruction
->text
, 128,
292 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
293 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
294 address
, opcode
, mnemonic
,
295 ((opcode
& 0xf0000000) == 0xf0000000)
296 ? "2" : COND(opcode
),
297 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
299 else /* LDC or STC */
301 uint8_t CRd
, Rn
, offset
;
304 char addressing_mode
[32];
306 CRd
= (opcode
& 0xf000) >> 12;
307 Rn
= (opcode
& 0xf0000) >> 16;
308 offset
= (opcode
& 0xff) << 2;
311 if (opcode
& 0x00100000)
313 instruction
->type
= ARM_LDC
;
318 instruction
->type
= ARM_STC
;
322 U
= (opcode
& 0x00800000) >> 23;
323 N
= (opcode
& 0x00400000) >> 22;
325 /* addressing modes */
326 if ((opcode
& 0x01200000) == 0x01000000) /* offset */
327 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
328 Rn
, U
? "" : "-", offset
);
329 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
330 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
331 Rn
, U
? "" : "-", offset
);
332 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
333 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
334 Rn
, U
? "" : "-", offset
);
335 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
336 snprintf(addressing_mode
, 32, "[r%i], {%d}",
339 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
341 "\t%s%s%s p%i, c%i, %s",
342 address
, opcode
, mnemonic
,
343 ((opcode
& 0xf0000000) == 0xf0000000)
344 ? "2" : COND(opcode
),
345 (opcode
& (1 << 22)) ? "L" : "",
346 cp_num
, CRd
, addressing_mode
);
352 /* Coprocessor data processing instructions */
353 /* Coprocessor register transfer instructions */
354 /* both normal and extended instruction space (condition field b1111) */
355 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
356 uint32_t address
, struct arm_instruction
*instruction
)
360 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
362 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
363 cp_num
= (opcode
& 0xf00) >> 8;
364 CRd_Rd
= (opcode
& 0xf000) >> 12;
365 CRn
= (opcode
& 0xf0000) >> 16;
366 CRm
= (opcode
& 0xf);
367 opcode_2
= (opcode
& 0xe0) >> 5;
370 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
372 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
374 instruction
->type
= ARM_MRC
;
377 else /* bit 20 not set -> MCR */
379 instruction
->type
= ARM_MCR
;
383 opcode_1
= (opcode
& 0x00e00000) >> 21;
385 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
386 address
, opcode
, mnemonic
, cond
,
387 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
389 else /* bit 4 not set -> CDP */
391 instruction
->type
= ARM_CDP
;
394 opcode_1
= (opcode
& 0x00f00000) >> 20;
396 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
397 address
, opcode
, mnemonic
, cond
,
398 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
404 /* Load/store instructions */
405 static int evaluate_load_store(uint32_t opcode
,
406 uint32_t address
, struct arm_instruction
*instruction
)
408 uint8_t I
, P
, U
, B
, W
, L
;
410 char *operation
; /* "LDR" or "STR" */
411 char *suffix
; /* "", "B", "T", "BT" */
415 I
= (opcode
& 0x02000000) >> 25;
416 P
= (opcode
& 0x01000000) >> 24;
417 U
= (opcode
& 0x00800000) >> 23;
418 B
= (opcode
& 0x00400000) >> 22;
419 W
= (opcode
& 0x00200000) >> 21;
420 L
= (opcode
& 0x00100000) >> 20;
422 /* target register */
423 Rd
= (opcode
& 0xf000) >> 12;
426 Rn
= (opcode
& 0xf0000) >> 16;
428 instruction
->info
.load_store
.Rd
= Rd
;
429 instruction
->info
.load_store
.Rn
= Rn
;
430 instruction
->info
.load_store
.U
= U
;
432 /* determine operation */
438 /* determine instruction type and suffix */
441 if ((P
== 0) && (W
== 1))
444 instruction
->type
= ARM_LDRBT
;
446 instruction
->type
= ARM_STRBT
;
452 instruction
->type
= ARM_LDRB
;
454 instruction
->type
= ARM_STRB
;
460 if ((P
== 0) && (W
== 1))
463 instruction
->type
= ARM_LDRT
;
465 instruction
->type
= ARM_STRT
;
471 instruction
->type
= ARM_LDR
;
473 instruction
->type
= ARM_STR
;
478 if (!I
) /* #+-<offset_12> */
480 uint32_t offset_12
= (opcode
& 0xfff);
482 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
484 snprintf(offset
, 32, "%s", "");
486 instruction
->info
.load_store
.offset_mode
= 0;
487 instruction
->info
.load_store
.offset
.offset
= offset_12
;
489 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
491 uint8_t shift_imm
, shift
;
494 shift_imm
= (opcode
& 0xf80) >> 7;
495 shift
= (opcode
& 0x60) >> 5;
498 /* LSR encodes a shift by 32 bit as 0x0 */
499 if ((shift
== 0x1) && (shift_imm
== 0x0))
502 /* ASR encodes a shift by 32 bit as 0x0 */
503 if ((shift
== 0x2) && (shift_imm
== 0x0))
506 /* ROR by 32 bit is actually a RRX */
507 if ((shift
== 0x3) && (shift_imm
== 0x0))
510 instruction
->info
.load_store
.offset_mode
= 1;
511 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
512 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
513 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
515 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
517 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
519 else /* +-<Rm>, <Shift>, #<shift_imm> */
524 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
527 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
530 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
533 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
536 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
544 if (W
== 0) /* offset */
546 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
547 address
, opcode
, operation
, COND(opcode
), suffix
,
550 instruction
->info
.load_store
.index_mode
= 0;
552 else /* pre-indexed */
554 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
555 address
, opcode
, operation
, COND(opcode
), suffix
,
558 instruction
->info
.load_store
.index_mode
= 1;
561 else /* post-indexed */
563 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
564 address
, opcode
, operation
, COND(opcode
), suffix
,
567 instruction
->info
.load_store
.index_mode
= 2;
573 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
575 unsigned rm
= (opcode
>> 0) & 0xf;
576 unsigned rd
= (opcode
>> 12) & 0xf;
577 unsigned rn
= (opcode
>> 16) & 0xf;
580 switch ((opcode
>> 24) & 0x3) {
585 sprintf(cp
, "UNDEFINED");
586 return ARM_UNDEFINED_INSTRUCTION
;
595 switch ((opcode
>> 10) & 0x3) {
611 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
612 (opcode
& (1 << 22)) ? 'U' : 'S',
617 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
618 (opcode
& (1 << 22)) ? 'U' : 'S',
625 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
631 switch ((opcode
>> 20) & 0x7) {
654 switch ((opcode
>> 5) & 0x7) {
683 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
684 (int) (opcode
>> 12) & 0xf,
685 (int) (opcode
>> 16) & 0xf,
686 (int) (opcode
>> 0) & 0xf);
690 /* these opcodes might be used someday */
691 sprintf(cp
, "UNDEFINED");
692 return ARM_UNDEFINED_INSTRUCTION
;
695 /* ARMv6 and later support "media" instructions (includes SIMD) */
696 static int evaluate_media(uint32_t opcode
, uint32_t address
,
697 struct arm_instruction
*instruction
)
699 char *cp
= instruction
->text
;
700 char *mnemonic
= NULL
;
703 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
707 /* parallel add/subtract */
708 if ((opcode
& 0x01800000) == 0x00000000) {
709 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
714 if ((opcode
& 0x01f00020) == 0x00800000) {
716 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
718 if (opcode
& (1 << 6)) {
727 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
729 (int) (opcode
>> 12) & 0xf,
730 (int) (opcode
>> 16) & 0xf,
731 (int) (opcode
>> 0) & 0xf,
737 if ((opcode
& 0x01a00020) == 0x00a00000) {
739 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
741 if (opcode
& (1 << 6)) {
749 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
750 (opcode
& (1 << 22)) ? 'U' : 'S',
752 (int) (opcode
>> 12) & 0xf,
753 (int) (opcode
>> 16) & 0x1f,
754 (int) (opcode
>> 0) & 0xf,
760 if ((opcode
& 0x018000f0) == 0x00800070) {
761 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
766 if ((opcode
& 0x01f00080) == 0x01000000) {
767 unsigned rn
= (opcode
>> 12) & 0xf;
770 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
771 (opcode
& (1 << 6)) ? 'S' : 'A',
772 (opcode
& (1 << 5)) ? "X" : "",
774 (int) (opcode
>> 16) & 0xf,
775 (int) (opcode
>> 0) & 0xf,
776 (int) (opcode
>> 8) & 0xf,
779 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
780 (opcode
& (1 << 6)) ? 'S' : 'A',
781 (opcode
& (1 << 5)) ? "X" : "",
783 (int) (opcode
>> 16) & 0xf,
784 (int) (opcode
>> 0) & 0xf,
785 (int) (opcode
>> 8) & 0xf);
788 if ((opcode
& 0x01f00000) == 0x01400000) {
789 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
790 (opcode
& (1 << 6)) ? 'S' : 'A',
791 (opcode
& (1 << 5)) ? "X" : "",
793 (int) (opcode
>> 12) & 0xf,
794 (int) (opcode
>> 16) & 0xf,
795 (int) (opcode
>> 0) & 0xf,
796 (int) (opcode
>> 8) & 0xf);
799 if ((opcode
& 0x01f00000) == 0x01500000) {
800 unsigned rn
= (opcode
>> 12) & 0xf;
802 switch (opcode
& 0xc0) {
814 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
815 (opcode
& (1 << 6)) ? 'S' : 'A',
816 (opcode
& (1 << 5)) ? "R" : "",
818 (int) (opcode
>> 16) & 0xf,
819 (int) (opcode
>> 0) & 0xf,
820 (int) (opcode
>> 8) & 0xf,
823 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
824 (opcode
& (1 << 5)) ? "R" : "",
826 (int) (opcode
>> 16) & 0xf,
827 (int) (opcode
>> 0) & 0xf,
828 (int) (opcode
>> 8) & 0xf);
833 /* simple matches against the remaining decode bits */
834 switch (opcode
& 0x01f000f0) {
837 /* parallel halfword saturate */
838 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
839 (opcode
& (1 << 22)) ? 'U' : 'S',
841 (int) (opcode
>> 12) & 0xf,
842 (int) (opcode
>> 16) & 0xf,
843 (int) (opcode
>> 0) & 0xf);
856 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
857 (int) (opcode
>> 12) & 0xf,
858 (int) (opcode
>> 16) & 0xf,
859 (int) (opcode
>> 0) & 0xf);
862 /* unsigned sum of absolute differences */
863 if (((opcode
>> 12) & 0xf) == 0xf)
864 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
865 (int) (opcode
>> 16) & 0xf,
866 (int) (opcode
>> 0) & 0xf,
867 (int) (opcode
>> 8) & 0xf);
869 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
870 (int) (opcode
>> 16) & 0xf,
871 (int) (opcode
>> 0) & 0xf,
872 (int) (opcode
>> 8) & 0xf,
873 (int) (opcode
>> 12) & 0xf);
877 unsigned rm
= (opcode
>> 0) & 0xf;
878 unsigned rd
= (opcode
>> 12) & 0xf;
880 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
885 /* these opcodes might be used someday */
886 sprintf(cp
, "UNDEFINED");
890 /* Miscellaneous load/store instructions */
891 static int evaluate_misc_load_store(uint32_t opcode
,
892 uint32_t address
, struct arm_instruction
*instruction
)
894 uint8_t P
, U
, I
, W
, L
, S
, H
;
896 char *operation
; /* "LDR" or "STR" */
897 char *suffix
; /* "H", "SB", "SH", "D" */
901 P
= (opcode
& 0x01000000) >> 24;
902 U
= (opcode
& 0x00800000) >> 23;
903 I
= (opcode
& 0x00400000) >> 22;
904 W
= (opcode
& 0x00200000) >> 21;
905 L
= (opcode
& 0x00100000) >> 20;
906 S
= (opcode
& 0x00000040) >> 6;
907 H
= (opcode
& 0x00000020) >> 5;
909 /* target register */
910 Rd
= (opcode
& 0xf000) >> 12;
913 Rn
= (opcode
& 0xf0000) >> 16;
915 instruction
->info
.load_store
.Rd
= Rd
;
916 instruction
->info
.load_store
.Rn
= Rn
;
917 instruction
->info
.load_store
.U
= U
;
919 /* determine instruction type and suffix */
927 instruction
->type
= ARM_LDRSH
;
933 instruction
->type
= ARM_LDRSB
;
937 else /* there are no signed stores, so this is used to encode double-register load/stores */
943 instruction
->type
= ARM_STRD
;
948 instruction
->type
= ARM_LDRD
;
958 instruction
->type
= ARM_LDRH
;
963 instruction
->type
= ARM_STRH
;
967 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
969 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
970 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
972 instruction
->info
.load_store
.offset_mode
= 0;
973 instruction
->info
.load_store
.offset
.offset
= offset_8
;
975 else /* Register offset/index (+-<Rm>) */
979 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
981 instruction
->info
.load_store
.offset_mode
= 1;
982 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
983 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
984 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
989 if (W
== 0) /* offset */
991 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
992 address
, opcode
, operation
, COND(opcode
), suffix
,
995 instruction
->info
.load_store
.index_mode
= 0;
997 else /* pre-indexed */
999 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1000 address
, opcode
, operation
, COND(opcode
), suffix
,
1003 instruction
->info
.load_store
.index_mode
= 1;
1006 else /* post-indexed */
1008 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1009 address
, opcode
, operation
, COND(opcode
), suffix
,
1012 instruction
->info
.load_store
.index_mode
= 2;
1018 /* Load/store multiples instructions */
1019 static int evaluate_ldm_stm(uint32_t opcode
,
1020 uint32_t address
, struct arm_instruction
*instruction
)
1022 uint8_t P
, U
, S
, W
, L
, Rn
;
1023 uint32_t register_list
;
1024 char *addressing_mode
;
1031 P
= (opcode
& 0x01000000) >> 24;
1032 U
= (opcode
& 0x00800000) >> 23;
1033 S
= (opcode
& 0x00400000) >> 22;
1034 W
= (opcode
& 0x00200000) >> 21;
1035 L
= (opcode
& 0x00100000) >> 20;
1036 register_list
= (opcode
& 0xffff);
1037 Rn
= (opcode
& 0xf0000) >> 16;
1039 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1040 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1041 instruction
->info
.load_store_multiple
.S
= S
;
1042 instruction
->info
.load_store_multiple
.W
= W
;
1046 instruction
->type
= ARM_LDM
;
1051 instruction
->type
= ARM_STM
;
1059 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1060 addressing_mode
= "IB";
1064 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1065 addressing_mode
= "DB";
1072 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1073 /* "IA" is the default in UAL syntax */
1074 addressing_mode
= "";
1078 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1079 addressing_mode
= "DA";
1083 reg_list_p
= reg_list
;
1084 for (i
= 0; i
<= 15; i
++)
1086 if ((register_list
>> i
) & 1)
1091 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1095 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1100 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
1101 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
1102 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1107 /* Multiplies, extra load/stores */
1108 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1109 uint32_t address
, struct arm_instruction
*instruction
)
1111 /* Multiply (accumulate) (long) and Swap/swap byte */
1112 if ((opcode
& 0x000000f0) == 0x00000090)
1114 /* Multiply (accumulate) */
1115 if ((opcode
& 0x0f800000) == 0x00000000)
1117 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1119 Rs
= (opcode
& 0xf00) >> 8;
1120 Rn
= (opcode
& 0xf000) >> 12;
1121 Rd
= (opcode
& 0xf0000) >> 16;
1122 S
= (opcode
& 0x00100000) >> 20;
1124 /* examine A bit (accumulate) */
1125 if (opcode
& 0x00200000)
1127 instruction
->type
= ARM_MLA
;
1128 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1129 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1133 instruction
->type
= ARM_MUL
;
1134 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1135 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1141 /* Multiply (accumulate) long */
1142 if ((opcode
& 0x0f800000) == 0x00800000)
1144 char* mnemonic
= NULL
;
1145 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1147 Rs
= (opcode
& 0xf00) >> 8;
1148 RdHi
= (opcode
& 0xf000) >> 12;
1149 RdLow
= (opcode
& 0xf0000) >> 16;
1150 S
= (opcode
& 0x00100000) >> 20;
1152 switch ((opcode
& 0x00600000) >> 21)
1155 instruction
->type
= ARM_UMULL
;
1159 instruction
->type
= ARM_UMLAL
;
1163 instruction
->type
= ARM_SMULL
;
1167 instruction
->type
= ARM_SMLAL
;
1172 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1173 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1174 RdLow
, RdHi
, Rm
, Rs
);
1179 /* Swap/swap byte */
1180 if ((opcode
& 0x0f800000) == 0x01000000)
1184 Rd
= (opcode
& 0xf000) >> 12;
1185 Rn
= (opcode
& 0xf0000) >> 16;
1187 /* examine B flag */
1188 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1190 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1191 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1197 return evaluate_misc_load_store(opcode
, address
, instruction
);
1200 static int evaluate_mrs_msr(uint32_t opcode
,
1201 uint32_t address
, struct arm_instruction
*instruction
)
1203 int R
= (opcode
& 0x00400000) >> 22;
1204 char *PSR
= (R
) ? "SPSR" : "CPSR";
1206 /* Move register to status register (MSR) */
1207 if (opcode
& 0x00200000)
1209 instruction
->type
= ARM_MSR
;
1211 /* immediate variant */
1212 if (opcode
& 0x02000000)
1214 uint8_t immediate
= (opcode
& 0xff);
1215 uint8_t rotate
= (opcode
& 0xf00);
1217 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1218 address
, opcode
, COND(opcode
), PSR
,
1219 (opcode
& 0x10000) ? "c" : "",
1220 (opcode
& 0x20000) ? "x" : "",
1221 (opcode
& 0x40000) ? "s" : "",
1222 (opcode
& 0x80000) ? "f" : "",
1223 ror(immediate
, (rotate
* 2))
1226 else /* register variant */
1228 uint8_t Rm
= opcode
& 0xf;
1229 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1230 address
, opcode
, COND(opcode
), PSR
,
1231 (opcode
& 0x10000) ? "c" : "",
1232 (opcode
& 0x20000) ? "x" : "",
1233 (opcode
& 0x40000) ? "s" : "",
1234 (opcode
& 0x80000) ? "f" : "",
1240 else /* Move status register to register (MRS) */
1244 instruction
->type
= ARM_MRS
;
1245 Rd
= (opcode
& 0x0000f000) >> 12;
1247 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1248 address
, opcode
, COND(opcode
), Rd
, PSR
);
1254 /* Miscellaneous instructions */
1255 static int evaluate_misc_instr(uint32_t opcode
,
1256 uint32_t address
, struct arm_instruction
*instruction
)
1259 if ((opcode
& 0x000000f0) == 0x00000000)
1261 evaluate_mrs_msr(opcode
, address
, instruction
);
1265 if ((opcode
& 0x006000f0) == 0x00200010)
1268 instruction
->type
= ARM_BX
;
1271 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1272 address
, opcode
, COND(opcode
), Rm
);
1274 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1275 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1278 /* BXJ - "Jazelle" support (ARMv5-J) */
1279 if ((opcode
& 0x006000f0) == 0x00200020)
1282 instruction
->type
= ARM_BX
;
1285 snprintf(instruction
->text
, 128,
1286 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1287 address
, opcode
, COND(opcode
), Rm
);
1289 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1290 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1294 if ((opcode
& 0x006000f0) == 0x00600010)
1297 instruction
->type
= ARM_CLZ
;
1299 Rd
= (opcode
& 0xf000) >> 12;
1301 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1302 address
, opcode
, COND(opcode
), Rd
, Rm
);
1306 if ((opcode
& 0x006000f0) == 0x00200030)
1309 instruction
->type
= ARM_BLX
;
1312 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1313 address
, opcode
, COND(opcode
), Rm
);
1315 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1316 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1319 /* Enhanced DSP add/subtracts */
1320 if ((opcode
& 0x0000000f0) == 0x00000050)
1323 char *mnemonic
= NULL
;
1325 Rd
= (opcode
& 0xf000) >> 12;
1326 Rn
= (opcode
& 0xf0000) >> 16;
1328 switch ((opcode
& 0x00600000) >> 21)
1331 instruction
->type
= ARM_QADD
;
1335 instruction
->type
= ARM_QSUB
;
1339 instruction
->type
= ARM_QDADD
;
1343 instruction
->type
= ARM_QDSUB
;
1348 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1349 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1352 /* Software breakpoints */
1353 if ((opcode
& 0x0000000f0) == 0x00000070)
1356 instruction
->type
= ARM_BKPT
;
1357 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1359 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1360 address
, opcode
, immediate
);
1363 /* Enhanced DSP multiplies */
1364 if ((opcode
& 0x000000090) == 0x00000080)
1366 int x
= (opcode
& 0x20) >> 5;
1367 int y
= (opcode
& 0x40) >> 6;
1370 if ((opcode
& 0x00600000) == 0x00000000)
1372 uint8_t Rd
, Rm
, Rs
, Rn
;
1373 instruction
->type
= ARM_SMLAxy
;
1374 Rd
= (opcode
& 0xf0000) >> 16;
1375 Rm
= (opcode
& 0xf);
1376 Rs
= (opcode
& 0xf00) >> 8;
1377 Rn
= (opcode
& 0xf000) >> 12;
1379 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1380 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1385 if ((opcode
& 0x00600000) == 0x00400000)
1387 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1388 instruction
->type
= ARM_SMLAxy
;
1389 RdHi
= (opcode
& 0xf0000) >> 16;
1390 RdLow
= (opcode
& 0xf000) >> 12;
1391 Rm
= (opcode
& 0xf);
1392 Rs
= (opcode
& 0xf00) >> 8;
1394 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1395 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1396 RdLow
, RdHi
, Rm
, Rs
);
1400 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1402 uint8_t Rd
, Rm
, Rs
, Rn
;
1403 instruction
->type
= ARM_SMLAWy
;
1404 Rd
= (opcode
& 0xf0000) >> 16;
1405 Rm
= (opcode
& 0xf);
1406 Rs
= (opcode
& 0xf00) >> 8;
1407 Rn
= (opcode
& 0xf000) >> 12;
1409 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1410 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1415 if ((opcode
& 0x00600000) == 0x00300000)
1418 instruction
->type
= ARM_SMULxy
;
1419 Rd
= (opcode
& 0xf0000) >> 16;
1420 Rm
= (opcode
& 0xf);
1421 Rs
= (opcode
& 0xf00) >> 8;
1423 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1424 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1429 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1432 instruction
->type
= ARM_SMULWy
;
1433 Rd
= (opcode
& 0xf0000) >> 16;
1434 Rm
= (opcode
& 0xf);
1435 Rs
= (opcode
& 0xf00) >> 8;
1437 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1438 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1446 static int evaluate_data_proc(uint32_t opcode
,
1447 uint32_t address
, struct arm_instruction
*instruction
)
1449 uint8_t I
, op
, S
, Rn
, Rd
;
1450 char *mnemonic
= NULL
;
1451 char shifter_operand
[32];
1453 I
= (opcode
& 0x02000000) >> 25;
1454 op
= (opcode
& 0x01e00000) >> 21;
1455 S
= (opcode
& 0x00100000) >> 20;
1457 Rd
= (opcode
& 0xf000) >> 12;
1458 Rn
= (opcode
& 0xf0000) >> 16;
1460 instruction
->info
.data_proc
.Rd
= Rd
;
1461 instruction
->info
.data_proc
.Rn
= Rn
;
1462 instruction
->info
.data_proc
.S
= S
;
1467 instruction
->type
= ARM_AND
;
1471 instruction
->type
= ARM_EOR
;
1475 instruction
->type
= ARM_SUB
;
1479 instruction
->type
= ARM_RSB
;
1483 instruction
->type
= ARM_ADD
;
1487 instruction
->type
= ARM_ADC
;
1491 instruction
->type
= ARM_SBC
;
1495 instruction
->type
= ARM_RSC
;
1499 instruction
->type
= ARM_TST
;
1503 instruction
->type
= ARM_TEQ
;
1507 instruction
->type
= ARM_CMP
;
1511 instruction
->type
= ARM_CMN
;
1515 instruction
->type
= ARM_ORR
;
1519 instruction
->type
= ARM_MOV
;
1523 instruction
->type
= ARM_BIC
;
1527 instruction
->type
= ARM_MVN
;
1532 if (I
) /* immediate shifter operand (#<immediate>)*/
1534 uint8_t immed_8
= opcode
& 0xff;
1535 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1538 immediate
= ror(immed_8
, rotate_imm
* 2);
1540 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1542 instruction
->info
.data_proc
.variant
= 0;
1543 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1545 else /* register-based shifter operand */
1548 shift
= (opcode
& 0x60) >> 5;
1549 Rm
= (opcode
& 0xf);
1551 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1554 shift_imm
= (opcode
& 0xf80) >> 7;
1556 instruction
->info
.data_proc
.variant
= 1;
1557 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1558 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1559 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1561 /* LSR encodes a shift by 32 bit as 0x0 */
1562 if ((shift
== 0x1) && (shift_imm
== 0x0))
1565 /* ASR encodes a shift by 32 bit as 0x0 */
1566 if ((shift
== 0x2) && (shift_imm
== 0x0))
1569 /* ROR by 32 bit is actually a RRX */
1570 if ((shift
== 0x3) && (shift_imm
== 0x0))
1573 if ((shift_imm
== 0x0) && (shift
== 0x0))
1575 snprintf(shifter_operand
, 32, "r%i", Rm
);
1579 if (shift
== 0x0) /* LSL */
1581 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1583 else if (shift
== 0x1) /* LSR */
1585 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1587 else if (shift
== 0x2) /* ASR */
1589 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1591 else if (shift
== 0x3) /* ROR */
1593 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1595 else if (shift
== 0x4) /* RRX */
1597 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1601 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1603 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1605 instruction
->info
.data_proc
.variant
= 2;
1606 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1607 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1608 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1610 if (shift
== 0x0) /* LSL */
1612 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1614 else if (shift
== 0x1) /* LSR */
1616 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1618 else if (shift
== 0x2) /* ASR */
1620 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1622 else if (shift
== 0x3) /* ROR */
1624 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1629 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1631 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1632 address
, opcode
, mnemonic
, COND(opcode
),
1633 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1635 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1637 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1638 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1640 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1641 address
, opcode
, mnemonic
, COND(opcode
),
1642 (S
) ? "S" : "", Rd
, shifter_operand
);
1644 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1646 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1647 address
, opcode
, mnemonic
, COND(opcode
),
1648 Rn
, shifter_operand
);
1654 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1655 struct arm_instruction
*instruction
)
1657 /* clear fields, to avoid confusion */
1658 memset(instruction
, 0, sizeof(struct arm_instruction
));
1659 instruction
->opcode
= opcode
;
1660 instruction
->instruction_size
= 4;
1662 /* catch opcodes with condition field [31:28] = b1111 */
1663 if ((opcode
& 0xf0000000) == 0xf0000000)
1665 /* Undefined instruction (or ARMv5E cache preload PLD) */
1666 if ((opcode
& 0x08000000) == 0x00000000)
1667 return evaluate_pld(opcode
, address
, instruction
);
1669 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1670 if ((opcode
& 0x0e000000) == 0x08000000)
1671 return evaluate_srs(opcode
, address
, instruction
);
1673 /* Branch and branch with link and change to Thumb */
1674 if ((opcode
& 0x0e000000) == 0x0a000000)
1675 return evaluate_blx_imm(opcode
, address
, instruction
);
1677 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1678 /* Coprocessor load/store and double register transfers */
1679 if ((opcode
& 0x0e000000) == 0x0c000000)
1680 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1682 /* Coprocessor data processing */
1683 if ((opcode
& 0x0f000100) == 0x0c000000)
1684 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1686 /* Coprocessor register transfers */
1687 if ((opcode
& 0x0f000010) == 0x0c000010)
1688 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1690 /* Undefined instruction */
1691 if ((opcode
& 0x0f000000) == 0x0f000000)
1693 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1694 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1699 /* catch opcodes with [27:25] = b000 */
1700 if ((opcode
& 0x0e000000) == 0x00000000)
1702 /* Multiplies, extra load/stores */
1703 if ((opcode
& 0x00000090) == 0x00000090)
1704 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1706 /* Miscellaneous instructions */
1707 if ((opcode
& 0x0f900000) == 0x01000000)
1708 return evaluate_misc_instr(opcode
, address
, instruction
);
1710 return evaluate_data_proc(opcode
, address
, instruction
);
1713 /* catch opcodes with [27:25] = b001 */
1714 if ((opcode
& 0x0e000000) == 0x02000000)
1716 /* Undefined instruction */
1717 if ((opcode
& 0x0fb00000) == 0x03000000)
1719 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1720 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1724 /* Move immediate to status register */
1725 if ((opcode
& 0x0fb00000) == 0x03200000)
1726 return evaluate_mrs_msr(opcode
, address
, instruction
);
1728 return evaluate_data_proc(opcode
, address
, instruction
);
1732 /* catch opcodes with [27:25] = b010 */
1733 if ((opcode
& 0x0e000000) == 0x04000000)
1735 /* Load/store immediate offset */
1736 return evaluate_load_store(opcode
, address
, instruction
);
1739 /* catch opcodes with [27:25] = b011 */
1740 if ((opcode
& 0x0e000000) == 0x06000000)
1742 /* Load/store register offset */
1743 if ((opcode
& 0x00000010) == 0x00000000)
1744 return evaluate_load_store(opcode
, address
, instruction
);
1746 /* Architecturally Undefined instruction
1747 * ... don't expect these to ever be used
1749 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1751 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1752 snprintf(instruction
->text
, 128,
1753 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1758 /* "media" instructions */
1759 return evaluate_media(opcode
, address
, instruction
);
1762 /* catch opcodes with [27:25] = b100 */
1763 if ((opcode
& 0x0e000000) == 0x08000000)
1765 /* Load/store multiple */
1766 return evaluate_ldm_stm(opcode
, address
, instruction
);
1769 /* catch opcodes with [27:25] = b101 */
1770 if ((opcode
& 0x0e000000) == 0x0a000000)
1772 /* Branch and branch with link */
1773 return evaluate_b_bl(opcode
, address
, instruction
);
1776 /* catch opcodes with [27:25] = b110 */
1777 if ((opcode
& 0x0e000000) == 0x0c000000)
1779 /* Coprocessor load/store and double register transfers */
1780 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1783 /* catch opcodes with [27:25] = b111 */
1784 if ((opcode
& 0x0e000000) == 0x0e000000)
1786 /* Software interrupt */
1787 if ((opcode
& 0x0f000000) == 0x0f000000)
1788 return evaluate_swi(opcode
, address
, instruction
);
1790 /* Coprocessor data processing */
1791 if ((opcode
& 0x0f000010) == 0x0e000000)
1792 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1794 /* Coprocessor register transfers */
1795 if ((opcode
& 0x0f000010) == 0x0e000010)
1796 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1799 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1804 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1805 uint32_t address
, struct arm_instruction
*instruction
)
1807 uint32_t offset
= opcode
& 0x7ff;
1808 uint32_t opc
= (opcode
>> 11) & 0x3;
1809 uint32_t target_address
;
1810 char *mnemonic
= NULL
;
1812 /* sign extend 11-bit offset */
1813 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1814 offset
= 0xfffff800 | offset
;
1816 target_address
= address
+ 4 + (offset
<< 1);
1820 /* unconditional branch */
1822 instruction
->type
= ARM_B
;
1827 instruction
->type
= ARM_BLX
;
1829 target_address
&= 0xfffffffc;
1833 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1834 mnemonic
= "prefix";
1835 target_address
= offset
<< 12;
1839 instruction
->type
= ARM_BL
;
1844 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1845 * these are effectively 32-bit instructions even in Thumb1. For
1846 * disassembly, it's simplest to always use the Thumb2 decoder.
1848 * But some cores will evidently handle them as two instructions,
1849 * where exceptions may occur between the two. The ETMv3.2+ ID
1850 * register has a bit which exposes this behavior.
1853 snprintf(instruction
->text
, 128,
1854 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1855 address
, opcode
, mnemonic
, target_address
);
1857 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1858 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1863 static int evaluate_add_sub_thumb(uint16_t opcode
,
1864 uint32_t address
, struct arm_instruction
*instruction
)
1866 uint8_t Rd
= (opcode
>> 0) & 0x7;
1867 uint8_t Rn
= (opcode
>> 3) & 0x7;
1868 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1869 uint32_t opc
= opcode
& (1 << 9);
1870 uint32_t reg_imm
= opcode
& (1 << 10);
1875 instruction
->type
= ARM_SUB
;
1880 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1881 instruction
->type
= ARM_ADD
;
1885 instruction
->info
.data_proc
.Rd
= Rd
;
1886 instruction
->info
.data_proc
.Rn
= Rn
;
1887 instruction
->info
.data_proc
.S
= 1;
1891 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1892 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1893 snprintf(instruction
->text
, 128,
1894 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1895 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1899 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1900 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1901 snprintf(instruction
->text
, 128,
1902 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1903 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1909 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1910 uint32_t address
, struct arm_instruction
*instruction
)
1912 uint8_t Rd
= (opcode
>> 0) & 0x7;
1913 uint8_t Rm
= (opcode
>> 3) & 0x7;
1914 uint8_t imm
= (opcode
>> 6) & 0x1f;
1915 uint8_t opc
= (opcode
>> 11) & 0x3;
1916 char *mnemonic
= NULL
;
1921 instruction
->type
= ARM_MOV
;
1923 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1926 instruction
->type
= ARM_MOV
;
1928 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1931 instruction
->type
= ARM_MOV
;
1933 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1937 if ((imm
== 0) && (opc
!= 0))
1940 instruction
->info
.data_proc
.Rd
= Rd
;
1941 instruction
->info
.data_proc
.Rn
= -1;
1942 instruction
->info
.data_proc
.S
= 1;
1944 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1945 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1946 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1948 snprintf(instruction
->text
, 128,
1949 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1950 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1955 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1956 uint32_t address
, struct arm_instruction
*instruction
)
1958 uint8_t imm
= opcode
& 0xff;
1959 uint8_t Rd
= (opcode
>> 8) & 0x7;
1960 uint32_t opc
= (opcode
>> 11) & 0x3;
1961 char *mnemonic
= NULL
;
1963 instruction
->info
.data_proc
.Rd
= Rd
;
1964 instruction
->info
.data_proc
.Rn
= Rd
;
1965 instruction
->info
.data_proc
.S
= 1;
1966 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1967 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1972 instruction
->type
= ARM_MOV
;
1974 instruction
->info
.data_proc
.Rn
= -1;
1977 instruction
->type
= ARM_CMP
;
1979 instruction
->info
.data_proc
.Rd
= -1;
1982 instruction
->type
= ARM_ADD
;
1986 instruction
->type
= ARM_SUB
;
1991 snprintf(instruction
->text
, 128,
1992 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1993 address
, opcode
, mnemonic
, Rd
, imm
);
1998 static int evaluate_data_proc_thumb(uint16_t opcode
,
1999 uint32_t address
, struct arm_instruction
*instruction
)
2001 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
2002 char *mnemonic
= NULL
;
2005 high_reg
= (opcode
& 0x0400) >> 10;
2006 op
= (opcode
& 0x03C0) >> 6;
2008 Rd
= (opcode
& 0x0007);
2009 Rm
= (opcode
& 0x0038) >> 3;
2010 H1
= (opcode
& 0x0080) >> 7;
2011 H2
= (opcode
& 0x0040) >> 6;
2013 instruction
->info
.data_proc
.Rd
= Rd
;
2014 instruction
->info
.data_proc
.Rn
= Rd
;
2015 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2016 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2017 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2028 instruction
->type
= ARM_ADD
;
2032 instruction
->type
= ARM_CMP
;
2036 instruction
->type
= ARM_MOV
;
2042 if ((opcode
& 0x7) == 0x0)
2044 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2047 instruction
->type
= ARM_BLX
;
2048 snprintf(instruction
->text
, 128,
2050 " 0x%4.4x \tBLX\tr%i",
2051 address
, opcode
, Rm
);
2055 instruction
->type
= ARM_BX
;
2056 snprintf(instruction
->text
, 128,
2058 " 0x%4.4x \tBX\tr%i",
2059 address
, opcode
, Rm
);
2064 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2065 snprintf(instruction
->text
, 128,
2068 "UNDEFINED INSTRUCTION",
2080 instruction
->type
= ARM_AND
;
2084 instruction
->type
= ARM_EOR
;
2088 instruction
->type
= ARM_MOV
;
2090 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2091 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2092 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2093 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2096 instruction
->type
= ARM_MOV
;
2098 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2099 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2100 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2101 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2104 instruction
->type
= ARM_MOV
;
2106 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2107 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2108 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2109 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2112 instruction
->type
= ARM_ADC
;
2116 instruction
->type
= ARM_SBC
;
2120 instruction
->type
= ARM_MOV
;
2122 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2123 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2124 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2125 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2128 instruction
->type
= ARM_TST
;
2132 instruction
->type
= ARM_RSB
;
2134 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2135 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2136 instruction
->info
.data_proc
.Rn
= Rm
;
2139 instruction
->type
= ARM_CMP
;
2143 instruction
->type
= ARM_CMN
;
2147 instruction
->type
= ARM_ORR
;
2151 instruction
->type
= ARM_MUL
;
2155 instruction
->type
= ARM_BIC
;
2159 instruction
->type
= ARM_MVN
;
2166 snprintf(instruction
->text
, 128,
2167 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2169 address
, opcode
, mnemonic
, Rd
, Rm
);
2171 snprintf(instruction
->text
, 128,
2172 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2173 address
, opcode
, mnemonic
, Rd
, Rm
);
2178 /* PC-relative data addressing is word-aligned even with Thumb */
2179 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2181 return (addr
+ 4) & ~3;
2184 static int evaluate_load_literal_thumb(uint16_t opcode
,
2185 uint32_t address
, struct arm_instruction
*instruction
)
2188 uint8_t Rd
= (opcode
>> 8) & 0x7;
2190 instruction
->type
= ARM_LDR
;
2191 immediate
= opcode
& 0x000000ff;
2194 instruction
->info
.load_store
.Rd
= Rd
;
2195 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2196 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2197 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2198 instruction
->info
.load_store
.offset
.offset
= immediate
;
2200 snprintf(instruction
->text
, 128,
2201 "0x%8.8" PRIx32
" 0x%4.4x \t"
2202 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2203 address
, opcode
, Rd
, immediate
,
2204 thumb_alignpc4(address
) + immediate
);
2209 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2210 uint32_t address
, struct arm_instruction
*instruction
)
2212 uint8_t Rd
= (opcode
>> 0) & 0x7;
2213 uint8_t Rn
= (opcode
>> 3) & 0x7;
2214 uint8_t Rm
= (opcode
>> 6) & 0x7;
2215 uint8_t opc
= (opcode
>> 9) & 0x7;
2216 char *mnemonic
= NULL
;
2221 instruction
->type
= ARM_STR
;
2225 instruction
->type
= ARM_STRH
;
2229 instruction
->type
= ARM_STRB
;
2233 instruction
->type
= ARM_LDRSB
;
2237 instruction
->type
= ARM_LDR
;
2241 instruction
->type
= ARM_LDRH
;
2245 instruction
->type
= ARM_LDRB
;
2249 instruction
->type
= ARM_LDRSH
;
2254 snprintf(instruction
->text
, 128,
2255 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2256 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2258 instruction
->info
.load_store
.Rd
= Rd
;
2259 instruction
->info
.load_store
.Rn
= Rn
;
2260 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2261 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2262 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2267 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2268 uint32_t address
, struct arm_instruction
*instruction
)
2270 uint32_t offset
= (opcode
>> 6) & 0x1f;
2271 uint8_t Rd
= (opcode
>> 0) & 0x7;
2272 uint8_t Rn
= (opcode
>> 3) & 0x7;
2273 uint32_t L
= opcode
& (1 << 11);
2274 uint32_t B
= opcode
& (1 << 12);
2281 instruction
->type
= ARM_LDR
;
2286 instruction
->type
= ARM_STR
;
2290 if ((opcode
&0xF000) == 0x8000)
2301 snprintf(instruction
->text
, 128,
2302 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2303 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2305 instruction
->info
.load_store
.Rd
= Rd
;
2306 instruction
->info
.load_store
.Rn
= Rn
;
2307 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2308 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2309 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2314 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2315 uint32_t address
, struct arm_instruction
*instruction
)
2317 uint32_t offset
= opcode
& 0xff;
2318 uint8_t Rd
= (opcode
>> 8) & 0x7;
2319 uint32_t L
= opcode
& (1 << 11);
2324 instruction
->type
= ARM_LDR
;
2329 instruction
->type
= ARM_STR
;
2333 snprintf(instruction
->text
, 128,
2334 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2335 address
, opcode
, mnemonic
, Rd
, offset
*4);
2337 instruction
->info
.load_store
.Rd
= Rd
;
2338 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2339 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2340 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2341 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2346 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2347 uint32_t address
, struct arm_instruction
*instruction
)
2349 uint32_t imm
= opcode
& 0xff;
2350 uint8_t Rd
= (opcode
>> 8) & 0x7;
2352 uint32_t SP
= opcode
& (1 << 11);
2355 instruction
->type
= ARM_ADD
;
2368 snprintf(instruction
->text
, 128,
2369 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2370 address
, opcode
, Rd
, reg_name
, imm
* 4);
2372 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2373 instruction
->info
.data_proc
.Rd
= Rd
;
2374 instruction
->info
.data_proc
.Rn
= Rn
;
2375 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2380 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2381 uint32_t address
, struct arm_instruction
*instruction
)
2383 uint32_t imm
= opcode
& 0x7f;
2384 uint8_t opc
= opcode
& (1 << 7);
2390 instruction
->type
= ARM_SUB
;
2395 instruction
->type
= ARM_ADD
;
2399 snprintf(instruction
->text
, 128,
2400 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2401 address
, opcode
, mnemonic
, imm
*4);
2403 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2404 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2405 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2406 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2411 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2412 uint32_t address
, struct arm_instruction
*instruction
)
2414 uint32_t imm
= opcode
& 0xff;
2416 instruction
->type
= ARM_BKPT
;
2418 snprintf(instruction
->text
, 128,
2419 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2420 address
, opcode
, imm
);
2425 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2426 uint32_t address
, struct arm_instruction
*instruction
)
2428 uint32_t reg_list
= opcode
& 0xff;
2429 uint32_t L
= opcode
& (1 << 11);
2430 uint32_t R
= opcode
& (1 << 8);
2431 uint8_t Rn
= (opcode
>> 8) & 7;
2432 uint8_t addr_mode
= 0 /* IA */;
2436 char ptr_name
[7] = "";
2439 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2440 * The STMIA and LDMIA opcodes are used for other instructions.
2443 if ((opcode
& 0xf000) == 0xc000)
2444 { /* generic load/store multiple */
2449 instruction
->type
= ARM_LDM
;
2451 if (opcode
& (1 << Rn
))
2456 instruction
->type
= ARM_STM
;
2459 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2466 instruction
->type
= ARM_LDM
;
2469 reg_list
|= (1 << 15) /*PC*/;
2473 instruction
->type
= ARM_STM
;
2475 addr_mode
= 3; /*DB*/
2477 reg_list
|= (1 << 14) /*LR*/;
2481 reg_names_p
= reg_names
;
2482 for (i
= 0; i
<= 15; i
++)
2484 if (reg_list
& (1 << i
))
2485 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2487 if (reg_names_p
> reg_names
)
2488 reg_names_p
[-2] = '\0';
2489 else /* invalid op : no registers */
2490 reg_names
[0] = '\0';
2492 snprintf(instruction
->text
, 128,
2493 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2494 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2496 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2497 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2498 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2503 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2504 uint32_t address
, struct arm_instruction
*instruction
)
2506 uint32_t offset
= opcode
& 0xff;
2507 uint8_t cond
= (opcode
>> 8) & 0xf;
2508 uint32_t target_address
;
2512 instruction
->type
= ARM_SWI
;
2513 snprintf(instruction
->text
, 128,
2514 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2515 address
, opcode
, offset
);
2518 else if (cond
== 0xe)
2520 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2521 snprintf(instruction
->text
, 128,
2522 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2527 /* sign extend 8-bit offset */
2528 if (offset
& 0x00000080)
2529 offset
= 0xffffff00 | offset
;
2531 target_address
= address
+ 4 + (offset
<< 1);
2533 snprintf(instruction
->text
, 128,
2534 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2536 arm_condition_strings
[cond
], target_address
);
2538 instruction
->type
= ARM_B
;
2539 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2540 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2545 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2546 struct arm_instruction
*instruction
)
2550 /* added in Thumb2 */
2551 offset
= (opcode
>> 3) & 0x1f;
2552 offset
|= (opcode
& 0x0200) >> 4;
2554 snprintf(instruction
->text
, 128,
2555 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2557 (opcode
& 0x0800) ? "N" : "",
2558 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2563 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2564 struct arm_instruction
*instruction
)
2566 /* added in ARMv6 */
2567 snprintf(instruction
->text
, 128,
2568 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2570 (opcode
& 0x0080) ? 'U' : 'S',
2571 (opcode
& 0x0040) ? 'B' : 'H',
2572 opcode
& 0x7, (opcode
>> 3) & 0x7);
2577 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2578 struct arm_instruction
*instruction
)
2580 /* added in ARMv6 */
2581 if ((opcode
& 0x0ff0) == 0x0650)
2582 snprintf(instruction
->text
, 128,
2583 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2585 (opcode
& 0x80) ? "BE" : "LE");
2586 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2587 snprintf(instruction
->text
, 128,
2588 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2590 (opcode
& 0x0010) ? 'D' : 'E',
2591 (opcode
& 0x0004) ? "A" : "",
2592 (opcode
& 0x0002) ? "I" : "",
2593 (opcode
& 0x0001) ? "F" : "");
2598 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2599 struct arm_instruction
*instruction
)
2603 /* added in ARMv6 */
2604 switch ((opcode
>> 6) & 3) {
2615 snprintf(instruction
->text
, 128,
2616 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2617 address
, opcode
, suffix
,
2618 opcode
& 0x7, (opcode
>> 3) & 0x7);
2623 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2624 struct arm_instruction
*instruction
)
2628 switch ((opcode
>> 4) & 0x0f) {
2645 hint
= "HINT (UNRECOGNIZED)";
2649 snprintf(instruction
->text
, 128,
2650 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2651 address
, opcode
, hint
);
2656 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2657 struct arm_instruction
*instruction
)
2659 unsigned cond
= (opcode
>> 4) & 0x0f;
2660 char *x
= "", *y
= "", *z
= "";
2663 z
= (opcode
& 0x02) ? "T" : "E";
2665 y
= (opcode
& 0x04) ? "T" : "E";
2667 x
= (opcode
& 0x08) ? "T" : "E";
2669 snprintf(instruction
->text
, 128,
2670 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2672 x
, y
, z
, arm_condition_strings
[cond
]);
2674 /* NOTE: strictly speaking, the next 1-4 instructions should
2675 * now be displayed with the relevant conditional suffix...
2681 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2683 /* clear fields, to avoid confusion */
2684 memset(instruction
, 0, sizeof(struct arm_instruction
));
2685 instruction
->opcode
= opcode
;
2686 instruction
->instruction_size
= 2;
2688 if ((opcode
& 0xe000) == 0x0000)
2690 /* add/substract register or immediate */
2691 if ((opcode
& 0x1800) == 0x1800)
2692 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2693 /* shift by immediate */
2695 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2698 /* Add/substract/compare/move immediate */
2699 if ((opcode
& 0xe000) == 0x2000)
2701 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2704 /* Data processing instructions */
2705 if ((opcode
& 0xf800) == 0x4000)
2707 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2710 /* Load from literal pool */
2711 if ((opcode
& 0xf800) == 0x4800)
2713 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2716 /* Load/Store register offset */
2717 if ((opcode
& 0xf000) == 0x5000)
2719 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2722 /* Load/Store immediate offset */
2723 if (((opcode
& 0xe000) == 0x6000)
2724 ||((opcode
& 0xf000) == 0x8000))
2726 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2729 /* Load/Store from/to stack */
2730 if ((opcode
& 0xf000) == 0x9000)
2732 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2736 if ((opcode
& 0xf000) == 0xa000)
2738 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2742 if ((opcode
& 0xf000) == 0xb000)
2744 switch ((opcode
>> 8) & 0x0f) {
2746 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2751 return evaluate_cb_thumb(opcode
, address
, instruction
);
2753 return evaluate_extend_thumb(opcode
, address
, instruction
);
2758 return evaluate_load_store_multiple_thumb(opcode
, address
,
2761 return evaluate_cps_thumb(opcode
, address
, instruction
);
2763 if ((opcode
& 0x00c0) == 0x0080)
2765 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2767 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2769 if (opcode
& 0x000f)
2770 return evaluate_ifthen_thumb(opcode
, address
,
2773 return evaluate_hint_thumb(opcode
, address
,
2777 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2778 snprintf(instruction
->text
, 128,
2779 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2784 /* Load/Store multiple */
2785 if ((opcode
& 0xf000) == 0xc000)
2787 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2790 /* Conditional branch + SWI */
2791 if ((opcode
& 0xf000) == 0xd000)
2793 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2796 if ((opcode
& 0xe000) == 0xe000)
2798 /* Undefined instructions */
2799 if ((opcode
& 0xf801) == 0xe801)
2801 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2802 snprintf(instruction
->text
, 128,
2803 "0x%8.8" PRIx32
" 0x%8.8x\t"
2804 "UNDEFINED INSTRUCTION",
2809 { /* Branch to offset */
2810 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2814 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2818 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2819 struct arm_instruction
*instruction
, char *cp
)
2822 unsigned b21
= 1 << 21;
2823 unsigned b22
= 1 << 22;
2825 /* instead of combining two smaller 16-bit branch instructions,
2826 * Thumb2 uses only one larger 32-bit instruction.
2828 offset
= opcode
& 0x7ff;
2829 offset
|= (opcode
& 0x03ff0000) >> 5;
2830 if (opcode
& (1 << 26)) {
2831 offset
|= 0xff << 23;
2832 if ((opcode
& (1 << 11)) == 0)
2834 if ((opcode
& (1 << 13)) == 0)
2837 if (opcode
& (1 << 11))
2839 if (opcode
& (1 << 13))
2847 address
+= offset
<< 1;
2849 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2850 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2851 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2852 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2853 (opcode
& (1 << 14)) ? "BL" : "B.W",
2859 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2860 struct arm_instruction
*instruction
, char *cp
)
2863 unsigned b17
= 1 << 17;
2864 unsigned b18
= 1 << 18;
2865 unsigned cond
= (opcode
>> 22) & 0x0f;
2867 offset
= opcode
& 0x7ff;
2868 offset
|= (opcode
& 0x003f0000) >> 5;
2869 if (opcode
& (1 << 26)) {
2870 offset
|= 0xffff << 19;
2871 if ((opcode
& (1 << 11)) == 0)
2873 if ((opcode
& (1 << 13)) == 0)
2876 if (opcode
& (1 << 11))
2878 if (opcode
& (1 << 13))
2885 address
+= offset
<< 1;
2887 instruction
->type
= ARM_B
;
2888 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2889 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2890 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2891 arm_condition_strings
[cond
],
2897 static const char *special_name(int number
)
2899 char *special
= "(RESERVED)";
2930 special
= "primask";
2933 special
= "basepri";
2936 special
= "basepri_max";
2939 special
= "faultmask";
2942 special
= "control";
2948 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2949 struct arm_instruction
*instruction
, char *cp
)
2951 const char *mnemonic
;
2953 if (opcode
& 0x0700) {
2954 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2955 strcpy(cp
, "UNDEFINED");
2959 if (opcode
& 0x00f0) {
2960 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2964 switch (opcode
& 0x0f) {
2969 mnemonic
= "YIELD.W";
2981 mnemonic
= "HINT.W (UNRECOGNIZED)";
2984 strcpy(cp
, mnemonic
);
2988 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2989 struct arm_instruction
*instruction
, char *cp
)
2991 const char *mnemonic
;
2993 switch ((opcode
>> 4) & 0x0f) {
2995 mnemonic
= "LEAVEX";
2998 mnemonic
= "ENTERX";
3013 return ERROR_INVALID_ARGUMENTS
;
3015 strcpy(cp
, mnemonic
);
3019 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3020 struct arm_instruction
*instruction
, char *cp
)
3022 /* permanently undefined */
3023 if ((opcode
& 0x07f07000) == 0x07f02000) {
3024 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3025 strcpy(cp
, "UNDEFINED");
3029 switch ((opcode
>> 12) & 0x5) {
3032 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3036 if (((opcode
>> 23) & 0x07) != 0x07)
3037 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3038 if (opcode
& (1 << 26))
3043 switch ((opcode
>> 20) & 0x7f) {
3046 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3047 (int) (opcode
>> 16) & 0x0f);
3050 return t2ev_hint(opcode
, address
, instruction
, cp
);
3052 return t2ev_misc(opcode
, address
, instruction
, cp
);
3054 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3058 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3059 special_name(opcode
& 0xff));
3064 return ERROR_INVALID_ARGUMENTS
;
3067 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3068 struct arm_instruction
*instruction
, char *cp
)
3070 char *mnemonic
= NULL
;
3071 int rn
= (opcode
>> 16) & 0xf;
3072 int rd
= (opcode
>> 8) & 0xf;
3073 unsigned immed
= opcode
& 0xff;
3079 /* ARMv7-M: A5.3.2 Modified immediate constants */
3080 func
= (opcode
>> 11) & 0x0e;
3083 if (opcode
& (1 << 26))
3086 /* "Modified" immediates */
3087 switch (func
>> 1) {
3094 immed
+= immed
<< 16;
3097 immed
+= immed
<< 8;
3098 immed
+= immed
<< 16;
3102 immed
= ror(immed
, func
);
3105 if (opcode
& (1 << 20))
3108 switch ((opcode
>> 21) & 0xf) {
3111 instruction
->type
= ARM_TST
;
3117 instruction
->type
= ARM_AND
;
3122 instruction
->type
= ARM_BIC
;
3127 instruction
->type
= ARM_MOV
;
3132 instruction
->type
= ARM_ORR
;
3138 instruction
->type
= ARM_MVN
;
3142 // instruction->type = ARM_ORN;
3148 instruction
->type
= ARM_TEQ
;
3154 instruction
->type
= ARM_EOR
;
3160 instruction
->type
= ARM_CMN
;
3166 instruction
->type
= ARM_ADD
;
3172 instruction
->type
= ARM_ADC
;
3177 instruction
->type
= ARM_SBC
;
3182 instruction
->type
= ARM_CMP
;
3188 instruction
->type
= ARM_SUB
;
3194 instruction
->type
= ARM_RSB
;
3199 return ERROR_INVALID_ARGUMENTS
;
3203 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3204 mnemonic
, suffix2
,rd
, immed
, immed
);
3206 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3207 mnemonic
, suffix
, suffix2
,
3208 rd
, rn
, immed
, immed
);
3213 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3214 struct arm_instruction
*instruction
, char *cp
)
3216 char *mnemonic
= NULL
;
3217 int rn
= (opcode
>> 16) & 0xf;
3218 int rd
= (opcode
>> 8) & 0xf;
3221 bool is_signed
= false;
3223 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3224 if (opcode
& (1 << 26))
3227 switch ((opcode
>> 20) & 0x1f) {
3236 immed
|= (opcode
>> 4) & 0xf000;
3237 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3245 /* move constant to top 16 bits of register */
3246 immed
|= (opcode
>> 4) & 0xf000;
3247 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3254 /* signed/unsigned saturated add */
3255 immed
= (opcode
>> 6) & 0x03;
3256 immed
|= (opcode
>> 10) & 0x1c;
3257 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3258 is_signed
? "S" : "U",
3259 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3260 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3261 immed
? immed
: 32);
3267 /* signed/unsigned bitfield extract */
3268 immed
= (opcode
>> 6) & 0x03;
3269 immed
|= (opcode
>> 10) & 0x1c;
3270 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3271 is_signed
? "S" : "U",
3273 (int) (opcode
& 0x1f) + 1);
3276 immed
= (opcode
>> 6) & 0x03;
3277 immed
|= (opcode
>> 10) & 0x1c;
3278 if (rn
== 0xf) /* bitfield clear */
3279 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3281 (int) (opcode
& 0x1f) + 1 - immed
);
3282 else /* bitfield insert */
3283 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3285 (int) (opcode
& 0x1f) + 1 - immed
);
3288 return ERROR_INVALID_ARGUMENTS
;
3291 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3292 rd
, rn
, immed
, immed
);
3296 address
= thumb_alignpc4(address
);
3301 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3302 * not hiding the pc-relative stuff will sometimes be useful.
3304 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3308 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3309 struct arm_instruction
*instruction
, char *cp
)
3311 unsigned op
= (opcode
>> 20) & 0xf;
3317 unsigned rn
= (opcode
>> 16) & 0x0f;
3318 unsigned rt
= (opcode
>> 12) & 0x0f;
3321 return ERROR_INVALID_ARGUMENTS
;
3323 if (opcode
& 0x0800)
3358 return ERROR_INVALID_ARGUMENTS
;
3361 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3362 size
, rt
, rn
, (int) opcode
& 0x0f,
3363 (int) (opcode
>> 4) & 0x03);
3367 immed
= opcode
& 0x0fff;
3368 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3369 size
, rt
, rn
, immed
, immed
);
3373 immed
= opcode
& 0x00ff;
3375 switch (opcode
& 0x700) {
3381 return ERROR_INVALID_ARGUMENTS
;
3384 /* two indexed modes will write back rn */
3385 if (opcode
& 0x100) {
3386 if (opcode
& 0x400) /* pre-indexed */
3388 else { /* post-indexed */
3394 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3395 size
, suffix
, rt
, rn
, p1
,
3396 (opcode
& 0x200) ? "" : "-",
3401 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3402 struct arm_instruction
*instruction
, char *cp
)
3404 int ra
= (opcode
>> 12) & 0xf;
3406 switch (opcode
& 0x007000f0) {
3409 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3410 (int) (opcode
>> 8) & 0xf,
3411 (int) (opcode
>> 16) & 0xf,
3412 (int) (opcode
>> 0) & 0xf);
3414 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3415 (int) (opcode
>> 8) & 0xf,
3416 (int) (opcode
>> 16) & 0xf,
3417 (int) (opcode
>> 0) & 0xf, ra
);
3420 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3421 (int) (opcode
>> 8) & 0xf,
3422 (int) (opcode
>> 16) & 0xf,
3423 (int) (opcode
>> 0) & 0xf, ra
);
3426 return ERROR_INVALID_ARGUMENTS
;
3431 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3432 struct arm_instruction
*instruction
, char *cp
)
3434 int op
= (opcode
>> 4) & 0xf;
3435 char *infix
= "MUL";
3437 op
+= (opcode
>> 16) & 0x70;
3445 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3446 (op
& 0x20) ? 'U' : 'S',
3448 (int) (opcode
>> 12) & 0xf,
3449 (int) (opcode
>> 8) & 0xf,
3450 (int) (opcode
>> 16) & 0xf,
3451 (int) (opcode
>> 0) & 0xf);
3455 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3456 (op
& 0x20) ? 'U' : 'S',
3457 (int) (opcode
>> 8) & 0xf,
3458 (int) (opcode
>> 16) & 0xf,
3459 (int) (opcode
>> 0) & 0xf);
3462 return ERROR_INVALID_ARGUMENTS
;
3468 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3469 struct arm_instruction
*instruction
, char *cp
)
3471 int rn
= (opcode
>> 16) & 0xf;
3472 int op
= (opcode
>> 22) & 0x6;
3473 int t
= (opcode
>> 21) & 1;
3474 unsigned registers
= opcode
& 0xffff;
3477 if (opcode
& (1 << 20))
3485 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3487 (unsigned) (opcode
& 0x1f));
3493 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3494 (unsigned) ((opcode
>> 16) & 0xf),
3498 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3502 sprintf(cp
, "POP.W\t");
3504 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3508 sprintf(cp
, "PUSH.W\t");
3510 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3513 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3516 return ERROR_INVALID_ARGUMENTS
;
3521 for (t
= 0; registers
; t
++, registers
>>= 1) {
3522 if ((registers
& 1) == 0)
3525 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3534 /* load/store dual or exclusive, table branch */
3535 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3536 struct arm_instruction
*instruction
, char *cp
)
3538 unsigned op1op2
= (opcode
>> 20) & 0x3;
3539 unsigned op3
= (opcode
>> 4) & 0xf;
3541 unsigned rn
= (opcode
>> 16) & 0xf;
3542 unsigned rt
= (opcode
>> 12) & 0xf;
3543 unsigned rd
= (opcode
>> 8) & 0xf;
3544 unsigned imm
= opcode
& 0xff;
3548 op1op2
|= (opcode
>> 21) & 0xc;
3578 mnemonic
= "STREXB";
3581 mnemonic
= "STREXH";
3584 return ERROR_INVALID_ARGUMENTS
;
3592 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3595 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3598 mnemonic
= "LDREXB";
3601 mnemonic
= "LDREXH";
3604 return ERROR_INVALID_ARGUMENTS
;
3609 return ERROR_INVALID_ARGUMENTS
;
3614 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3615 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3617 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3618 mnemonic
, rd
, rt
, rn
);
3624 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3625 mnemonic
, rt
, rn
, imm
, imm
);
3627 sprintf(cp
, "%s\tr%u, [r%u]",
3632 /* two indexed modes will write back rn */
3633 if (opcode
& (1 << 21)) {
3634 if (opcode
& (1 << 24)) /* pre-indexed */
3636 else { /* post-indexed */
3643 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3644 mnemonic
, rt
, rd
, rn
, p1
,
3645 (opcode
& (1 << 23)) ? "" : "-",
3650 address
= thumb_alignpc4(address
);
3652 if (opcode
& (1 << 23))
3656 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3657 mnemonic
, rt
, rd
, address
);
3661 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3662 struct arm_instruction
*instruction
, char *cp
)
3664 int op
= (opcode
>> 21) & 0xf;
3665 int rd
= (opcode
>> 8) & 0xf;
3666 int rn
= (opcode
>> 16) & 0xf;
3667 int type
= (opcode
>> 4) & 0x3;
3668 int immed
= (opcode
>> 6) & 0x3;
3672 immed
|= (opcode
>> 10) & 0x1c;
3673 if (opcode
& (1 << 20))
3679 if (!(opcode
& (1 << 20)))
3680 return ERROR_INVALID_ARGUMENTS
;
3681 instruction
->type
= ARM_TST
;
3686 instruction
->type
= ARM_AND
;
3690 instruction
->type
= ARM_BIC
;
3695 instruction
->type
= ARM_MOV
;
3699 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3701 (int) (opcode
& 0xf));
3714 sprintf(cp
, "RRX%s\tr%d, r%d",
3716 (int) (opcode
& 0xf));
3724 instruction
->type
= ARM_ORR
;
3730 instruction
->type
= ARM_MVN
;
3735 // instruction->type = ARM_ORN;
3741 if (!(opcode
& (1 << 20)))
3742 return ERROR_INVALID_ARGUMENTS
;
3743 instruction
->type
= ARM_TEQ
;
3748 instruction
->type
= ARM_EOR
;
3753 if (!(opcode
& (1 << 20)))
3754 return ERROR_INVALID_ARGUMENTS
;
3755 instruction
->type
= ARM_CMN
;
3760 instruction
->type
= ARM_ADD
;
3764 instruction
->type
= ARM_ADC
;
3768 instruction
->type
= ARM_SBC
;
3773 if (!(opcode
& (1 << 21)))
3774 return ERROR_INVALID_ARGUMENTS
;
3775 instruction
->type
= ARM_CMP
;
3780 instruction
->type
= ARM_SUB
;
3784 instruction
->type
= ARM_RSB
;
3788 return ERROR_INVALID_ARGUMENTS
;
3791 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3792 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3815 strcpy(cp
, ", RRX");
3821 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3825 sprintf(cp
, "%s%s.W\tr%d, r%d",
3826 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3830 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3831 mnemonic
, suffix
, rd
,
3832 (int) (opcode
& 0xf), immed
? immed
: 32);
3836 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3837 struct arm_instruction
*instruction
, char *cp
)
3842 if (((opcode
>> 4) & 0xf) == 0) {
3843 switch ((opcode
>> 21) & 0x7) {
3857 return ERROR_INVALID_ARGUMENTS
;
3860 instruction
->type
= ARM_MOV
;
3861 if (opcode
& (1 << 20))
3863 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3865 (int) (opcode
>> 8) & 0xf,
3866 (int) (opcode
>> 16) & 0xf,
3867 (int) (opcode
>> 0) & 0xf);
3869 } else if (opcode
& (1 << 7)) {
3870 switch ((opcode
>> 20) & 0xf) {
3875 switch ((opcode
>> 4) & 0x3) {
3877 suffix
= ", ROR #8";
3880 suffix
= ", ROR #16";
3883 suffix
= ", ROR #24";
3886 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3887 (opcode
& (1 << 24)) ? 'U' : 'S',
3888 (opcode
& (1 << 26)) ? 'B' : 'H',
3889 (int) (opcode
>> 8) & 0xf,
3890 (int) (opcode
>> 0) & 0xf,
3897 if (opcode
& (1 << 6))
3898 return ERROR_INVALID_ARGUMENTS
;
3899 if (((opcode
>> 12) & 0xf) != 0xf)
3900 return ERROR_INVALID_ARGUMENTS
;
3901 if (!(opcode
& (1 << 20)))
3902 return ERROR_INVALID_ARGUMENTS
;
3904 switch (((opcode
>> 19) & 0x04)
3905 | ((opcode
>> 4) & 0x3)) {
3910 mnemonic
= "REV16.W";
3916 mnemonic
= "REVSH.W";
3922 return ERROR_INVALID_ARGUMENTS
;
3924 sprintf(cp
, "%s\tr%d, r%d",
3926 (int) (opcode
>> 8) & 0xf,
3927 (int) (opcode
>> 0) & 0xf);
3930 return ERROR_INVALID_ARGUMENTS
;
3937 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3938 struct arm_instruction
*instruction
, char *cp
)
3940 int rn
= (opcode
>> 16) & 0xf;
3943 instruction
->type
= ARM_LDR
;
3946 immed
= opcode
& 0x0fff;
3947 if ((opcode
& (1 << 23)) == 0)
3949 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3950 (int) (opcode
>> 12) & 0xf,
3951 thumb_alignpc4(address
) + immed
);
3955 if (opcode
& (1 << 23)) {
3956 immed
= opcode
& 0x0fff;
3957 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3958 (int) (opcode
>> 12) & 0xf,
3963 if (!(opcode
& (0x3f << 6))) {
3964 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3965 (int) (opcode
>> 12) & 0xf,
3967 (int) (opcode
>> 0) & 0xf,
3968 (int) (opcode
>> 4) & 0x3);
3973 if (((opcode
>> 8) & 0xf) == 0xe) {
3974 immed
= opcode
& 0x00ff;
3976 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3977 (int) (opcode
>> 12) & 0xf,
3982 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3983 char *p1
= "]", *p2
= "";
3985 if (!(opcode
& 0x0500))
3986 return ERROR_INVALID_ARGUMENTS
;
3988 immed
= opcode
& 0x00ff;
3990 /* two indexed modes will write back rn */
3991 if (opcode
& 0x100) {
3992 if (opcode
& 0x400) /* pre-indexed */
3994 else { /* post-indexed */
4000 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4001 (int) (opcode
>> 12) & 0xf,
4003 (opcode
& 0x200) ? "" : "-",
4008 return ERROR_INVALID_ARGUMENTS
;
4011 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4012 struct arm_instruction
*instruction
, char *cp
)
4014 int rn
= (opcode
>> 16) & 0xf;
4015 int rt
= (opcode
>> 12) & 0xf;
4016 int op2
= (opcode
>> 6) & 0x3f;
4018 char *p1
= "", *p2
= "]";
4021 switch ((opcode
>> 23) & 0x3) {
4023 if ((rn
& rt
) == 0xf) {
4025 immed
= opcode
& 0xfff;
4026 address
= thumb_alignpc4(address
);
4027 if (opcode
& (1 << 23))
4031 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4035 if (rn
== 0x0f && rt
!= 0x0f) {
4037 immed
= opcode
& 0xfff;
4038 address
= thumb_alignpc4(address
);
4039 if (opcode
& (1 << 23))
4043 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4049 if ((op2
& 0x3c) == 0x38) {
4050 immed
= opcode
& 0xff;
4051 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4052 rt
, rn
, immed
, immed
);
4055 if ((op2
& 0x3c) == 0x30) {
4057 immed
= opcode
& 0xff;
4060 p1
= (opcode
& (1 << 21)) ? "W" : "";
4061 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4062 p1
, rn
, immed
, immed
);
4067 immed
= opcode
& 0xff;
4068 if (!(opcode
& 0x200))
4071 /* two indexed modes will write back rn */
4072 if (opcode
& 0x100) {
4073 if (opcode
& 0x400) /* pre-indexed */
4075 else { /* post-indexed */
4081 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4082 mnemonic
, rt
, rn
, p1
,
4086 if ((op2
& 0x24) == 0x24) {
4088 goto ldrxb_immediate_t3
;
4091 int rm
= opcode
& 0xf;
4094 sprintf(cp
, "PLD\t");
4096 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4097 immed
= (opcode
>> 4) & 0x3;
4099 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4104 if ((rn
& rt
) == 0xf)
4107 immed
= opcode
& 0xfff;
4108 goto preload_immediate
;
4112 mnemonic
= "LDRB.W";
4113 immed
= opcode
& 0xfff;
4114 goto ldrxb_immediate_t2
;
4116 if ((rn
& rt
) == 0xf) {
4117 immed
= opcode
& 0xfff;
4118 address
= thumb_alignpc4(address
);
4119 if (opcode
& (1 << 23))
4123 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4126 if (rn
== 0xf && rt
!= 0xf) {
4128 immed
= opcode
& 0xfff;
4129 address
= thumb_alignpc4(address
);
4130 if (opcode
& (1 << 23))
4134 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4139 if ((op2
& 0x3c) == 0x38) {
4140 immed
= opcode
& 0xff;
4141 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4142 rt
, rn
, immed
, immed
);
4145 if ((op2
& 0x3c) == 0x30) {
4147 immed
= opcode
& 0xff;
4148 immed
= -immed
; // pli
4149 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4154 goto ldrxb_immediate_t3
;
4156 if ((op2
& 0x24) == 0x24) {
4158 goto ldrxb_immediate_t3
;
4161 int rm
= opcode
& 0xf;
4164 sprintf(cp
, "PLI\t");
4166 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4167 immed
= (opcode
>> 4) & 0x3;
4169 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4175 immed
= opcode
& 0xfff;
4176 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4182 immed
= opcode
& 0xfff;
4184 goto ldrxb_immediate_t2
;
4187 return ERROR_INVALID_ARGUMENTS
;
4190 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4191 struct arm_instruction
*instruction
, char *cp
)
4193 int rn
= (opcode
>> 16) & 0xf;
4194 int rt
= (opcode
>> 12) & 0xf;
4195 int op2
= (opcode
>> 6) & 0x3f;
4200 sprintf(cp
, "HINT (UNALLOCATED)");
4204 if (opcode
& (1 << 24))
4207 if ((opcode
& (1 << 23)) == 0) {
4210 immed
= opcode
& 0xfff;
4211 address
= thumb_alignpc4(address
);
4212 if (opcode
& (1 << 23))
4216 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4221 int rm
= opcode
& 0xf;
4223 immed
= (opcode
>> 4) & 0x3;
4224 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4225 sign
, rt
, rn
, rm
, immed
);
4228 if ((op2
& 0x3c) == 0x38) {
4229 immed
= opcode
& 0xff;
4230 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4231 sign
, rt
, rn
, immed
, immed
);
4234 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4235 char *p1
= "", *p2
= "]";
4237 immed
= opcode
& 0xff;
4238 if (!(opcode
& 0x200))
4241 /* two indexed modes will write back rn */
4242 if (opcode
& 0x100) {
4243 if (opcode
& 0x400) /* pre-indexed */
4245 else { /* post-indexed */
4250 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4251 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4258 immed
= opcode
& 0xfff;
4259 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4260 sign
, *sign
? "" : ".W",
4261 rt
, rn
, immed
, immed
);
4265 return ERROR_INVALID_ARGUMENTS
;
4269 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4270 * always set. That means eventual arm_simulate_step() support for Thumb2
4271 * will need work in this area.
4273 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4280 /* clear low bit ... it's set on function pointers */
4283 /* clear fields, to avoid confusion */
4284 memset(instruction
, 0, sizeof(struct arm_instruction
));
4286 /* read first halfword, see if this is the only one */
4287 retval
= target_read_u16(target
, address
, &op
);
4288 if (retval
!= ERROR_OK
)
4291 switch (op
& 0xf800) {
4295 /* 32-bit instructions */
4296 instruction
->instruction_size
= 4;
4298 retval
= target_read_u16(target
, address
+ 2, &op
);
4299 if (retval
!= ERROR_OK
)
4302 instruction
->opcode
= opcode
;
4305 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4306 return thumb_evaluate_opcode(op
, address
, instruction
);
4309 snprintf(instruction
->text
, 128,
4310 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4312 cp
= strchr(instruction
->text
, 0);
4313 retval
= ERROR_FAIL
;
4315 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4316 if ((opcode
& 0x1a008000) == 0x10000000)
4317 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4319 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4320 else if ((opcode
& 0x1a008000) == 0x12000000)
4321 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4323 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4324 else if ((opcode
& 0x18008000) == 0x10008000)
4325 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4327 /* ARMv7-M: A5.3.5 Load/store multiple */
4328 else if ((opcode
& 0x1e400000) == 0x08000000)
4329 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4331 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4332 else if ((opcode
& 0x1e400000) == 0x08400000)
4333 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4335 /* ARMv7-M: A5.3.7 Load word */
4336 else if ((opcode
& 0x1f700000) == 0x18500000)
4337 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4339 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4340 else if ((opcode
& 0x1e700000) == 0x18300000)
4341 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4343 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4344 else if ((opcode
& 0x1e700000) == 0x18100000)
4345 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4347 /* ARMv7-M: A5.3.10 Store single data item */
4348 else if ((opcode
& 0x1f100000) == 0x18000000)
4349 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4351 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4352 else if ((opcode
& 0x1e000000) == 0x0a000000)
4353 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4355 /* ARMv7-M: A5.3.12 Data processing (register)
4356 * and A5.3.13 Miscellaneous operations
4358 else if ((opcode
& 0x1f000000) == 0x1a000000)
4359 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4361 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4362 else if ((opcode
& 0x1f800000) == 0x1b000000)
4363 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4365 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4366 else if ((opcode
& 0x1f800000) == 0x1b800000)
4367 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4369 if (retval
== ERROR_OK
)
4373 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4374 * instructions; not yet handled here.
4377 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4378 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4379 strcpy(cp
, "UNDEFINED OPCODE");
4383 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4386 strcpy(cp
, "(32-bit Thumb2 ...)");
4390 int arm_access_size(struct arm_instruction
*instruction
)
4392 if ((instruction
->type
== ARM_LDRB
)
4393 || (instruction
->type
== ARM_LDRBT
)
4394 || (instruction
->type
== ARM_LDRSB
)
4395 || (instruction
->type
== ARM_STRB
)
4396 || (instruction
->type
== ARM_STRBT
))
4400 else if ((instruction
->type
== ARM_LDRH
)
4401 || (instruction
->type
== ARM_LDRSH
)
4402 || (instruction
->type
== ARM_STRH
))
4406 else if ((instruction
->type
== ARM_LDR
)
4407 || (instruction
->type
== ARM_LDRT
)
4408 || (instruction
->type
== ARM_STR
)
4409 || (instruction
->type
== ARM_STRT
))
4413 else if ((instruction
->type
== ARM_LDRD
)
4414 || (instruction
->type
== ARM_STRD
))
4420 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction
->type
);
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)