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)) ? "!" : "";
140 switch ((opcode
>> 23) & 0x3) {
145 /* "IA" is default */
156 switch (opcode
& 0x0e500000) {
158 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
160 "\tSRS%s\tSP%s, #%d",
162 mode
, wback
, opcode
& 0x1f);
165 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
169 mode
, (opcode
>> 16) & 0xf, wback
);
172 return evaluate_unknown(opcode
, address
, instruction
);
177 static int evaluate_swi(uint32_t opcode
,
178 uint32_t address
, struct arm_instruction
*instruction
)
180 instruction
->type
= ARM_SWI
;
182 snprintf(instruction
->text
, 128,
183 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
184 address
, opcode
, (opcode
& 0xffffff));
189 static int evaluate_blx_imm(uint32_t opcode
,
190 uint32_t address
, struct arm_instruction
*instruction
)
194 uint32_t target_address
;
196 instruction
->type
= ARM_BLX
;
197 immediate
= opcode
& 0x00ffffff;
199 /* sign extend 24-bit immediate */
200 if (immediate
& 0x00800000)
201 offset
= 0xff000000 | immediate
;
205 /* shift two bits left */
208 /* odd/event halfword */
209 if (opcode
& 0x01000000)
212 target_address
= address
+ 8 + offset
;
214 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
216 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
217 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
222 static int evaluate_b_bl(uint32_t opcode
,
223 uint32_t address
, struct arm_instruction
*instruction
)
228 uint32_t target_address
;
230 immediate
= opcode
& 0x00ffffff;
231 L
= (opcode
& 0x01000000) >> 24;
233 /* sign extend 24-bit immediate */
234 if (immediate
& 0x00800000)
235 offset
= 0xff000000 | immediate
;
239 /* shift two bits left */
242 target_address
= address
+ 8 + offset
;
245 instruction
->type
= ARM_BL
;
247 instruction
->type
= ARM_B
;
249 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
250 (L
) ? "L" : "", COND(opcode
), target_address
);
252 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
253 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
258 /* Coprocessor load/store and double register transfers */
259 /* both normal and extended instruction space (condition field b1111) */
260 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
261 uint32_t address
, struct arm_instruction
*instruction
)
263 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
266 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
268 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
271 cp_opcode
= (opcode
& 0xf0) >> 4;
272 Rd
= (opcode
& 0xf000) >> 12;
273 Rn
= (opcode
& 0xf0000) >> 16;
274 CRm
= (opcode
& 0xf);
277 if ((opcode
& 0x0ff00000) == 0x0c400000)
279 instruction
->type
= ARM_MCRR
;
284 if ((opcode
& 0x0ff00000) == 0x0c500000)
286 instruction
->type
= ARM_MRRC
;
290 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
291 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
293 else /* LDC or STC */
295 uint8_t CRd
, Rn
, offset
;
298 char addressing_mode
[32];
300 CRd
= (opcode
& 0xf000) >> 12;
301 Rn
= (opcode
& 0xf0000) >> 16;
302 offset
= (opcode
& 0xff);
305 if (opcode
& 0x00100000)
307 instruction
->type
= ARM_LDC
;
312 instruction
->type
= ARM_STC
;
316 U
= (opcode
& 0x00800000) >> 23;
317 N
= (opcode
& 0x00400000) >> 22;
319 /* addressing modes */
320 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
321 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
322 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
323 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
324 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
325 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
326 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
327 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
329 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
330 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
332 cp_num
, CRd
, addressing_mode
);
338 /* Coprocessor data processing instructions */
339 /* Coprocessor register transfer instructions */
340 /* both normal and extended instruction space (condition field b1111) */
341 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
342 uint32_t address
, struct arm_instruction
*instruction
)
346 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
348 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
349 cp_num
= (opcode
& 0xf00) >> 8;
350 CRd_Rd
= (opcode
& 0xf000) >> 12;
351 CRn
= (opcode
& 0xf0000) >> 16;
352 CRm
= (opcode
& 0xf);
353 opcode_2
= (opcode
& 0xe0) >> 5;
356 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
358 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
360 instruction
->type
= ARM_MRC
;
363 else /* bit 20 not set -> MCR */
365 instruction
->type
= ARM_MCR
;
369 opcode_1
= (opcode
& 0x00e00000) >> 21;
371 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",
372 address
, opcode
, mnemonic
, cond
,
373 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
375 else /* bit 4 not set -> CDP */
377 instruction
->type
= ARM_CDP
;
380 opcode_1
= (opcode
& 0x00f00000) >> 20;
382 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",
383 address
, opcode
, mnemonic
, cond
,
384 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
390 /* Load/store instructions */
391 static int evaluate_load_store(uint32_t opcode
,
392 uint32_t address
, struct arm_instruction
*instruction
)
394 uint8_t I
, P
, U
, B
, W
, L
;
396 char *operation
; /* "LDR" or "STR" */
397 char *suffix
; /* "", "B", "T", "BT" */
401 I
= (opcode
& 0x02000000) >> 25;
402 P
= (opcode
& 0x01000000) >> 24;
403 U
= (opcode
& 0x00800000) >> 23;
404 B
= (opcode
& 0x00400000) >> 22;
405 W
= (opcode
& 0x00200000) >> 21;
406 L
= (opcode
& 0x00100000) >> 20;
408 /* target register */
409 Rd
= (opcode
& 0xf000) >> 12;
412 Rn
= (opcode
& 0xf0000) >> 16;
414 instruction
->info
.load_store
.Rd
= Rd
;
415 instruction
->info
.load_store
.Rn
= Rn
;
416 instruction
->info
.load_store
.U
= U
;
418 /* determine operation */
424 /* determine instruction type and suffix */
427 if ((P
== 0) && (W
== 1))
430 instruction
->type
= ARM_LDRBT
;
432 instruction
->type
= ARM_STRBT
;
438 instruction
->type
= ARM_LDRB
;
440 instruction
->type
= ARM_STRB
;
446 if ((P
== 0) && (W
== 1))
449 instruction
->type
= ARM_LDRT
;
451 instruction
->type
= ARM_STRT
;
457 instruction
->type
= ARM_LDR
;
459 instruction
->type
= ARM_STR
;
464 if (!I
) /* #+-<offset_12> */
466 uint32_t offset_12
= (opcode
& 0xfff);
468 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
470 snprintf(offset
, 32, "%s", "");
472 instruction
->info
.load_store
.offset_mode
= 0;
473 instruction
->info
.load_store
.offset
.offset
= offset_12
;
475 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
477 uint8_t shift_imm
, shift
;
480 shift_imm
= (opcode
& 0xf80) >> 7;
481 shift
= (opcode
& 0x60) >> 5;
484 /* LSR encodes a shift by 32 bit as 0x0 */
485 if ((shift
== 0x1) && (shift_imm
== 0x0))
488 /* ASR encodes a shift by 32 bit as 0x0 */
489 if ((shift
== 0x2) && (shift_imm
== 0x0))
492 /* ROR by 32 bit is actually a RRX */
493 if ((shift
== 0x3) && (shift_imm
== 0x0))
496 instruction
->info
.load_store
.offset_mode
= 1;
497 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
498 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
499 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
501 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
503 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
505 else /* +-<Rm>, <Shift>, #<shift_imm> */
510 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
513 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
516 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
519 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
522 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
530 if (W
== 0) /* offset */
532 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
533 address
, opcode
, operation
, COND(opcode
), suffix
,
536 instruction
->info
.load_store
.index_mode
= 0;
538 else /* pre-indexed */
540 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
541 address
, opcode
, operation
, COND(opcode
), suffix
,
544 instruction
->info
.load_store
.index_mode
= 1;
547 else /* post-indexed */
549 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
550 address
, opcode
, operation
, COND(opcode
), suffix
,
553 instruction
->info
.load_store
.index_mode
= 2;
559 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
561 unsigned rm
= (opcode
>> 0) & 0xf;
562 unsigned rd
= (opcode
>> 12) & 0xf;
563 unsigned rn
= (opcode
>> 16) & 0xf;
566 switch ((opcode
>> 24) & 0x3) {
571 sprintf(cp
, "UNDEFINED");
572 return ARM_UNDEFINED_INSTRUCTION
;
581 switch ((opcode
>> 10) & 0x3) {
597 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
598 (opcode
& (1 << 22)) ? 'U' : 'S',
603 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
604 (opcode
& (1 << 22)) ? 'U' : 'S',
611 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
617 switch ((opcode
>> 20) & 0x7) {
640 switch ((opcode
>> 5) & 0x7) {
669 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
670 (int) (opcode
>> 12) & 0xf,
671 (int) (opcode
>> 16) & 0xf,
672 (int) (opcode
>> 0) & 0xf);
676 /* these opcodes might be used someday */
677 sprintf(cp
, "UNDEFINED");
678 return ARM_UNDEFINED_INSTRUCTION
;
681 /* ARMv6 and later support "media" instructions (includes SIMD) */
682 static int evaluate_media(uint32_t opcode
, uint32_t address
,
683 struct arm_instruction
*instruction
)
685 char *cp
= instruction
->text
;
686 char *mnemonic
= NULL
;
689 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
693 /* parallel add/subtract */
694 if ((opcode
& 0x01800000) == 0x00000000) {
695 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
700 if ((opcode
& 0x01f00020) == 0x00800000) {
702 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
704 if (opcode
& (1 << 6)) {
713 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
715 (int) (opcode
>> 12) & 0xf,
716 (int) (opcode
>> 16) & 0xf,
717 (int) (opcode
>> 0) & 0xf,
723 if ((opcode
& 0x01a00020) == 0x00a00000) {
725 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
727 if (opcode
& (1 << 6)) {
735 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
736 (opcode
& (1 << 22)) ? 'U' : 'S',
738 (int) (opcode
>> 12) & 0xf,
739 (int) (opcode
>> 16) & 0x1f,
740 (int) (opcode
>> 0) & 0xf,
746 if ((opcode
& 0x018000f0) == 0x00800070) {
747 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
752 if ((opcode
& 0x01f00080) == 0x01000000) {
753 unsigned rn
= (opcode
>> 12) & 0xf;
756 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
757 (opcode
& (1 << 6)) ? 'S' : 'A',
758 (opcode
& (1 << 5)) ? "X" : "",
760 (int) (opcode
>> 16) & 0xf,
761 (int) (opcode
>> 0) & 0xf,
762 (int) (opcode
>> 8) & 0xf,
765 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
766 (opcode
& (1 << 6)) ? 'S' : 'A',
767 (opcode
& (1 << 5)) ? "X" : "",
769 (int) (opcode
>> 16) & 0xf,
770 (int) (opcode
>> 0) & 0xf,
771 (int) (opcode
>> 8) & 0xf);
774 if ((opcode
& 0x01f00000) == 0x01400000) {
775 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
776 (opcode
& (1 << 6)) ? 'S' : 'A',
777 (opcode
& (1 << 5)) ? "X" : "",
779 (int) (opcode
>> 12) & 0xf,
780 (int) (opcode
>> 16) & 0xf,
781 (int) (opcode
>> 0) & 0xf,
782 (int) (opcode
>> 8) & 0xf);
785 if ((opcode
& 0x01f00000) == 0x01500000) {
786 unsigned rn
= (opcode
>> 12) & 0xf;
788 switch (opcode
& 0xc0) {
800 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
801 (opcode
& (1 << 6)) ? 'S' : 'A',
802 (opcode
& (1 << 5)) ? "R" : "",
804 (int) (opcode
>> 16) & 0xf,
805 (int) (opcode
>> 0) & 0xf,
806 (int) (opcode
>> 8) & 0xf,
809 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
810 (opcode
& (1 << 5)) ? "R" : "",
812 (int) (opcode
>> 16) & 0xf,
813 (int) (opcode
>> 0) & 0xf,
814 (int) (opcode
>> 8) & 0xf);
819 /* simple matches against the remaining decode bits */
820 switch (opcode
& 0x01f000f0) {
823 /* parallel halfword saturate */
824 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
825 (opcode
& (1 << 22)) ? 'U' : 'S',
827 (int) (opcode
>> 12) & 0xf,
828 (int) (opcode
>> 16) & 0xf,
829 (int) (opcode
>> 0) & 0xf);
842 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
843 (int) (opcode
>> 12) & 0xf,
844 (int) (opcode
>> 16) & 0xf,
845 (int) (opcode
>> 0) & 0xf);
848 /* unsigned sum of absolute differences */
849 if (((opcode
>> 12) & 0xf) == 0xf)
850 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
851 (int) (opcode
>> 16) & 0xf,
852 (int) (opcode
>> 0) & 0xf,
853 (int) (opcode
>> 8) & 0xf);
855 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
856 (int) (opcode
>> 16) & 0xf,
857 (int) (opcode
>> 0) & 0xf,
858 (int) (opcode
>> 8) & 0xf,
859 (int) (opcode
>> 12) & 0xf);
863 unsigned rm
= (opcode
>> 0) & 0xf;
864 unsigned rd
= (opcode
>> 12) & 0xf;
866 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
871 /* these opcodes might be used someday */
872 sprintf(cp
, "UNDEFINED");
876 /* Miscellaneous load/store instructions */
877 static int evaluate_misc_load_store(uint32_t opcode
,
878 uint32_t address
, struct arm_instruction
*instruction
)
880 uint8_t P
, U
, I
, W
, L
, S
, H
;
882 char *operation
; /* "LDR" or "STR" */
883 char *suffix
; /* "H", "SB", "SH", "D" */
887 P
= (opcode
& 0x01000000) >> 24;
888 U
= (opcode
& 0x00800000) >> 23;
889 I
= (opcode
& 0x00400000) >> 22;
890 W
= (opcode
& 0x00200000) >> 21;
891 L
= (opcode
& 0x00100000) >> 20;
892 S
= (opcode
& 0x00000040) >> 6;
893 H
= (opcode
& 0x00000020) >> 5;
895 /* target register */
896 Rd
= (opcode
& 0xf000) >> 12;
899 Rn
= (opcode
& 0xf0000) >> 16;
901 instruction
->info
.load_store
.Rd
= Rd
;
902 instruction
->info
.load_store
.Rn
= Rn
;
903 instruction
->info
.load_store
.U
= U
;
905 /* determine instruction type and suffix */
913 instruction
->type
= ARM_LDRSH
;
919 instruction
->type
= ARM_LDRSB
;
923 else /* there are no signed stores, so this is used to encode double-register load/stores */
929 instruction
->type
= ARM_STRD
;
934 instruction
->type
= ARM_LDRD
;
944 instruction
->type
= ARM_LDRH
;
949 instruction
->type
= ARM_STRH
;
953 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
955 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
956 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
958 instruction
->info
.load_store
.offset_mode
= 0;
959 instruction
->info
.load_store
.offset
.offset
= offset_8
;
961 else /* Register offset/index (+-<Rm>) */
965 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
967 instruction
->info
.load_store
.offset_mode
= 1;
968 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
969 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
970 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
975 if (W
== 0) /* offset */
977 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
978 address
, opcode
, operation
, COND(opcode
), suffix
,
981 instruction
->info
.load_store
.index_mode
= 0;
983 else /* pre-indexed */
985 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
986 address
, opcode
, operation
, COND(opcode
), suffix
,
989 instruction
->info
.load_store
.index_mode
= 1;
992 else /* post-indexed */
994 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
995 address
, opcode
, operation
, COND(opcode
), suffix
,
998 instruction
->info
.load_store
.index_mode
= 2;
1004 /* Load/store multiples instructions */
1005 static int evaluate_ldm_stm(uint32_t opcode
,
1006 uint32_t address
, struct arm_instruction
*instruction
)
1008 uint8_t P
, U
, S
, W
, L
, Rn
;
1009 uint32_t register_list
;
1010 char *addressing_mode
;
1017 P
= (opcode
& 0x01000000) >> 24;
1018 U
= (opcode
& 0x00800000) >> 23;
1019 S
= (opcode
& 0x00400000) >> 22;
1020 W
= (opcode
& 0x00200000) >> 21;
1021 L
= (opcode
& 0x00100000) >> 20;
1022 register_list
= (opcode
& 0xffff);
1023 Rn
= (opcode
& 0xf0000) >> 16;
1025 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1026 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1027 instruction
->info
.load_store_multiple
.S
= S
;
1028 instruction
->info
.load_store_multiple
.W
= W
;
1032 instruction
->type
= ARM_LDM
;
1037 instruction
->type
= ARM_STM
;
1045 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1046 addressing_mode
= "IB";
1050 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1051 addressing_mode
= "DB";
1058 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1059 /* "IA" is the default in UAL syntax */
1060 addressing_mode
= "";
1064 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1065 addressing_mode
= "DA";
1069 reg_list_p
= reg_list
;
1070 for (i
= 0; i
<= 15; i
++)
1072 if ((register_list
>> i
) & 1)
1077 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1081 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1086 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
1087 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
1088 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1093 /* Multiplies, extra load/stores */
1094 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1095 uint32_t address
, struct arm_instruction
*instruction
)
1097 /* Multiply (accumulate) (long) and Swap/swap byte */
1098 if ((opcode
& 0x000000f0) == 0x00000090)
1100 /* Multiply (accumulate) */
1101 if ((opcode
& 0x0f800000) == 0x00000000)
1103 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1105 Rs
= (opcode
& 0xf00) >> 8;
1106 Rn
= (opcode
& 0xf000) >> 12;
1107 Rd
= (opcode
& 0xf0000) >> 16;
1108 S
= (opcode
& 0x00100000) >> 20;
1110 /* examine A bit (accumulate) */
1111 if (opcode
& 0x00200000)
1113 instruction
->type
= ARM_MLA
;
1114 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1115 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1119 instruction
->type
= ARM_MUL
;
1120 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1121 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1127 /* Multiply (accumulate) long */
1128 if ((opcode
& 0x0f800000) == 0x00800000)
1130 char* mnemonic
= NULL
;
1131 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1133 Rs
= (opcode
& 0xf00) >> 8;
1134 RdHi
= (opcode
& 0xf000) >> 12;
1135 RdLow
= (opcode
& 0xf0000) >> 16;
1136 S
= (opcode
& 0x00100000) >> 20;
1138 switch ((opcode
& 0x00600000) >> 21)
1141 instruction
->type
= ARM_UMULL
;
1145 instruction
->type
= ARM_UMLAL
;
1149 instruction
->type
= ARM_SMULL
;
1153 instruction
->type
= ARM_SMLAL
;
1158 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1159 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1160 RdLow
, RdHi
, Rm
, Rs
);
1165 /* Swap/swap byte */
1166 if ((opcode
& 0x0f800000) == 0x01000000)
1170 Rd
= (opcode
& 0xf000) >> 12;
1171 Rn
= (opcode
& 0xf0000) >> 16;
1173 /* examine B flag */
1174 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1176 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1177 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1183 return evaluate_misc_load_store(opcode
, address
, instruction
);
1186 static int evaluate_mrs_msr(uint32_t opcode
,
1187 uint32_t address
, struct arm_instruction
*instruction
)
1189 int R
= (opcode
& 0x00400000) >> 22;
1190 char *PSR
= (R
) ? "SPSR" : "CPSR";
1192 /* Move register to status register (MSR) */
1193 if (opcode
& 0x00200000)
1195 instruction
->type
= ARM_MSR
;
1197 /* immediate variant */
1198 if (opcode
& 0x02000000)
1200 uint8_t immediate
= (opcode
& 0xff);
1201 uint8_t rotate
= (opcode
& 0xf00);
1203 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1204 address
, opcode
, COND(opcode
), PSR
,
1205 (opcode
& 0x10000) ? "c" : "",
1206 (opcode
& 0x20000) ? "x" : "",
1207 (opcode
& 0x40000) ? "s" : "",
1208 (opcode
& 0x80000) ? "f" : "",
1209 ror(immediate
, (rotate
* 2))
1212 else /* register variant */
1214 uint8_t Rm
= opcode
& 0xf;
1215 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1216 address
, opcode
, COND(opcode
), PSR
,
1217 (opcode
& 0x10000) ? "c" : "",
1218 (opcode
& 0x20000) ? "x" : "",
1219 (opcode
& 0x40000) ? "s" : "",
1220 (opcode
& 0x80000) ? "f" : "",
1226 else /* Move status register to register (MRS) */
1230 instruction
->type
= ARM_MRS
;
1231 Rd
= (opcode
& 0x0000f000) >> 12;
1233 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1234 address
, opcode
, COND(opcode
), Rd
, PSR
);
1240 /* Miscellaneous instructions */
1241 static int evaluate_misc_instr(uint32_t opcode
,
1242 uint32_t address
, struct arm_instruction
*instruction
)
1245 if ((opcode
& 0x000000f0) == 0x00000000)
1247 evaluate_mrs_msr(opcode
, address
, instruction
);
1251 if ((opcode
& 0x006000f0) == 0x00200010)
1254 instruction
->type
= ARM_BX
;
1257 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1258 address
, opcode
, COND(opcode
), Rm
);
1260 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1261 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1264 /* BXJ - "Jazelle" support (ARMv5-J) */
1265 if ((opcode
& 0x006000f0) == 0x00200020)
1268 instruction
->type
= ARM_BX
;
1271 snprintf(instruction
->text
, 128,
1272 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1273 address
, opcode
, COND(opcode
), Rm
);
1275 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1276 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1280 if ((opcode
& 0x006000f0) == 0x00600010)
1283 instruction
->type
= ARM_CLZ
;
1285 Rd
= (opcode
& 0xf000) >> 12;
1287 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1288 address
, opcode
, COND(opcode
), Rd
, Rm
);
1292 if ((opcode
& 0x006000f0) == 0x00200030)
1295 instruction
->type
= ARM_BLX
;
1298 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1299 address
, opcode
, COND(opcode
), Rm
);
1301 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1302 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1305 /* Enhanced DSP add/subtracts */
1306 if ((opcode
& 0x0000000f0) == 0x00000050)
1309 char *mnemonic
= NULL
;
1311 Rd
= (opcode
& 0xf000) >> 12;
1312 Rn
= (opcode
& 0xf0000) >> 16;
1314 switch ((opcode
& 0x00600000) >> 21)
1317 instruction
->type
= ARM_QADD
;
1321 instruction
->type
= ARM_QSUB
;
1325 instruction
->type
= ARM_QDADD
;
1329 instruction
->type
= ARM_QDSUB
;
1334 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1335 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1338 /* Software breakpoints */
1339 if ((opcode
& 0x0000000f0) == 0x00000070)
1342 instruction
->type
= ARM_BKPT
;
1343 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1345 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1346 address
, opcode
, immediate
);
1349 /* Enhanced DSP multiplies */
1350 if ((opcode
& 0x000000090) == 0x00000080)
1352 int x
= (opcode
& 0x20) >> 5;
1353 int y
= (opcode
& 0x40) >> 6;
1356 if ((opcode
& 0x00600000) == 0x00000000)
1358 uint8_t Rd
, Rm
, Rs
, Rn
;
1359 instruction
->type
= ARM_SMLAxy
;
1360 Rd
= (opcode
& 0xf0000) >> 16;
1361 Rm
= (opcode
& 0xf);
1362 Rs
= (opcode
& 0xf00) >> 8;
1363 Rn
= (opcode
& 0xf000) >> 12;
1365 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1366 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1371 if ((opcode
& 0x00600000) == 0x00400000)
1373 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1374 instruction
->type
= ARM_SMLAxy
;
1375 RdHi
= (opcode
& 0xf0000) >> 16;
1376 RdLow
= (opcode
& 0xf000) >> 12;
1377 Rm
= (opcode
& 0xf);
1378 Rs
= (opcode
& 0xf00) >> 8;
1380 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1381 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1382 RdLow
, RdHi
, Rm
, Rs
);
1386 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1388 uint8_t Rd
, Rm
, Rs
, Rn
;
1389 instruction
->type
= ARM_SMLAWy
;
1390 Rd
= (opcode
& 0xf0000) >> 16;
1391 Rm
= (opcode
& 0xf);
1392 Rs
= (opcode
& 0xf00) >> 8;
1393 Rn
= (opcode
& 0xf000) >> 12;
1395 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1396 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1401 if ((opcode
& 0x00600000) == 0x00300000)
1404 instruction
->type
= ARM_SMULxy
;
1405 Rd
= (opcode
& 0xf0000) >> 16;
1406 Rm
= (opcode
& 0xf);
1407 Rs
= (opcode
& 0xf00) >> 8;
1409 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1410 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1415 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1418 instruction
->type
= ARM_SMULWy
;
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 r%i, r%i, r%i",
1424 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1432 static int evaluate_data_proc(uint32_t opcode
,
1433 uint32_t address
, struct arm_instruction
*instruction
)
1435 uint8_t I
, op
, S
, Rn
, Rd
;
1436 char *mnemonic
= NULL
;
1437 char shifter_operand
[32];
1439 I
= (opcode
& 0x02000000) >> 25;
1440 op
= (opcode
& 0x01e00000) >> 21;
1441 S
= (opcode
& 0x00100000) >> 20;
1443 Rd
= (opcode
& 0xf000) >> 12;
1444 Rn
= (opcode
& 0xf0000) >> 16;
1446 instruction
->info
.data_proc
.Rd
= Rd
;
1447 instruction
->info
.data_proc
.Rn
= Rn
;
1448 instruction
->info
.data_proc
.S
= S
;
1453 instruction
->type
= ARM_AND
;
1457 instruction
->type
= ARM_EOR
;
1461 instruction
->type
= ARM_SUB
;
1465 instruction
->type
= ARM_RSB
;
1469 instruction
->type
= ARM_ADD
;
1473 instruction
->type
= ARM_ADC
;
1477 instruction
->type
= ARM_SBC
;
1481 instruction
->type
= ARM_RSC
;
1485 instruction
->type
= ARM_TST
;
1489 instruction
->type
= ARM_TEQ
;
1493 instruction
->type
= ARM_CMP
;
1497 instruction
->type
= ARM_CMN
;
1501 instruction
->type
= ARM_ORR
;
1505 instruction
->type
= ARM_MOV
;
1509 instruction
->type
= ARM_BIC
;
1513 instruction
->type
= ARM_MVN
;
1518 if (I
) /* immediate shifter operand (#<immediate>)*/
1520 uint8_t immed_8
= opcode
& 0xff;
1521 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1524 immediate
= ror(immed_8
, rotate_imm
* 2);
1526 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1528 instruction
->info
.data_proc
.variant
= 0;
1529 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1531 else /* register-based shifter operand */
1534 shift
= (opcode
& 0x60) >> 5;
1535 Rm
= (opcode
& 0xf);
1537 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1540 shift_imm
= (opcode
& 0xf80) >> 7;
1542 instruction
->info
.data_proc
.variant
= 1;
1543 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1544 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1545 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1547 /* LSR encodes a shift by 32 bit as 0x0 */
1548 if ((shift
== 0x1) && (shift_imm
== 0x0))
1551 /* ASR encodes a shift by 32 bit as 0x0 */
1552 if ((shift
== 0x2) && (shift_imm
== 0x0))
1555 /* ROR by 32 bit is actually a RRX */
1556 if ((shift
== 0x3) && (shift_imm
== 0x0))
1559 if ((shift_imm
== 0x0) && (shift
== 0x0))
1561 snprintf(shifter_operand
, 32, "r%i", Rm
);
1565 if (shift
== 0x0) /* LSL */
1567 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1569 else if (shift
== 0x1) /* LSR */
1571 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1573 else if (shift
== 0x2) /* ASR */
1575 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1577 else if (shift
== 0x3) /* ROR */
1579 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1581 else if (shift
== 0x4) /* RRX */
1583 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1587 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1589 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1591 instruction
->info
.data_proc
.variant
= 2;
1592 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1593 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1594 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1596 if (shift
== 0x0) /* LSL */
1598 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1600 else if (shift
== 0x1) /* LSR */
1602 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1604 else if (shift
== 0x2) /* ASR */
1606 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1608 else if (shift
== 0x3) /* ROR */
1610 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1615 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1617 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1618 address
, opcode
, mnemonic
, COND(opcode
),
1619 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1621 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1623 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1624 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1626 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1627 address
, opcode
, mnemonic
, COND(opcode
),
1628 (S
) ? "S" : "", Rd
, shifter_operand
);
1630 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1632 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1633 address
, opcode
, mnemonic
, COND(opcode
),
1634 Rn
, shifter_operand
);
1640 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
1642 /* clear fields, to avoid confusion */
1643 memset(instruction
, 0, sizeof(struct arm_instruction
));
1644 instruction
->opcode
= opcode
;
1645 instruction
->instruction_size
= 4;
1647 /* catch opcodes with condition field [31:28] = b1111 */
1648 if ((opcode
& 0xf0000000) == 0xf0000000)
1650 /* Undefined instruction (or ARMv5E cache preload PLD) */
1651 if ((opcode
& 0x08000000) == 0x00000000)
1652 return evaluate_pld(opcode
, address
, instruction
);
1654 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1655 if ((opcode
& 0x0e000000) == 0x08000000)
1656 return evaluate_srs(opcode
, address
, instruction
);
1658 /* Branch and branch with link and change to Thumb */
1659 if ((opcode
& 0x0e000000) == 0x0a000000)
1660 return evaluate_blx_imm(opcode
, address
, instruction
);
1662 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1663 /* Coprocessor load/store and double register transfers */
1664 if ((opcode
& 0x0e000000) == 0x0c000000)
1665 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1667 /* Coprocessor data processing */
1668 if ((opcode
& 0x0f000100) == 0x0c000000)
1669 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1671 /* Coprocessor register transfers */
1672 if ((opcode
& 0x0f000010) == 0x0c000010)
1673 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1675 /* Undefined instruction */
1676 if ((opcode
& 0x0f000000) == 0x0f000000)
1678 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1679 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1684 /* catch opcodes with [27:25] = b000 */
1685 if ((opcode
& 0x0e000000) == 0x00000000)
1687 /* Multiplies, extra load/stores */
1688 if ((opcode
& 0x00000090) == 0x00000090)
1689 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1691 /* Miscellaneous instructions */
1692 if ((opcode
& 0x0f900000) == 0x01000000)
1693 return evaluate_misc_instr(opcode
, address
, instruction
);
1695 return evaluate_data_proc(opcode
, address
, instruction
);
1698 /* catch opcodes with [27:25] = b001 */
1699 if ((opcode
& 0x0e000000) == 0x02000000)
1701 /* Undefined instruction */
1702 if ((opcode
& 0x0fb00000) == 0x03000000)
1704 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1705 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1709 /* Move immediate to status register */
1710 if ((opcode
& 0x0fb00000) == 0x03200000)
1711 return evaluate_mrs_msr(opcode
, address
, instruction
);
1713 return evaluate_data_proc(opcode
, address
, instruction
);
1717 /* catch opcodes with [27:25] = b010 */
1718 if ((opcode
& 0x0e000000) == 0x04000000)
1720 /* Load/store immediate offset */
1721 return evaluate_load_store(opcode
, address
, instruction
);
1724 /* catch opcodes with [27:25] = b011 */
1725 if ((opcode
& 0x0e000000) == 0x06000000)
1727 /* Load/store register offset */
1728 if ((opcode
& 0x00000010) == 0x00000000)
1729 return evaluate_load_store(opcode
, address
, instruction
);
1731 /* Architecturally Undefined instruction
1732 * ... don't expect these to ever be used
1734 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1736 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1737 snprintf(instruction
->text
, 128,
1738 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1743 /* "media" instructions */
1744 return evaluate_media(opcode
, address
, instruction
);
1747 /* catch opcodes with [27:25] = b100 */
1748 if ((opcode
& 0x0e000000) == 0x08000000)
1750 /* Load/store multiple */
1751 return evaluate_ldm_stm(opcode
, address
, instruction
);
1754 /* catch opcodes with [27:25] = b101 */
1755 if ((opcode
& 0x0e000000) == 0x0a000000)
1757 /* Branch and branch with link */
1758 return evaluate_b_bl(opcode
, address
, instruction
);
1761 /* catch opcodes with [27:25] = b110 */
1762 if ((opcode
& 0x0e000000) == 0x0a000000)
1764 /* Coprocessor load/store and double register transfers */
1765 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1768 /* catch opcodes with [27:25] = b111 */
1769 if ((opcode
& 0x0e000000) == 0x0e000000)
1771 /* Software interrupt */
1772 if ((opcode
& 0x0f000000) == 0x0f000000)
1773 return evaluate_swi(opcode
, address
, instruction
);
1775 /* Coprocessor data processing */
1776 if ((opcode
& 0x0f000010) == 0x0e000000)
1777 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1779 /* Coprocessor register transfers */
1780 if ((opcode
& 0x0f000010) == 0x0e000010)
1781 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1784 LOG_ERROR("should never reach this point");
1788 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1789 uint32_t address
, struct arm_instruction
*instruction
)
1791 uint32_t offset
= opcode
& 0x7ff;
1792 uint32_t opc
= (opcode
>> 11) & 0x3;
1793 uint32_t target_address
;
1794 char *mnemonic
= NULL
;
1796 /* sign extend 11-bit offset */
1797 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1798 offset
= 0xfffff800 | offset
;
1800 target_address
= address
+ 4 + (offset
<< 1);
1804 /* unconditional branch */
1806 instruction
->type
= ARM_B
;
1811 instruction
->type
= ARM_BLX
;
1813 target_address
&= 0xfffffffc;
1817 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1818 mnemonic
= "prefix";
1819 target_address
= offset
<< 12;
1823 instruction
->type
= ARM_BL
;
1828 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1829 * these are effectively 32-bit instructions even in Thumb1. For
1830 * disassembly, it's simplest to always use the Thumb2 decoder.
1832 * But some cores will evidently handle them as two instructions,
1833 * where exceptions may occur between the two. The ETMv3.2+ ID
1834 * register has a bit which exposes this behavior.
1837 snprintf(instruction
->text
, 128,
1838 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1839 address
, opcode
, mnemonic
, target_address
);
1841 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1842 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1847 static int evaluate_add_sub_thumb(uint16_t opcode
,
1848 uint32_t address
, struct arm_instruction
*instruction
)
1850 uint8_t Rd
= (opcode
>> 0) & 0x7;
1851 uint8_t Rn
= (opcode
>> 3) & 0x7;
1852 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1853 uint32_t opc
= opcode
& (1 << 9);
1854 uint32_t reg_imm
= opcode
& (1 << 10);
1859 instruction
->type
= ARM_SUB
;
1864 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1865 instruction
->type
= ARM_ADD
;
1869 instruction
->info
.data_proc
.Rd
= Rd
;
1870 instruction
->info
.data_proc
.Rn
= Rn
;
1871 instruction
->info
.data_proc
.S
= 1;
1875 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1876 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1877 snprintf(instruction
->text
, 128,
1878 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1879 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1883 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1884 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1885 snprintf(instruction
->text
, 128,
1886 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1887 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1893 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1894 uint32_t address
, struct arm_instruction
*instruction
)
1896 uint8_t Rd
= (opcode
>> 0) & 0x7;
1897 uint8_t Rm
= (opcode
>> 3) & 0x7;
1898 uint8_t imm
= (opcode
>> 6) & 0x1f;
1899 uint8_t opc
= (opcode
>> 11) & 0x3;
1900 char *mnemonic
= NULL
;
1905 instruction
->type
= ARM_MOV
;
1907 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1910 instruction
->type
= ARM_MOV
;
1912 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1915 instruction
->type
= ARM_MOV
;
1917 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1921 if ((imm
== 0) && (opc
!= 0))
1924 instruction
->info
.data_proc
.Rd
= Rd
;
1925 instruction
->info
.data_proc
.Rn
= -1;
1926 instruction
->info
.data_proc
.S
= 1;
1928 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1929 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1930 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1932 snprintf(instruction
->text
, 128,
1933 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1934 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1939 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1940 uint32_t address
, struct arm_instruction
*instruction
)
1942 uint8_t imm
= opcode
& 0xff;
1943 uint8_t Rd
= (opcode
>> 8) & 0x7;
1944 uint32_t opc
= (opcode
>> 11) & 0x3;
1945 char *mnemonic
= NULL
;
1947 instruction
->info
.data_proc
.Rd
= Rd
;
1948 instruction
->info
.data_proc
.Rn
= Rd
;
1949 instruction
->info
.data_proc
.S
= 1;
1950 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1951 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1956 instruction
->type
= ARM_MOV
;
1958 instruction
->info
.data_proc
.Rn
= -1;
1961 instruction
->type
= ARM_CMP
;
1963 instruction
->info
.data_proc
.Rd
= -1;
1966 instruction
->type
= ARM_ADD
;
1970 instruction
->type
= ARM_SUB
;
1975 snprintf(instruction
->text
, 128,
1976 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1977 address
, opcode
, mnemonic
, Rd
, imm
);
1982 static int evaluate_data_proc_thumb(uint16_t opcode
,
1983 uint32_t address
, struct arm_instruction
*instruction
)
1985 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1986 char *mnemonic
= NULL
;
1989 high_reg
= (opcode
& 0x0400) >> 10;
1990 op
= (opcode
& 0x03C0) >> 6;
1992 Rd
= (opcode
& 0x0007);
1993 Rm
= (opcode
& 0x0038) >> 3;
1994 H1
= (opcode
& 0x0080) >> 7;
1995 H2
= (opcode
& 0x0040) >> 6;
1997 instruction
->info
.data_proc
.Rd
= Rd
;
1998 instruction
->info
.data_proc
.Rn
= Rd
;
1999 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2000 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2001 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2012 instruction
->type
= ARM_ADD
;
2016 instruction
->type
= ARM_CMP
;
2020 instruction
->type
= ARM_MOV
;
2026 if ((opcode
& 0x7) == 0x0)
2028 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2031 instruction
->type
= ARM_BLX
;
2032 snprintf(instruction
->text
, 128,
2034 " 0x%4.4x \tBLX\tr%i",
2035 address
, opcode
, Rm
);
2039 instruction
->type
= ARM_BX
;
2040 snprintf(instruction
->text
, 128,
2042 " 0x%4.4x \tBX\tr%i",
2043 address
, opcode
, Rm
);
2048 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2049 snprintf(instruction
->text
, 128,
2052 "UNDEFINED INSTRUCTION",
2064 instruction
->type
= ARM_AND
;
2068 instruction
->type
= ARM_EOR
;
2072 instruction
->type
= ARM_MOV
;
2074 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2075 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2076 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2077 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2080 instruction
->type
= ARM_MOV
;
2082 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2083 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2084 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2085 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2088 instruction
->type
= ARM_MOV
;
2090 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2091 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
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_ADC
;
2100 instruction
->type
= ARM_SBC
;
2104 instruction
->type
= ARM_MOV
;
2106 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2107 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
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_TST
;
2116 instruction
->type
= ARM_RSB
;
2118 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2119 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2120 instruction
->info
.data_proc
.Rn
= Rm
;
2123 instruction
->type
= ARM_CMP
;
2127 instruction
->type
= ARM_CMN
;
2131 instruction
->type
= ARM_ORR
;
2135 instruction
->type
= ARM_MUL
;
2139 instruction
->type
= ARM_BIC
;
2143 instruction
->type
= ARM_MVN
;
2150 snprintf(instruction
->text
, 128,
2151 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2153 address
, opcode
, mnemonic
, Rd
, Rm
);
2155 snprintf(instruction
->text
, 128,
2156 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2157 address
, opcode
, mnemonic
, Rd
, Rm
);
2162 /* PC-relative data addressing is word-aligned even with Thumb */
2163 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2165 return (addr
+ 4) & ~3;
2168 static int evaluate_load_literal_thumb(uint16_t opcode
,
2169 uint32_t address
, struct arm_instruction
*instruction
)
2172 uint8_t Rd
= (opcode
>> 8) & 0x7;
2174 instruction
->type
= ARM_LDR
;
2175 immediate
= opcode
& 0x000000ff;
2178 instruction
->info
.load_store
.Rd
= Rd
;
2179 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2180 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2181 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2182 instruction
->info
.load_store
.offset
.offset
= immediate
;
2184 snprintf(instruction
->text
, 128,
2185 "0x%8.8" PRIx32
" 0x%4.4x \t"
2186 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2187 address
, opcode
, Rd
, immediate
,
2188 thumb_alignpc4(address
) + immediate
);
2193 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2194 uint32_t address
, struct arm_instruction
*instruction
)
2196 uint8_t Rd
= (opcode
>> 0) & 0x7;
2197 uint8_t Rn
= (opcode
>> 3) & 0x7;
2198 uint8_t Rm
= (opcode
>> 6) & 0x7;
2199 uint8_t opc
= (opcode
>> 9) & 0x7;
2200 char *mnemonic
= NULL
;
2205 instruction
->type
= ARM_STR
;
2209 instruction
->type
= ARM_STRH
;
2213 instruction
->type
= ARM_STRB
;
2217 instruction
->type
= ARM_LDRSB
;
2221 instruction
->type
= ARM_LDR
;
2225 instruction
->type
= ARM_LDRH
;
2229 instruction
->type
= ARM_LDRB
;
2233 instruction
->type
= ARM_LDRSH
;
2238 snprintf(instruction
->text
, 128,
2239 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2240 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2242 instruction
->info
.load_store
.Rd
= Rd
;
2243 instruction
->info
.load_store
.Rn
= Rn
;
2244 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2245 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2246 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2251 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2252 uint32_t address
, struct arm_instruction
*instruction
)
2254 uint32_t offset
= (opcode
>> 6) & 0x1f;
2255 uint8_t Rd
= (opcode
>> 0) & 0x7;
2256 uint8_t Rn
= (opcode
>> 3) & 0x7;
2257 uint32_t L
= opcode
& (1 << 11);
2258 uint32_t B
= opcode
& (1 << 12);
2265 instruction
->type
= ARM_LDR
;
2270 instruction
->type
= ARM_STR
;
2274 if ((opcode
&0xF000) == 0x8000)
2285 snprintf(instruction
->text
, 128,
2286 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2287 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2289 instruction
->info
.load_store
.Rd
= Rd
;
2290 instruction
->info
.load_store
.Rn
= Rn
;
2291 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2292 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2293 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2298 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2299 uint32_t address
, struct arm_instruction
*instruction
)
2301 uint32_t offset
= opcode
& 0xff;
2302 uint8_t Rd
= (opcode
>> 8) & 0x7;
2303 uint32_t L
= opcode
& (1 << 11);
2308 instruction
->type
= ARM_LDR
;
2313 instruction
->type
= ARM_STR
;
2317 snprintf(instruction
->text
, 128,
2318 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2319 address
, opcode
, mnemonic
, Rd
, offset
*4);
2321 instruction
->info
.load_store
.Rd
= Rd
;
2322 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2323 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2324 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2325 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2330 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2331 uint32_t address
, struct arm_instruction
*instruction
)
2333 uint32_t imm
= opcode
& 0xff;
2334 uint8_t Rd
= (opcode
>> 8) & 0x7;
2336 uint32_t SP
= opcode
& (1 << 11);
2339 instruction
->type
= ARM_ADD
;
2352 snprintf(instruction
->text
, 128,
2353 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2354 address
, opcode
, Rd
, reg_name
, imm
* 4);
2356 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2357 instruction
->info
.data_proc
.Rd
= Rd
;
2358 instruction
->info
.data_proc
.Rn
= Rn
;
2359 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2364 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2365 uint32_t address
, struct arm_instruction
*instruction
)
2367 uint32_t imm
= opcode
& 0x7f;
2368 uint8_t opc
= opcode
& (1 << 7);
2374 instruction
->type
= ARM_SUB
;
2379 instruction
->type
= ARM_ADD
;
2383 snprintf(instruction
->text
, 128,
2384 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2385 address
, opcode
, mnemonic
, imm
*4);
2387 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2388 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2389 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2390 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2395 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2396 uint32_t address
, struct arm_instruction
*instruction
)
2398 uint32_t imm
= opcode
& 0xff;
2400 instruction
->type
= ARM_BKPT
;
2402 snprintf(instruction
->text
, 128,
2403 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2404 address
, opcode
, imm
);
2409 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2410 uint32_t address
, struct arm_instruction
*instruction
)
2412 uint32_t reg_list
= opcode
& 0xff;
2413 uint32_t L
= opcode
& (1 << 11);
2414 uint32_t R
= opcode
& (1 << 8);
2415 uint8_t Rn
= (opcode
>> 8) & 7;
2416 uint8_t addr_mode
= 0 /* IA */;
2420 char ptr_name
[7] = "";
2423 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2424 * The STMIA and LDMIA opcodes are used for other instructions.
2427 if ((opcode
& 0xf000) == 0xc000)
2428 { /* generic load/store multiple */
2433 instruction
->type
= ARM_LDM
;
2435 if (opcode
& (1 << Rn
))
2440 instruction
->type
= ARM_STM
;
2443 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2450 instruction
->type
= ARM_LDM
;
2453 reg_list
|= (1 << 15) /*PC*/;
2457 instruction
->type
= ARM_STM
;
2459 addr_mode
= 3; /*DB*/
2461 reg_list
|= (1 << 14) /*LR*/;
2465 reg_names_p
= reg_names
;
2466 for (i
= 0; i
<= 15; i
++)
2468 if (reg_list
& (1 << i
))
2469 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2471 if (reg_names_p
> reg_names
)
2472 reg_names_p
[-2] = '\0';
2473 else /* invalid op : no registers */
2474 reg_names
[0] = '\0';
2476 snprintf(instruction
->text
, 128,
2477 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2478 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2480 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2481 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2482 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2487 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2488 uint32_t address
, struct arm_instruction
*instruction
)
2490 uint32_t offset
= opcode
& 0xff;
2491 uint8_t cond
= (opcode
>> 8) & 0xf;
2492 uint32_t target_address
;
2496 instruction
->type
= ARM_SWI
;
2497 snprintf(instruction
->text
, 128,
2498 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2499 address
, opcode
, offset
);
2502 else if (cond
== 0xe)
2504 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2505 snprintf(instruction
->text
, 128,
2506 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2511 /* sign extend 8-bit offset */
2512 if (offset
& 0x00000080)
2513 offset
= 0xffffff00 | offset
;
2515 target_address
= address
+ 4 + (offset
<< 1);
2517 snprintf(instruction
->text
, 128,
2518 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2520 arm_condition_strings
[cond
], target_address
);
2522 instruction
->type
= ARM_B
;
2523 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2524 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2529 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2530 struct arm_instruction
*instruction
)
2534 /* added in Thumb2 */
2535 offset
= (opcode
>> 3) & 0x1f;
2536 offset
|= (opcode
& 0x0200) >> 4;
2538 snprintf(instruction
->text
, 128,
2539 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2541 (opcode
& 0x0800) ? "N" : "",
2542 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2547 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2548 struct arm_instruction
*instruction
)
2550 /* added in ARMv6 */
2551 snprintf(instruction
->text
, 128,
2552 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2554 (opcode
& 0x0080) ? 'U' : 'S',
2555 (opcode
& 0x0040) ? 'B' : 'H',
2556 opcode
& 0x7, (opcode
>> 3) & 0x7);
2561 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2562 struct arm_instruction
*instruction
)
2564 /* added in ARMv6 */
2565 if ((opcode
& 0x0ff0) == 0x0650)
2566 snprintf(instruction
->text
, 128,
2567 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2569 (opcode
& 0x80) ? "BE" : "LE");
2570 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2571 snprintf(instruction
->text
, 128,
2572 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2574 (opcode
& 0x0010) ? 'D' : 'E',
2575 (opcode
& 0x0004) ? "A" : "",
2576 (opcode
& 0x0002) ? "I" : "",
2577 (opcode
& 0x0001) ? "F" : "");
2582 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2583 struct arm_instruction
*instruction
)
2587 /* added in ARMv6 */
2588 switch ((opcode
>> 6) & 3) {
2599 snprintf(instruction
->text
, 128,
2600 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2601 address
, opcode
, suffix
,
2602 opcode
& 0x7, (opcode
>> 3) & 0x7);
2607 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2608 struct arm_instruction
*instruction
)
2612 switch ((opcode
>> 4) & 0x0f) {
2629 hint
= "HINT (UNRECOGNIZED)";
2633 snprintf(instruction
->text
, 128,
2634 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2635 address
, opcode
, hint
);
2640 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2641 struct arm_instruction
*instruction
)
2643 unsigned cond
= (opcode
>> 4) & 0x0f;
2644 char *x
= "", *y
= "", *z
= "";
2647 z
= (opcode
& 0x02) ? "T" : "E";
2649 y
= (opcode
& 0x04) ? "T" : "E";
2651 x
= (opcode
& 0x08) ? "T" : "E";
2653 snprintf(instruction
->text
, 128,
2654 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2656 x
, y
, z
, arm_condition_strings
[cond
]);
2658 /* NOTE: strictly speaking, the next 1-4 instructions should
2659 * now be displayed with the relevant conditional suffix...
2665 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2667 /* clear fields, to avoid confusion */
2668 memset(instruction
, 0, sizeof(struct arm_instruction
));
2669 instruction
->opcode
= opcode
;
2670 instruction
->instruction_size
= 2;
2672 if ((opcode
& 0xe000) == 0x0000)
2674 /* add/substract register or immediate */
2675 if ((opcode
& 0x1800) == 0x1800)
2676 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2677 /* shift by immediate */
2679 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2682 /* Add/substract/compare/move immediate */
2683 if ((opcode
& 0xe000) == 0x2000)
2685 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2688 /* Data processing instructions */
2689 if ((opcode
& 0xf800) == 0x4000)
2691 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2694 /* Load from literal pool */
2695 if ((opcode
& 0xf800) == 0x4800)
2697 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2700 /* Load/Store register offset */
2701 if ((opcode
& 0xf000) == 0x5000)
2703 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2706 /* Load/Store immediate offset */
2707 if (((opcode
& 0xe000) == 0x6000)
2708 ||((opcode
& 0xf000) == 0x8000))
2710 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2713 /* Load/Store from/to stack */
2714 if ((opcode
& 0xf000) == 0x9000)
2716 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2720 if ((opcode
& 0xf000) == 0xa000)
2722 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2726 if ((opcode
& 0xf000) == 0xb000)
2728 switch ((opcode
>> 8) & 0x0f) {
2730 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2735 return evaluate_cb_thumb(opcode
, address
, instruction
);
2737 return evaluate_extend_thumb(opcode
, address
, instruction
);
2742 return evaluate_load_store_multiple_thumb(opcode
, address
,
2745 return evaluate_cps_thumb(opcode
, address
, instruction
);
2747 if ((opcode
& 0x00c0) == 0x0080)
2749 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2751 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2753 if (opcode
& 0x000f)
2754 return evaluate_ifthen_thumb(opcode
, address
,
2757 return evaluate_hint_thumb(opcode
, address
,
2761 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2762 snprintf(instruction
->text
, 128,
2763 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2768 /* Load/Store multiple */
2769 if ((opcode
& 0xf000) == 0xc000)
2771 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2774 /* Conditional branch + SWI */
2775 if ((opcode
& 0xf000) == 0xd000)
2777 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2780 if ((opcode
& 0xe000) == 0xe000)
2782 /* Undefined instructions */
2783 if ((opcode
& 0xf801) == 0xe801)
2785 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2786 snprintf(instruction
->text
, 128,
2787 "0x%8.8" PRIx32
" 0x%8.8x\t"
2788 "UNDEFINED INSTRUCTION",
2793 { /* Branch to offset */
2794 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2798 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2802 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2803 struct arm_instruction
*instruction
, char *cp
)
2806 unsigned b21
= 1 << 21;
2807 unsigned b22
= 1 << 22;
2809 /* instead of combining two smaller 16-bit branch instructions,
2810 * Thumb2 uses only one larger 32-bit instruction.
2812 offset
= opcode
& 0x7ff;
2813 offset
|= (opcode
& 0x03ff0000) >> 5;
2814 if (opcode
& (1 << 26)) {
2815 offset
|= 0xff << 23;
2816 if ((opcode
& (1 << 11)) == 0)
2818 if ((opcode
& (1 << 13)) == 0)
2821 if (opcode
& (1 << 11))
2823 if (opcode
& (1 << 13))
2831 address
+= offset
<< 1;
2833 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2834 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2835 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2836 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2837 (opcode
& (1 << 14)) ? "BL" : "B.W",
2843 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2844 struct arm_instruction
*instruction
, char *cp
)
2847 unsigned b17
= 1 << 17;
2848 unsigned b18
= 1 << 18;
2849 unsigned cond
= (opcode
>> 22) & 0x0f;
2851 offset
= opcode
& 0x7ff;
2852 offset
|= (opcode
& 0x003f0000) >> 5;
2853 if (opcode
& (1 << 26)) {
2854 offset
|= 0xffff << 19;
2855 if ((opcode
& (1 << 11)) == 0)
2857 if ((opcode
& (1 << 13)) == 0)
2860 if (opcode
& (1 << 11))
2862 if (opcode
& (1 << 13))
2869 address
+= offset
<< 1;
2871 instruction
->type
= ARM_B
;
2872 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2873 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2874 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2875 arm_condition_strings
[cond
],
2881 static const char *special_name(int number
)
2883 char *special
= "(RESERVED)";
2914 special
= "primask";
2917 special
= "basepri";
2920 special
= "basepri_max";
2923 special
= "faultmask";
2926 special
= "control";
2932 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2933 struct arm_instruction
*instruction
, char *cp
)
2935 const char *mnemonic
;
2937 if (opcode
& 0x0700) {
2938 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2939 strcpy(cp
, "UNDEFINED");
2943 if (opcode
& 0x00f0) {
2944 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2948 switch (opcode
& 0x0f) {
2953 mnemonic
= "YIELD.W";
2965 mnemonic
= "HINT.W (UNRECOGNIZED)";
2968 strcpy(cp
, mnemonic
);
2972 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2973 struct arm_instruction
*instruction
, char *cp
)
2975 const char *mnemonic
;
2977 switch ((opcode
>> 4) & 0x0f) {
2979 mnemonic
= "LEAVEX";
2982 mnemonic
= "ENTERX";
2997 return ERROR_INVALID_ARGUMENTS
;
2999 strcpy(cp
, mnemonic
);
3003 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3004 struct arm_instruction
*instruction
, char *cp
)
3006 /* permanently undefined */
3007 if ((opcode
& 0x07f07000) == 0x07f02000) {
3008 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3009 strcpy(cp
, "UNDEFINED");
3013 switch ((opcode
>> 12) & 0x5) {
3016 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3020 if (((opcode
>> 23) & 0x07) != 0x07)
3021 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3022 if (opcode
& (1 << 26))
3027 switch ((opcode
>> 20) & 0x7f) {
3030 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3031 (int) (opcode
>> 16) & 0x0f);
3034 return t2ev_hint(opcode
, address
, instruction
, cp
);
3036 return t2ev_misc(opcode
, address
, instruction
, cp
);
3038 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3042 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3043 special_name(opcode
& 0xff));
3048 return ERROR_INVALID_ARGUMENTS
;
3051 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3052 struct arm_instruction
*instruction
, char *cp
)
3054 char *mnemonic
= NULL
;
3055 int rn
= (opcode
>> 16) & 0xf;
3056 int rd
= (opcode
>> 8) & 0xf;
3057 unsigned immed
= opcode
& 0xff;
3063 /* ARMv7-M: A5.3.2 Modified immediate constants */
3064 func
= (opcode
>> 11) & 0x0e;
3067 if (opcode
& (1 << 26))
3070 /* "Modified" immediates */
3071 switch (func
>> 1) {
3078 immed
+= immed
<< 16;
3081 immed
+= immed
<< 8;
3082 immed
+= immed
<< 16;
3086 immed
= ror(immed
, func
);
3089 if (opcode
& (1 << 20))
3092 switch ((opcode
>> 21) & 0xf) {
3095 instruction
->type
= ARM_TST
;
3101 instruction
->type
= ARM_AND
;
3106 instruction
->type
= ARM_BIC
;
3111 instruction
->type
= ARM_MOV
;
3116 instruction
->type
= ARM_ORR
;
3122 instruction
->type
= ARM_MVN
;
3126 // instruction->type = ARM_ORN;
3132 instruction
->type
= ARM_TEQ
;
3138 instruction
->type
= ARM_EOR
;
3144 instruction
->type
= ARM_CMN
;
3150 instruction
->type
= ARM_ADD
;
3156 instruction
->type
= ARM_ADC
;
3161 instruction
->type
= ARM_SBC
;
3166 instruction
->type
= ARM_CMP
;
3172 instruction
->type
= ARM_SUB
;
3178 instruction
->type
= ARM_RSB
;
3183 return ERROR_INVALID_ARGUMENTS
;
3187 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3188 mnemonic
, suffix2
,rd
, immed
, immed
);
3190 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3191 mnemonic
, suffix
, suffix2
,
3192 rd
, rn
, immed
, immed
);
3197 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3198 struct arm_instruction
*instruction
, char *cp
)
3200 char *mnemonic
= NULL
;
3201 int rn
= (opcode
>> 16) & 0xf;
3202 int rd
= (opcode
>> 8) & 0xf;
3205 bool is_signed
= false;
3207 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3208 if (opcode
& (1 << 26))
3211 switch ((opcode
>> 20) & 0x1f) {
3220 immed
|= (opcode
>> 4) & 0xf000;
3221 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3229 /* move constant to top 16 bits of register */
3230 immed
|= (opcode
>> 4) & 0xf000;
3231 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3238 /* signed/unsigned saturated add */
3239 immed
= (opcode
>> 6) & 0x03;
3240 immed
|= (opcode
>> 10) & 0x1c;
3241 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3242 is_signed
? "S" : "U",
3243 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3244 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3245 immed
? immed
: 32);
3251 /* signed/unsigned bitfield extract */
3252 immed
= (opcode
>> 6) & 0x03;
3253 immed
|= (opcode
>> 10) & 0x1c;
3254 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3255 is_signed
? "S" : "U",
3257 (int) (opcode
& 0x1f) + 1);
3260 immed
= (opcode
>> 6) & 0x03;
3261 immed
|= (opcode
>> 10) & 0x1c;
3262 if (rn
== 0xf) /* bitfield clear */
3263 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3265 (int) (opcode
& 0x1f) + 1 - immed
);
3266 else /* bitfield insert */
3267 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3269 (int) (opcode
& 0x1f) + 1 - immed
);
3272 return ERROR_INVALID_ARGUMENTS
;
3275 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3276 rd
, rn
, immed
, immed
);
3280 address
= thumb_alignpc4(address
);
3285 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3286 * not hiding the pc-relative stuff will sometimes be useful.
3288 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3292 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3293 struct arm_instruction
*instruction
, char *cp
)
3295 unsigned op
= (opcode
>> 20) & 0xf;
3301 unsigned rn
= (opcode
>> 16) & 0x0f;
3302 unsigned rt
= (opcode
>> 12) & 0x0f;
3305 return ERROR_INVALID_ARGUMENTS
;
3307 if (opcode
& 0x0800)
3342 return ERROR_INVALID_ARGUMENTS
;
3345 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3346 size
, rt
, rn
, (int) opcode
& 0x0f,
3347 (int) (opcode
>> 4) & 0x03);
3351 immed
= opcode
& 0x0fff;
3352 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3353 size
, rt
, rn
, immed
, immed
);
3357 immed
= opcode
& 0x00ff;
3359 switch (opcode
& 0x700) {
3365 return ERROR_INVALID_ARGUMENTS
;
3368 /* two indexed modes will write back rn */
3369 if (opcode
& 0x100) {
3370 if (opcode
& 0x400) /* pre-indexed */
3372 else { /* post-indexed */
3378 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3379 size
, suffix
, rt
, rn
, p1
,
3380 (opcode
& 0x200) ? "" : "-",
3385 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3386 struct arm_instruction
*instruction
, char *cp
)
3388 int ra
= (opcode
>> 12) & 0xf;
3390 switch (opcode
& 0x007000f0) {
3393 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3394 (int) (opcode
>> 8) & 0xf,
3395 (int) (opcode
>> 16) & 0xf,
3396 (int) (opcode
>> 0) & 0xf);
3398 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3399 (int) (opcode
>> 8) & 0xf,
3400 (int) (opcode
>> 16) & 0xf,
3401 (int) (opcode
>> 0) & 0xf, ra
);
3404 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3405 (int) (opcode
>> 8) & 0xf,
3406 (int) (opcode
>> 16) & 0xf,
3407 (int) (opcode
>> 0) & 0xf, ra
);
3410 return ERROR_INVALID_ARGUMENTS
;
3415 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3416 struct arm_instruction
*instruction
, char *cp
)
3418 int op
= (opcode
>> 4) & 0xf;
3419 char *infix
= "MUL";
3421 op
+= (opcode
>> 16) & 0x70;
3429 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3430 (op
& 0x20) ? 'U' : 'S',
3432 (int) (opcode
>> 12) & 0xf,
3433 (int) (opcode
>> 8) & 0xf,
3434 (int) (opcode
>> 16) & 0xf,
3435 (int) (opcode
>> 0) & 0xf);
3439 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3440 (op
& 0x20) ? 'U' : 'S',
3441 (int) (opcode
>> 8) & 0xf,
3442 (int) (opcode
>> 16) & 0xf,
3443 (int) (opcode
>> 0) & 0xf);
3446 return ERROR_INVALID_ARGUMENTS
;
3452 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3453 struct arm_instruction
*instruction
, char *cp
)
3455 int rn
= (opcode
>> 16) & 0xf;
3456 int op
= (opcode
>> 22) & 0x6;
3457 int t
= (opcode
>> 21) & 1;
3458 unsigned registers
= opcode
& 0xffff;
3461 if (opcode
& (1 << 20))
3469 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3477 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3478 (opcode
>> 16) & 0xf,
3482 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3486 sprintf(cp
, "POP.W\t");
3488 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3492 sprintf(cp
, "PUSH.W\t");
3494 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3497 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3500 return ERROR_INVALID_ARGUMENTS
;
3505 for (t
= 0; registers
; t
++, registers
>>= 1) {
3506 if ((registers
& 1) == 0)
3509 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3518 /* load/store dual or exclusive, table branch */
3519 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3520 struct arm_instruction
*instruction
, char *cp
)
3522 unsigned op1op2
= (opcode
>> 20) & 0x3;
3523 unsigned op3
= (opcode
>> 4) & 0xf;
3525 unsigned rn
= (opcode
>> 16) & 0xf;
3526 unsigned rt
= (opcode
>> 12) & 0xf;
3527 unsigned rd
= (opcode
>> 8) & 0xf;
3528 unsigned imm
= opcode
& 0xff;
3532 op1op2
|= (opcode
>> 21) & 0xc;
3562 mnemonic
= "STREXB";
3565 mnemonic
= "STREXH";
3568 return ERROR_INVALID_ARGUMENTS
;
3576 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3579 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3582 mnemonic
= "LDREXB";
3585 mnemonic
= "LDREXH";
3588 return ERROR_INVALID_ARGUMENTS
;
3593 return ERROR_INVALID_ARGUMENTS
;
3598 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3599 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3601 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3602 mnemonic
, rd
, rt
, rn
);
3608 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3609 mnemonic
, rt
, rn
, imm
, imm
);
3611 sprintf(cp
, "%s\tr%u, [r%u]",
3616 /* two indexed modes will write back rn */
3617 if (opcode
& (1 << 21)) {
3618 if (opcode
& (1 << 24)) /* pre-indexed */
3620 else { /* post-indexed */
3627 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3628 mnemonic
, rt
, rd
, rn
, p1
,
3629 (opcode
& (1 << 23)) ? "" : "-",
3634 address
= thumb_alignpc4(address
);
3636 if (opcode
& (1 << 23))
3640 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3641 mnemonic
, rt
, rd
, address
);
3645 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3646 struct arm_instruction
*instruction
, char *cp
)
3648 int op
= (opcode
>> 21) & 0xf;
3649 int rd
= (opcode
>> 8) & 0xf;
3650 int rn
= (opcode
>> 16) & 0xf;
3651 int type
= (opcode
>> 4) & 0x3;
3652 int immed
= (opcode
>> 6) & 0x3;
3656 immed
|= (opcode
>> 10) & 0x1c;
3657 if (opcode
& (1 << 20))
3663 if (!(opcode
& (1 << 20)))
3664 return ERROR_INVALID_ARGUMENTS
;
3665 instruction
->type
= ARM_TST
;
3670 instruction
->type
= ARM_AND
;
3674 instruction
->type
= ARM_BIC
;
3679 instruction
->type
= ARM_MOV
;
3683 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3685 (int) (opcode
& 0xf));
3698 sprintf(cp
, "RRX%s\tr%d, r%d",
3700 (int) (opcode
& 0xf));
3708 instruction
->type
= ARM_ORR
;
3714 instruction
->type
= ARM_MVN
;
3719 // instruction->type = ARM_ORN;
3725 if (!(opcode
& (1 << 20)))
3726 return ERROR_INVALID_ARGUMENTS
;
3727 instruction
->type
= ARM_TEQ
;
3732 instruction
->type
= ARM_EOR
;
3737 if (!(opcode
& (1 << 20)))
3738 return ERROR_INVALID_ARGUMENTS
;
3739 instruction
->type
= ARM_CMN
;
3744 instruction
->type
= ARM_ADD
;
3748 instruction
->type
= ARM_ADC
;
3752 instruction
->type
= ARM_SBC
;
3757 if (!(opcode
& (1 << 21)))
3758 return ERROR_INVALID_ARGUMENTS
;
3759 instruction
->type
= ARM_CMP
;
3764 instruction
->type
= ARM_SUB
;
3768 instruction
->type
= ARM_RSB
;
3772 return ERROR_INVALID_ARGUMENTS
;
3775 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3776 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3799 strcpy(cp
, ", RRX");
3805 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3809 sprintf(cp
, "%s%s.W\tr%d, r%d",
3810 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3814 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3815 mnemonic
, suffix
, rd
,
3816 (int) (opcode
& 0xf), immed
? immed
: 32);
3820 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3821 struct arm_instruction
*instruction
, char *cp
)
3826 if (((opcode
>> 4) & 0xf) == 0) {
3827 switch ((opcode
>> 21) & 0x7) {
3841 return ERROR_INVALID_ARGUMENTS
;
3844 instruction
->type
= ARM_MOV
;
3845 if (opcode
& (1 << 20))
3847 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3849 (int) (opcode
>> 8) & 0xf,
3850 (int) (opcode
>> 16) & 0xf,
3851 (int) (opcode
>> 0) & 0xf);
3853 } else if (opcode
& (1 << 7)) {
3854 switch ((opcode
>> 20) & 0xf) {
3859 switch ((opcode
>> 4) & 0x3) {
3861 suffix
= ", ROR #8";
3864 suffix
= ", ROR #16";
3867 suffix
= ", ROR #24";
3870 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3871 (opcode
& (1 << 24)) ? 'U' : 'S',
3872 (opcode
& (1 << 26)) ? 'B' : 'H',
3873 (int) (opcode
>> 8) & 0xf,
3874 (int) (opcode
>> 0) & 0xf,
3881 if (opcode
& (1 << 6))
3882 return ERROR_INVALID_ARGUMENTS
;
3883 if (((opcode
>> 12) & 0xf) != 0xf)
3884 return ERROR_INVALID_ARGUMENTS
;
3885 if (!(opcode
& (1 << 20)))
3886 return ERROR_INVALID_ARGUMENTS
;
3888 switch (((opcode
>> 19) & 0x04)
3889 | ((opcode
>> 4) & 0x3)) {
3894 mnemonic
= "REV16.W";
3900 mnemonic
= "REVSH.W";
3906 return ERROR_INVALID_ARGUMENTS
;
3908 sprintf(cp
, "%s\tr%d, r%d",
3910 (int) (opcode
>> 8) & 0xf,
3911 (int) (opcode
>> 0) & 0xf);
3914 return ERROR_INVALID_ARGUMENTS
;
3921 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3922 struct arm_instruction
*instruction
, char *cp
)
3924 int rn
= (opcode
>> 16) & 0xf;
3927 instruction
->type
= ARM_LDR
;
3930 immed
= opcode
& 0x0fff;
3931 if ((opcode
& (1 << 23)) == 0)
3933 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3934 (int) (opcode
>> 12) & 0xf,
3935 thumb_alignpc4(address
) + immed
);
3939 if (opcode
& (1 << 23)) {
3940 immed
= opcode
& 0x0fff;
3941 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3942 (int) (opcode
>> 12) & 0xf,
3947 if (!(opcode
& (0x3f << 6))) {
3948 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3949 (int) (opcode
>> 12) & 0xf,
3951 (int) (opcode
>> 0) & 0xf,
3952 (int) (opcode
>> 4) & 0x3);
3957 if (((opcode
>> 8) & 0xf) == 0xe) {
3958 immed
= opcode
& 0x00ff;
3960 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3961 (int) (opcode
>> 12) & 0xf,
3966 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3967 char *p1
= "]", *p2
= "";
3969 if (!(opcode
& 0x0500))
3970 return ERROR_INVALID_ARGUMENTS
;
3972 immed
= opcode
& 0x00ff;
3974 /* two indexed modes will write back rn */
3975 if (opcode
& 0x100) {
3976 if (opcode
& 0x400) /* pre-indexed */
3978 else { /* post-indexed */
3984 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3985 (int) (opcode
>> 12) & 0xf,
3987 (opcode
& 0x200) ? "" : "-",
3992 return ERROR_INVALID_ARGUMENTS
;
3995 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3996 struct arm_instruction
*instruction
, char *cp
)
3998 int rn
= (opcode
>> 16) & 0xf;
3999 int rt
= (opcode
>> 12) & 0xf;
4000 int op2
= (opcode
>> 6) & 0x3f;
4002 char *p1
= "", *p2
= "]";
4005 switch ((opcode
>> 23) & 0x3) {
4007 if ((rn
& rt
) == 0xf) {
4009 immed
= opcode
& 0xfff;
4010 address
= thumb_alignpc4(address
);
4011 if (opcode
& (1 << 23))
4015 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4019 if (rn
== 0x0f && rt
!= 0x0f) {
4021 immed
= opcode
& 0xfff;
4022 address
= thumb_alignpc4(address
);
4023 if (opcode
& (1 << 23))
4027 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4033 if ((op2
& 0x3c) == 0x38) {
4034 immed
= opcode
& 0xff;
4035 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4036 rt
, rn
, immed
, immed
);
4039 if ((op2
& 0x3c) == 0x30) {
4041 immed
= opcode
& 0xff;
4044 p1
= (opcode
& (1 << 21)) ? "W" : "";
4045 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4046 p1
, rn
, immed
, immed
);
4051 immed
= opcode
& 0xff;
4052 if (!(opcode
& 0x200))
4055 /* two indexed modes will write back rn */
4056 if (opcode
& 0x100) {
4057 if (opcode
& 0x400) /* pre-indexed */
4059 else { /* post-indexed */
4065 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4066 mnemonic
, rt
, rn
, p1
,
4070 if ((op2
& 0x24) == 0x24) {
4072 goto ldrxb_immediate_t3
;
4075 int rm
= opcode
& 0xf;
4078 sprintf(cp
, "PLD\t");
4080 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4081 immed
= (opcode
>> 4) & 0x3;
4083 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4088 if ((rn
& rt
) == 0xf)
4091 immed
= opcode
& 0xfff;
4092 goto preload_immediate
;
4096 mnemonic
= "LDRB.W";
4097 immed
= opcode
& 0xfff;
4098 goto ldrxb_immediate_t2
;
4100 if ((rn
& rt
) == 0xf) {
4101 immed
= opcode
& 0xfff;
4102 address
= thumb_alignpc4(address
);
4103 if (opcode
& (1 << 23))
4107 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4110 if (rn
== 0xf && rt
!= 0xf) {
4112 immed
= opcode
& 0xfff;
4113 address
= thumb_alignpc4(address
);
4114 if (opcode
& (1 << 23))
4118 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4123 if ((op2
& 0x3c) == 0x38) {
4124 immed
= opcode
& 0xff;
4125 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4126 rt
, rn
, immed
, immed
);
4129 if ((op2
& 0x3c) == 0x30) {
4131 immed
= opcode
& 0xff;
4132 immed
= -immed
; // pli
4133 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4138 goto ldrxb_immediate_t3
;
4140 if ((op2
& 0x24) == 0x24) {
4142 goto ldrxb_immediate_t3
;
4145 int rm
= opcode
& 0xf;
4148 sprintf(cp
, "PLI\t");
4150 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4151 immed
= (opcode
>> 4) & 0x3;
4153 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4159 immed
= opcode
& 0xfff;
4160 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4166 immed
= opcode
& 0xfff;
4168 goto ldrxb_immediate_t2
;
4171 return ERROR_INVALID_ARGUMENTS
;
4174 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4175 struct arm_instruction
*instruction
, char *cp
)
4177 int rn
= (opcode
>> 16) & 0xf;
4178 int rt
= (opcode
>> 12) & 0xf;
4179 int op2
= (opcode
>> 6) & 0x3f;
4184 sprintf(cp
, "HINT (UNALLOCATED)");
4188 if (opcode
& (1 << 24))
4191 if ((opcode
& (1 << 23)) == 0) {
4194 immed
= opcode
& 0xfff;
4195 address
= thumb_alignpc4(address
);
4196 if (opcode
& (1 << 23))
4200 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4205 int rm
= opcode
& 0xf;
4207 immed
= (opcode
>> 4) & 0x3;
4208 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4209 sign
, rt
, rn
, rm
, immed
);
4212 if ((op2
& 0x3c) == 0x38) {
4213 immed
= opcode
& 0xff;
4214 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4215 sign
, rt
, rn
, immed
, immed
);
4218 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4219 char *p1
= "", *p2
= "]";
4221 immed
= opcode
& 0xff;
4222 if (!(opcode
& 0x200))
4225 /* two indexed modes will write back rn */
4226 if (opcode
& 0x100) {
4227 if (opcode
& 0x400) /* pre-indexed */
4229 else { /* post-indexed */
4234 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4235 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4242 immed
= opcode
& 0xfff;
4243 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4244 sign
, *sign
? "" : ".W",
4245 rt
, rn
, immed
, immed
);
4249 return ERROR_INVALID_ARGUMENTS
;
4253 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4254 * always set. That means eventual arm_simulate_step() support for Thumb2
4255 * will need work in this area.
4257 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4264 /* clear low bit ... it's set on function pointers */
4267 /* clear fields, to avoid confusion */
4268 memset(instruction
, 0, sizeof(struct arm_instruction
));
4270 /* read first halfword, see if this is the only one */
4271 retval
= target_read_u16(target
, address
, &op
);
4272 if (retval
!= ERROR_OK
)
4275 switch (op
& 0xf800) {
4279 /* 32-bit instructions */
4280 instruction
->instruction_size
= 4;
4282 retval
= target_read_u16(target
, address
+ 2, &op
);
4283 if (retval
!= ERROR_OK
)
4286 instruction
->opcode
= opcode
;
4289 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4290 return thumb_evaluate_opcode(op
, address
, instruction
);
4293 snprintf(instruction
->text
, 128,
4294 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4296 cp
= strchr(instruction
->text
, 0);
4297 retval
= ERROR_FAIL
;
4299 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4300 if ((opcode
& 0x1a008000) == 0x10000000)
4301 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4303 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4304 else if ((opcode
& 0x1a008000) == 0x12000000)
4305 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4307 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4308 else if ((opcode
& 0x18008000) == 0x10008000)
4309 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4311 /* ARMv7-M: A5.3.5 Load/store multiple */
4312 else if ((opcode
& 0x1e400000) == 0x08000000)
4313 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4315 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4316 else if ((opcode
& 0x1e400000) == 0x08400000)
4317 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4319 /* ARMv7-M: A5.3.7 Load word */
4320 else if ((opcode
& 0x1f700000) == 0x18500000)
4321 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4323 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4324 else if ((opcode
& 0x1e700000) == 0x18300000)
4325 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4327 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4328 else if ((opcode
& 0x1e700000) == 0x18100000)
4329 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4331 /* ARMv7-M: A5.3.10 Store single data item */
4332 else if ((opcode
& 0x1f100000) == 0x18000000)
4333 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4335 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4336 else if ((opcode
& 0x1e000000) == 0x0a000000)
4337 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4339 /* ARMv7-M: A5.3.12 Data processing (register)
4340 * and A5.3.13 Miscellaneous operations
4342 else if ((opcode
& 0x1f000000) == 0x1a000000)
4343 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4345 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4346 else if ((opcode
& 0x1f800000) == 0x1b000000)
4347 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4349 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4350 else if ((opcode
& 0x1f800000) == 0x1b800000)
4351 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4353 if (retval
== ERROR_OK
)
4357 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4358 * instructions; not yet handled here.
4361 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4362 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4363 strcpy(cp
, "UNDEFINED OPCODE");
4367 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4370 strcpy(cp
, "(32-bit Thumb2 ...)");
4374 int arm_access_size(struct arm_instruction
*instruction
)
4376 if ((instruction
->type
== ARM_LDRB
)
4377 || (instruction
->type
== ARM_LDRBT
)
4378 || (instruction
->type
== ARM_LDRSB
)
4379 || (instruction
->type
== ARM_STRB
)
4380 || (instruction
->type
== ARM_STRBT
))
4384 else if ((instruction
->type
== ARM_LDRH
)
4385 || (instruction
->type
== ARM_LDRSH
)
4386 || (instruction
->type
== ARM_STRH
))
4390 else if ((instruction
->type
== ARM_LDR
)
4391 || (instruction
->type
== ARM_LDRT
)
4392 || (instruction
->type
== ARM_STR
)
4393 || (instruction
->type
== ARM_STRT
))
4397 else if ((instruction
->type
== ARM_LDRD
)
4398 || (instruction
->type
== ARM_STRD
))
4404 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)