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",
161 mode
, wback
, opcode
& 0x1f);
164 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
168 mode
, (opcode
>> 16) & 0xf, wback
);
171 return evaluate_unknown(opcode
, address
, instruction
);
176 static int evaluate_swi(uint32_t opcode
,
177 uint32_t address
, struct arm_instruction
*instruction
)
179 instruction
->type
= ARM_SWI
;
181 snprintf(instruction
->text
, 128,
182 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
183 address
, opcode
, (opcode
& 0xffffff));
188 static int evaluate_blx_imm(uint32_t opcode
,
189 uint32_t address
, struct arm_instruction
*instruction
)
193 uint32_t target_address
;
195 instruction
->type
= ARM_BLX
;
196 immediate
= opcode
& 0x00ffffff;
198 /* sign extend 24-bit immediate */
199 if (immediate
& 0x00800000)
200 offset
= 0xff000000 | immediate
;
204 /* shift two bits left */
207 /* odd/event halfword */
208 if (opcode
& 0x01000000)
211 target_address
= address
+ 8 + offset
;
213 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
215 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
216 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
221 static int evaluate_b_bl(uint32_t opcode
,
222 uint32_t address
, struct arm_instruction
*instruction
)
227 uint32_t target_address
;
229 immediate
= opcode
& 0x00ffffff;
230 L
= (opcode
& 0x01000000) >> 24;
232 /* sign extend 24-bit immediate */
233 if (immediate
& 0x00800000)
234 offset
= 0xff000000 | immediate
;
238 /* shift two bits left */
241 target_address
= address
+ 8 + offset
;
244 instruction
->type
= ARM_BL
;
246 instruction
->type
= ARM_B
;
248 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
249 (L
) ? "L" : "", COND(opcode
), target_address
);
251 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
252 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
257 /* Coprocessor load/store and double register transfers */
258 /* both normal and extended instruction space (condition field b1111) */
259 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
260 uint32_t address
, struct arm_instruction
*instruction
)
262 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
265 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
267 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
270 cp_opcode
= (opcode
& 0xf0) >> 4;
271 Rd
= (opcode
& 0xf000) >> 12;
272 Rn
= (opcode
& 0xf0000) >> 16;
273 CRm
= (opcode
& 0xf);
276 if ((opcode
& 0x0ff00000) == 0x0c400000)
278 instruction
->type
= ARM_MCRR
;
283 if ((opcode
& 0x0ff00000) == 0x0c500000)
285 instruction
->type
= ARM_MRRC
;
289 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
290 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
292 else /* LDC or STC */
294 uint8_t CRd
, Rn
, offset
;
297 char addressing_mode
[32];
299 CRd
= (opcode
& 0xf000) >> 12;
300 Rn
= (opcode
& 0xf0000) >> 16;
301 offset
= (opcode
& 0xff);
304 if (opcode
& 0x00100000)
306 instruction
->type
= ARM_LDC
;
311 instruction
->type
= ARM_STC
;
315 U
= (opcode
& 0x00800000) >> 23;
316 N
= (opcode
& 0x00400000) >> 22;
318 /* addressing modes */
319 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
320 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
321 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
322 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
323 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
324 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
325 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
326 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
328 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
329 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
331 cp_num
, CRd
, addressing_mode
);
337 /* Coprocessor data processing instructions */
338 /* Coprocessor register transfer instructions */
339 /* both normal and extended instruction space (condition field b1111) */
340 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
341 uint32_t address
, struct arm_instruction
*instruction
)
345 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
347 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
348 cp_num
= (opcode
& 0xf00) >> 8;
349 CRd_Rd
= (opcode
& 0xf000) >> 12;
350 CRn
= (opcode
& 0xf0000) >> 16;
351 CRm
= (opcode
& 0xf);
352 opcode_2
= (opcode
& 0xe0) >> 5;
355 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
357 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
359 instruction
->type
= ARM_MRC
;
362 else /* bit 20 not set -> MCR */
364 instruction
->type
= ARM_MCR
;
368 opcode_1
= (opcode
& 0x00e00000) >> 21;
370 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",
371 address
, opcode
, mnemonic
, cond
,
372 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
374 else /* bit 4 not set -> CDP */
376 instruction
->type
= ARM_CDP
;
379 opcode_1
= (opcode
& 0x00f00000) >> 20;
381 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",
382 address
, opcode
, mnemonic
, cond
,
383 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
389 /* Load/store instructions */
390 static int evaluate_load_store(uint32_t opcode
,
391 uint32_t address
, struct arm_instruction
*instruction
)
393 uint8_t I
, P
, U
, B
, W
, L
;
395 char *operation
; /* "LDR" or "STR" */
396 char *suffix
; /* "", "B", "T", "BT" */
400 I
= (opcode
& 0x02000000) >> 25;
401 P
= (opcode
& 0x01000000) >> 24;
402 U
= (opcode
& 0x00800000) >> 23;
403 B
= (opcode
& 0x00400000) >> 22;
404 W
= (opcode
& 0x00200000) >> 21;
405 L
= (opcode
& 0x00100000) >> 20;
407 /* target register */
408 Rd
= (opcode
& 0xf000) >> 12;
411 Rn
= (opcode
& 0xf0000) >> 16;
413 instruction
->info
.load_store
.Rd
= Rd
;
414 instruction
->info
.load_store
.Rn
= Rn
;
415 instruction
->info
.load_store
.U
= U
;
417 /* determine operation */
423 /* determine instruction type and suffix */
426 if ((P
== 0) && (W
== 1))
429 instruction
->type
= ARM_LDRBT
;
431 instruction
->type
= ARM_STRBT
;
437 instruction
->type
= ARM_LDRB
;
439 instruction
->type
= ARM_STRB
;
445 if ((P
== 0) && (W
== 1))
448 instruction
->type
= ARM_LDRT
;
450 instruction
->type
= ARM_STRT
;
456 instruction
->type
= ARM_LDR
;
458 instruction
->type
= ARM_STR
;
463 if (!I
) /* #+-<offset_12> */
465 uint32_t offset_12
= (opcode
& 0xfff);
467 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
469 snprintf(offset
, 32, "%s", "");
471 instruction
->info
.load_store
.offset_mode
= 0;
472 instruction
->info
.load_store
.offset
.offset
= offset_12
;
474 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
476 uint8_t shift_imm
, shift
;
479 shift_imm
= (opcode
& 0xf80) >> 7;
480 shift
= (opcode
& 0x60) >> 5;
483 /* LSR encodes a shift by 32 bit as 0x0 */
484 if ((shift
== 0x1) && (shift_imm
== 0x0))
487 /* ASR encodes a shift by 32 bit as 0x0 */
488 if ((shift
== 0x2) && (shift_imm
== 0x0))
491 /* ROR by 32 bit is actually a RRX */
492 if ((shift
== 0x3) && (shift_imm
== 0x0))
495 instruction
->info
.load_store
.offset_mode
= 1;
496 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
497 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
498 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
500 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
502 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
504 else /* +-<Rm>, <Shift>, #<shift_imm> */
509 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
512 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
515 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
518 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
521 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
529 if (W
== 0) /* offset */
531 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
532 address
, opcode
, operation
, COND(opcode
), suffix
,
535 instruction
->info
.load_store
.index_mode
= 0;
537 else /* pre-indexed */
539 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
540 address
, opcode
, operation
, COND(opcode
), suffix
,
543 instruction
->info
.load_store
.index_mode
= 1;
546 else /* post-indexed */
548 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
549 address
, opcode
, operation
, COND(opcode
), suffix
,
552 instruction
->info
.load_store
.index_mode
= 2;
558 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
560 unsigned rm
= (opcode
>> 0) & 0xf;
561 unsigned rd
= (opcode
>> 12) & 0xf;
562 unsigned rn
= (opcode
>> 16) & 0xf;
565 switch ((opcode
>> 24) & 0x3) {
570 sprintf(cp
, "UNDEFINED");
571 return ARM_UNDEFINED_INSTRUCTION
;
580 switch ((opcode
>> 10) & 0x3) {
596 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
597 (opcode
& (1 << 22)) ? 'U' : 'S',
602 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
603 (opcode
& (1 << 22)) ? 'U' : 'S',
610 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
616 switch ((opcode
>> 20) & 0x7) {
639 switch ((opcode
>> 5) & 0x7) {
668 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
669 (int) (opcode
>> 12) & 0xf,
670 (int) (opcode
>> 16) & 0xf,
671 (int) (opcode
>> 0) & 0xf);
675 /* these opcodes might be used someday */
676 sprintf(cp
, "UNDEFINED");
677 return ARM_UNDEFINED_INSTRUCTION
;
680 /* ARMv6 and later support "media" instructions (includes SIMD) */
681 static int evaluate_media(uint32_t opcode
, uint32_t address
,
682 struct arm_instruction
*instruction
)
684 char *cp
= instruction
->text
;
685 char *mnemonic
= NULL
;
688 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
692 /* parallel add/subtract */
693 if ((opcode
& 0x01800000) == 0x00000000) {
694 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
699 if ((opcode
& 0x01f00020) == 0x00800000) {
701 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
703 if (opcode
& (1 << 6)) {
712 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
714 (int) (opcode
>> 12) & 0xf,
715 (int) (opcode
>> 16) & 0xf,
716 (int) (opcode
>> 0) & 0xf,
722 if ((opcode
& 0x01a00020) == 0x00a00000) {
724 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
726 if (opcode
& (1 << 6)) {
734 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
735 (opcode
& (1 << 22)) ? 'U' : 'S',
737 (int) (opcode
>> 12) & 0xf,
738 (int) (opcode
>> 16) & 0x1f,
739 (int) (opcode
>> 0) & 0xf,
745 if ((opcode
& 0x018000f0) == 0x00800070) {
746 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
751 if ((opcode
& 0x01f00080) == 0x01000000) {
752 unsigned rn
= (opcode
>> 12) & 0xf;
755 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
756 (opcode
& (1 << 6)) ? 'S' : 'A',
757 (opcode
& (1 << 5)) ? "X" : "",
759 (int) (opcode
>> 16) & 0xf,
760 (int) (opcode
>> 0) & 0xf,
761 (int) (opcode
>> 8) & 0xf,
764 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
765 (opcode
& (1 << 6)) ? 'S' : 'A',
766 (opcode
& (1 << 5)) ? "X" : "",
768 (int) (opcode
>> 16) & 0xf,
769 (int) (opcode
>> 0) & 0xf,
770 (int) (opcode
>> 8) & 0xf);
773 if ((opcode
& 0x01f00000) == 0x01400000) {
774 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
775 (opcode
& (1 << 6)) ? 'S' : 'A',
776 (opcode
& (1 << 5)) ? "X" : "",
778 (int) (opcode
>> 12) & 0xf,
779 (int) (opcode
>> 16) & 0xf,
780 (int) (opcode
>> 0) & 0xf,
781 (int) (opcode
>> 8) & 0xf);
784 if ((opcode
& 0x01f00000) == 0x01500000) {
785 unsigned rn
= (opcode
>> 12) & 0xf;
787 switch (opcode
& 0xc0) {
799 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
800 (opcode
& (1 << 6)) ? 'S' : 'A',
801 (opcode
& (1 << 5)) ? "R" : "",
803 (int) (opcode
>> 16) & 0xf,
804 (int) (opcode
>> 0) & 0xf,
805 (int) (opcode
>> 8) & 0xf,
808 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
809 (opcode
& (1 << 5)) ? "R" : "",
811 (int) (opcode
>> 16) & 0xf,
812 (int) (opcode
>> 0) & 0xf,
813 (int) (opcode
>> 8) & 0xf);
818 /* simple matches against the remaining decode bits */
819 switch (opcode
& 0x01f000f0) {
822 /* parallel halfword saturate */
823 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
824 (opcode
& (1 << 22)) ? 'U' : 'S',
826 (int) (opcode
>> 12) & 0xf,
827 (int) (opcode
>> 16) & 0xf,
828 (int) (opcode
>> 0) & 0xf);
841 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
842 (int) (opcode
>> 12) & 0xf,
843 (int) (opcode
>> 16) & 0xf,
844 (int) (opcode
>> 0) & 0xf);
847 /* unsigned sum of absolute differences */
848 if (((opcode
>> 12) & 0xf) == 0xf)
849 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
850 (int) (opcode
>> 16) & 0xf,
851 (int) (opcode
>> 0) & 0xf,
852 (int) (opcode
>> 8) & 0xf);
854 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
855 (int) (opcode
>> 16) & 0xf,
856 (int) (opcode
>> 0) & 0xf,
857 (int) (opcode
>> 8) & 0xf,
858 (int) (opcode
>> 12) & 0xf);
862 unsigned rm
= (opcode
>> 0) & 0xf;
863 unsigned rd
= (opcode
>> 12) & 0xf;
865 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
870 /* these opcodes might be used someday */
871 sprintf(cp
, "UNDEFINED");
875 /* Miscellaneous load/store instructions */
876 static int evaluate_misc_load_store(uint32_t opcode
,
877 uint32_t address
, struct arm_instruction
*instruction
)
879 uint8_t P
, U
, I
, W
, L
, S
, H
;
881 char *operation
; /* "LDR" or "STR" */
882 char *suffix
; /* "H", "SB", "SH", "D" */
886 P
= (opcode
& 0x01000000) >> 24;
887 U
= (opcode
& 0x00800000) >> 23;
888 I
= (opcode
& 0x00400000) >> 22;
889 W
= (opcode
& 0x00200000) >> 21;
890 L
= (opcode
& 0x00100000) >> 20;
891 S
= (opcode
& 0x00000040) >> 6;
892 H
= (opcode
& 0x00000020) >> 5;
894 /* target register */
895 Rd
= (opcode
& 0xf000) >> 12;
898 Rn
= (opcode
& 0xf0000) >> 16;
900 instruction
->info
.load_store
.Rd
= Rd
;
901 instruction
->info
.load_store
.Rn
= Rn
;
902 instruction
->info
.load_store
.U
= U
;
904 /* determine instruction type and suffix */
912 instruction
->type
= ARM_LDRSH
;
918 instruction
->type
= ARM_LDRSB
;
922 else /* there are no signed stores, so this is used to encode double-register load/stores */
928 instruction
->type
= ARM_STRD
;
933 instruction
->type
= ARM_LDRD
;
943 instruction
->type
= ARM_LDRH
;
948 instruction
->type
= ARM_STRH
;
952 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
954 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
955 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
957 instruction
->info
.load_store
.offset_mode
= 0;
958 instruction
->info
.load_store
.offset
.offset
= offset_8
;
960 else /* Register offset/index (+-<Rm>) */
964 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
966 instruction
->info
.load_store
.offset_mode
= 1;
967 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
968 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
969 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
974 if (W
== 0) /* offset */
976 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
977 address
, opcode
, operation
, COND(opcode
), suffix
,
980 instruction
->info
.load_store
.index_mode
= 0;
982 else /* pre-indexed */
984 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
985 address
, opcode
, operation
, COND(opcode
), suffix
,
988 instruction
->info
.load_store
.index_mode
= 1;
991 else /* post-indexed */
993 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
994 address
, opcode
, operation
, COND(opcode
), suffix
,
997 instruction
->info
.load_store
.index_mode
= 2;
1003 /* Load/store multiples instructions */
1004 static int evaluate_ldm_stm(uint32_t opcode
,
1005 uint32_t address
, struct arm_instruction
*instruction
)
1007 uint8_t P
, U
, S
, W
, L
, Rn
;
1008 uint32_t register_list
;
1009 char *addressing_mode
;
1016 P
= (opcode
& 0x01000000) >> 24;
1017 U
= (opcode
& 0x00800000) >> 23;
1018 S
= (opcode
& 0x00400000) >> 22;
1019 W
= (opcode
& 0x00200000) >> 21;
1020 L
= (opcode
& 0x00100000) >> 20;
1021 register_list
= (opcode
& 0xffff);
1022 Rn
= (opcode
& 0xf0000) >> 16;
1024 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1025 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1026 instruction
->info
.load_store_multiple
.S
= S
;
1027 instruction
->info
.load_store_multiple
.W
= W
;
1031 instruction
->type
= ARM_LDM
;
1036 instruction
->type
= ARM_STM
;
1044 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1045 addressing_mode
= "IB";
1049 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1050 addressing_mode
= "DB";
1057 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1058 /* "IA" is the default in UAL syntax */
1059 addressing_mode
= "";
1063 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1064 addressing_mode
= "DA";
1068 reg_list_p
= reg_list
;
1069 for (i
= 0; i
<= 15; i
++)
1071 if ((register_list
>> i
) & 1)
1076 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1080 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1085 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
1086 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
1087 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1092 /* Multiplies, extra load/stores */
1093 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1094 uint32_t address
, struct arm_instruction
*instruction
)
1096 /* Multiply (accumulate) (long) and Swap/swap byte */
1097 if ((opcode
& 0x000000f0) == 0x00000090)
1099 /* Multiply (accumulate) */
1100 if ((opcode
& 0x0f800000) == 0x00000000)
1102 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1104 Rs
= (opcode
& 0xf00) >> 8;
1105 Rn
= (opcode
& 0xf000) >> 12;
1106 Rd
= (opcode
& 0xf0000) >> 16;
1107 S
= (opcode
& 0x00100000) >> 20;
1109 /* examine A bit (accumulate) */
1110 if (opcode
& 0x00200000)
1112 instruction
->type
= ARM_MLA
;
1113 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1114 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1118 instruction
->type
= ARM_MUL
;
1119 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1120 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1126 /* Multiply (accumulate) long */
1127 if ((opcode
& 0x0f800000) == 0x00800000)
1129 char* mnemonic
= NULL
;
1130 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1132 Rs
= (opcode
& 0xf00) >> 8;
1133 RdHi
= (opcode
& 0xf000) >> 12;
1134 RdLow
= (opcode
& 0xf0000) >> 16;
1135 S
= (opcode
& 0x00100000) >> 20;
1137 switch ((opcode
& 0x00600000) >> 21)
1140 instruction
->type
= ARM_UMULL
;
1144 instruction
->type
= ARM_UMLAL
;
1148 instruction
->type
= ARM_SMULL
;
1152 instruction
->type
= ARM_SMLAL
;
1157 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1158 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1159 RdLow
, RdHi
, Rm
, Rs
);
1164 /* Swap/swap byte */
1165 if ((opcode
& 0x0f800000) == 0x01000000)
1169 Rd
= (opcode
& 0xf000) >> 12;
1170 Rn
= (opcode
& 0xf0000) >> 16;
1172 /* examine B flag */
1173 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1175 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1176 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1182 return evaluate_misc_load_store(opcode
, address
, instruction
);
1185 static int evaluate_mrs_msr(uint32_t opcode
,
1186 uint32_t address
, struct arm_instruction
*instruction
)
1188 int R
= (opcode
& 0x00400000) >> 22;
1189 char *PSR
= (R
) ? "SPSR" : "CPSR";
1191 /* Move register to status register (MSR) */
1192 if (opcode
& 0x00200000)
1194 instruction
->type
= ARM_MSR
;
1196 /* immediate variant */
1197 if (opcode
& 0x02000000)
1199 uint8_t immediate
= (opcode
& 0xff);
1200 uint8_t rotate
= (opcode
& 0xf00);
1202 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1203 address
, opcode
, COND(opcode
), PSR
,
1204 (opcode
& 0x10000) ? "c" : "",
1205 (opcode
& 0x20000) ? "x" : "",
1206 (opcode
& 0x40000) ? "s" : "",
1207 (opcode
& 0x80000) ? "f" : "",
1208 ror(immediate
, (rotate
* 2))
1211 else /* register variant */
1213 uint8_t Rm
= opcode
& 0xf;
1214 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1215 address
, opcode
, COND(opcode
), PSR
,
1216 (opcode
& 0x10000) ? "c" : "",
1217 (opcode
& 0x20000) ? "x" : "",
1218 (opcode
& 0x40000) ? "s" : "",
1219 (opcode
& 0x80000) ? "f" : "",
1225 else /* Move status register to register (MRS) */
1229 instruction
->type
= ARM_MRS
;
1230 Rd
= (opcode
& 0x0000f000) >> 12;
1232 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1233 address
, opcode
, COND(opcode
), Rd
, PSR
);
1239 /* Miscellaneous instructions */
1240 static int evaluate_misc_instr(uint32_t opcode
,
1241 uint32_t address
, struct arm_instruction
*instruction
)
1244 if ((opcode
& 0x000000f0) == 0x00000000)
1246 evaluate_mrs_msr(opcode
, address
, instruction
);
1250 if ((opcode
& 0x006000f0) == 0x00200010)
1253 instruction
->type
= ARM_BX
;
1256 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1257 address
, opcode
, COND(opcode
), Rm
);
1259 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1260 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1263 /* BXJ - "Jazelle" support (ARMv5-J) */
1264 if ((opcode
& 0x006000f0) == 0x00200020)
1267 instruction
->type
= ARM_BX
;
1270 snprintf(instruction
->text
, 128,
1271 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%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;
1279 if ((opcode
& 0x006000f0) == 0x00600010)
1282 instruction
->type
= ARM_CLZ
;
1284 Rd
= (opcode
& 0xf000) >> 12;
1286 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1287 address
, opcode
, COND(opcode
), Rd
, Rm
);
1291 if ((opcode
& 0x006000f0) == 0x00200030)
1294 instruction
->type
= ARM_BLX
;
1297 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1298 address
, opcode
, COND(opcode
), Rm
);
1300 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1301 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1304 /* Enhanced DSP add/subtracts */
1305 if ((opcode
& 0x0000000f0) == 0x00000050)
1308 char *mnemonic
= NULL
;
1310 Rd
= (opcode
& 0xf000) >> 12;
1311 Rn
= (opcode
& 0xf0000) >> 16;
1313 switch ((opcode
& 0x00600000) >> 21)
1316 instruction
->type
= ARM_QADD
;
1320 instruction
->type
= ARM_QSUB
;
1324 instruction
->type
= ARM_QDADD
;
1328 instruction
->type
= ARM_QDSUB
;
1333 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1334 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1337 /* Software breakpoints */
1338 if ((opcode
& 0x0000000f0) == 0x00000070)
1341 instruction
->type
= ARM_BKPT
;
1342 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1344 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1345 address
, opcode
, immediate
);
1348 /* Enhanced DSP multiplies */
1349 if ((opcode
& 0x000000090) == 0x00000080)
1351 int x
= (opcode
& 0x20) >> 5;
1352 int y
= (opcode
& 0x40) >> 6;
1355 if ((opcode
& 0x00600000) == 0x00000000)
1357 uint8_t Rd
, Rm
, Rs
, Rn
;
1358 instruction
->type
= ARM_SMLAxy
;
1359 Rd
= (opcode
& 0xf0000) >> 16;
1360 Rm
= (opcode
& 0xf);
1361 Rs
= (opcode
& 0xf00) >> 8;
1362 Rn
= (opcode
& 0xf000) >> 12;
1364 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1365 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1370 if ((opcode
& 0x00600000) == 0x00400000)
1372 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1373 instruction
->type
= ARM_SMLAxy
;
1374 RdHi
= (opcode
& 0xf0000) >> 16;
1375 RdLow
= (opcode
& 0xf000) >> 12;
1376 Rm
= (opcode
& 0xf);
1377 Rs
= (opcode
& 0xf00) >> 8;
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
),
1381 RdLow
, RdHi
, Rm
, Rs
);
1385 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1387 uint8_t Rd
, Rm
, Rs
, Rn
;
1388 instruction
->type
= ARM_SMLAWy
;
1389 Rd
= (opcode
& 0xf0000) >> 16;
1390 Rm
= (opcode
& 0xf);
1391 Rs
= (opcode
& 0xf00) >> 8;
1392 Rn
= (opcode
& 0xf000) >> 12;
1394 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1395 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1400 if ((opcode
& 0x00600000) == 0x00300000)
1403 instruction
->type
= ARM_SMULxy
;
1404 Rd
= (opcode
& 0xf0000) >> 16;
1405 Rm
= (opcode
& 0xf);
1406 Rs
= (opcode
& 0xf00) >> 8;
1408 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1409 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1414 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1417 instruction
->type
= ARM_SMULWy
;
1418 Rd
= (opcode
& 0xf0000) >> 16;
1419 Rm
= (opcode
& 0xf);
1420 Rs
= (opcode
& 0xf00) >> 8;
1422 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1423 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1431 static int evaluate_data_proc(uint32_t opcode
,
1432 uint32_t address
, struct arm_instruction
*instruction
)
1434 uint8_t I
, op
, S
, Rn
, Rd
;
1435 char *mnemonic
= NULL
;
1436 char shifter_operand
[32];
1438 I
= (opcode
& 0x02000000) >> 25;
1439 op
= (opcode
& 0x01e00000) >> 21;
1440 S
= (opcode
& 0x00100000) >> 20;
1442 Rd
= (opcode
& 0xf000) >> 12;
1443 Rn
= (opcode
& 0xf0000) >> 16;
1445 instruction
->info
.data_proc
.Rd
= Rd
;
1446 instruction
->info
.data_proc
.Rn
= Rn
;
1447 instruction
->info
.data_proc
.S
= S
;
1452 instruction
->type
= ARM_AND
;
1456 instruction
->type
= ARM_EOR
;
1460 instruction
->type
= ARM_SUB
;
1464 instruction
->type
= ARM_RSB
;
1468 instruction
->type
= ARM_ADD
;
1472 instruction
->type
= ARM_ADC
;
1476 instruction
->type
= ARM_SBC
;
1480 instruction
->type
= ARM_RSC
;
1484 instruction
->type
= ARM_TST
;
1488 instruction
->type
= ARM_TEQ
;
1492 instruction
->type
= ARM_CMP
;
1496 instruction
->type
= ARM_CMN
;
1500 instruction
->type
= ARM_ORR
;
1504 instruction
->type
= ARM_MOV
;
1508 instruction
->type
= ARM_BIC
;
1512 instruction
->type
= ARM_MVN
;
1517 if (I
) /* immediate shifter operand (#<immediate>)*/
1519 uint8_t immed_8
= opcode
& 0xff;
1520 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1523 immediate
= ror(immed_8
, rotate_imm
* 2);
1525 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1527 instruction
->info
.data_proc
.variant
= 0;
1528 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1530 else /* register-based shifter operand */
1533 shift
= (opcode
& 0x60) >> 5;
1534 Rm
= (opcode
& 0xf);
1536 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1539 shift_imm
= (opcode
& 0xf80) >> 7;
1541 instruction
->info
.data_proc
.variant
= 1;
1542 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1543 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1544 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1546 /* LSR encodes a shift by 32 bit as 0x0 */
1547 if ((shift
== 0x1) && (shift_imm
== 0x0))
1550 /* ASR encodes a shift by 32 bit as 0x0 */
1551 if ((shift
== 0x2) && (shift_imm
== 0x0))
1554 /* ROR by 32 bit is actually a RRX */
1555 if ((shift
== 0x3) && (shift_imm
== 0x0))
1558 if ((shift_imm
== 0x0) && (shift
== 0x0))
1560 snprintf(shifter_operand
, 32, "r%i", Rm
);
1564 if (shift
== 0x0) /* LSL */
1566 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1568 else if (shift
== 0x1) /* LSR */
1570 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1572 else if (shift
== 0x2) /* ASR */
1574 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1576 else if (shift
== 0x3) /* ROR */
1578 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1580 else if (shift
== 0x4) /* RRX */
1582 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1586 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1588 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1590 instruction
->info
.data_proc
.variant
= 2;
1591 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1592 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1593 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1595 if (shift
== 0x0) /* LSL */
1597 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1599 else if (shift
== 0x1) /* LSR */
1601 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1603 else if (shift
== 0x2) /* ASR */
1605 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1607 else if (shift
== 0x3) /* ROR */
1609 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1614 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1616 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1617 address
, opcode
, mnemonic
, COND(opcode
),
1618 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1620 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1622 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1623 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1625 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1626 address
, opcode
, mnemonic
, COND(opcode
),
1627 (S
) ? "S" : "", Rd
, shifter_operand
);
1629 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1631 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1632 address
, opcode
, mnemonic
, COND(opcode
),
1633 Rn
, shifter_operand
);
1639 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
1641 /* clear fields, to avoid confusion */
1642 memset(instruction
, 0, sizeof(struct arm_instruction
));
1643 instruction
->opcode
= opcode
;
1644 instruction
->instruction_size
= 4;
1646 /* catch opcodes with condition field [31:28] = b1111 */
1647 if ((opcode
& 0xf0000000) == 0xf0000000)
1649 /* Undefined instruction (or ARMv5E cache preload PLD) */
1650 if ((opcode
& 0x08000000) == 0x00000000)
1651 return evaluate_pld(opcode
, address
, instruction
);
1653 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1654 if ((opcode
& 0x0e000000) == 0x08000000)
1655 return evaluate_srs(opcode
, address
, instruction
);
1657 /* Branch and branch with link and change to Thumb */
1658 if ((opcode
& 0x0e000000) == 0x0a000000)
1659 return evaluate_blx_imm(opcode
, address
, instruction
);
1661 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1662 /* Coprocessor load/store and double register transfers */
1663 if ((opcode
& 0x0e000000) == 0x0c000000)
1664 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1666 /* Coprocessor data processing */
1667 if ((opcode
& 0x0f000100) == 0x0c000000)
1668 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1670 /* Coprocessor register transfers */
1671 if ((opcode
& 0x0f000010) == 0x0c000010)
1672 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1674 /* Undefined instruction */
1675 if ((opcode
& 0x0f000000) == 0x0f000000)
1677 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1678 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1683 /* catch opcodes with [27:25] = b000 */
1684 if ((opcode
& 0x0e000000) == 0x00000000)
1686 /* Multiplies, extra load/stores */
1687 if ((opcode
& 0x00000090) == 0x00000090)
1688 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1690 /* Miscellaneous instructions */
1691 if ((opcode
& 0x0f900000) == 0x01000000)
1692 return evaluate_misc_instr(opcode
, address
, instruction
);
1694 return evaluate_data_proc(opcode
, address
, instruction
);
1697 /* catch opcodes with [27:25] = b001 */
1698 if ((opcode
& 0x0e000000) == 0x02000000)
1700 /* Undefined instruction */
1701 if ((opcode
& 0x0fb00000) == 0x03000000)
1703 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1704 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1708 /* Move immediate to status register */
1709 if ((opcode
& 0x0fb00000) == 0x03200000)
1710 return evaluate_mrs_msr(opcode
, address
, instruction
);
1712 return evaluate_data_proc(opcode
, address
, instruction
);
1716 /* catch opcodes with [27:25] = b010 */
1717 if ((opcode
& 0x0e000000) == 0x04000000)
1719 /* Load/store immediate offset */
1720 return evaluate_load_store(opcode
, address
, instruction
);
1723 /* catch opcodes with [27:25] = b011 */
1724 if ((opcode
& 0x0e000000) == 0x06000000)
1726 /* Load/store register offset */
1727 if ((opcode
& 0x00000010) == 0x00000000)
1728 return evaluate_load_store(opcode
, address
, instruction
);
1730 /* Architecturally Undefined instruction
1731 * ... don't expect these to ever be used
1733 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1735 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1736 snprintf(instruction
->text
, 128,
1737 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1742 /* "media" instructions */
1743 return evaluate_media(opcode
, address
, instruction
);
1746 /* catch opcodes with [27:25] = b100 */
1747 if ((opcode
& 0x0e000000) == 0x08000000)
1749 /* Load/store multiple */
1750 return evaluate_ldm_stm(opcode
, address
, instruction
);
1753 /* catch opcodes with [27:25] = b101 */
1754 if ((opcode
& 0x0e000000) == 0x0a000000)
1756 /* Branch and branch with link */
1757 return evaluate_b_bl(opcode
, address
, instruction
);
1760 /* catch opcodes with [27:25] = b110 */
1761 if ((opcode
& 0x0e000000) == 0x0a000000)
1763 /* Coprocessor load/store and double register transfers */
1764 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1767 /* catch opcodes with [27:25] = b111 */
1768 if ((opcode
& 0x0e000000) == 0x0e000000)
1770 /* Software interrupt */
1771 if ((opcode
& 0x0f000000) == 0x0f000000)
1772 return evaluate_swi(opcode
, address
, instruction
);
1774 /* Coprocessor data processing */
1775 if ((opcode
& 0x0f000010) == 0x0e000000)
1776 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1778 /* Coprocessor register transfers */
1779 if ((opcode
& 0x0f000010) == 0x0e000010)
1780 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1783 LOG_ERROR("should never reach this point");
1787 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1788 uint32_t address
, struct arm_instruction
*instruction
)
1790 uint32_t offset
= opcode
& 0x7ff;
1791 uint32_t opc
= (opcode
>> 11) & 0x3;
1792 uint32_t target_address
;
1793 char *mnemonic
= NULL
;
1795 /* sign extend 11-bit offset */
1796 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1797 offset
= 0xfffff800 | offset
;
1799 target_address
= address
+ 4 + (offset
<< 1);
1803 /* unconditional branch */
1805 instruction
->type
= ARM_B
;
1810 instruction
->type
= ARM_BLX
;
1812 target_address
&= 0xfffffffc;
1816 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1817 mnemonic
= "prefix";
1818 target_address
= offset
<< 12;
1822 instruction
->type
= ARM_BL
;
1827 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1828 * these are effectively 32-bit instructions even in Thumb1. For
1829 * disassembly, it's simplest to always use the Thumb2 decoder.
1831 * But some cores will evidently handle them as two instructions,
1832 * where exceptions may occur between the two. The ETMv3.2+ ID
1833 * register has a bit which exposes this behavior.
1836 snprintf(instruction
->text
, 128,
1837 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1838 address
, opcode
, mnemonic
, target_address
);
1840 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1841 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1846 static int evaluate_add_sub_thumb(uint16_t opcode
,
1847 uint32_t address
, struct arm_instruction
*instruction
)
1849 uint8_t Rd
= (opcode
>> 0) & 0x7;
1850 uint8_t Rn
= (opcode
>> 3) & 0x7;
1851 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1852 uint32_t opc
= opcode
& (1 << 9);
1853 uint32_t reg_imm
= opcode
& (1 << 10);
1858 instruction
->type
= ARM_SUB
;
1863 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1864 instruction
->type
= ARM_ADD
;
1868 instruction
->info
.data_proc
.Rd
= Rd
;
1869 instruction
->info
.data_proc
.Rn
= Rn
;
1870 instruction
->info
.data_proc
.S
= 1;
1874 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1875 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1876 snprintf(instruction
->text
, 128,
1877 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1878 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1882 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1883 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1884 snprintf(instruction
->text
, 128,
1885 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1886 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1892 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1893 uint32_t address
, struct arm_instruction
*instruction
)
1895 uint8_t Rd
= (opcode
>> 0) & 0x7;
1896 uint8_t Rm
= (opcode
>> 3) & 0x7;
1897 uint8_t imm
= (opcode
>> 6) & 0x1f;
1898 uint8_t opc
= (opcode
>> 11) & 0x3;
1899 char *mnemonic
= NULL
;
1904 instruction
->type
= ARM_MOV
;
1906 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1909 instruction
->type
= ARM_MOV
;
1911 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1914 instruction
->type
= ARM_MOV
;
1916 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1920 if ((imm
== 0) && (opc
!= 0))
1923 instruction
->info
.data_proc
.Rd
= Rd
;
1924 instruction
->info
.data_proc
.Rn
= -1;
1925 instruction
->info
.data_proc
.S
= 1;
1927 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1928 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1929 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1931 snprintf(instruction
->text
, 128,
1932 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1933 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1938 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1939 uint32_t address
, struct arm_instruction
*instruction
)
1941 uint8_t imm
= opcode
& 0xff;
1942 uint8_t Rd
= (opcode
>> 8) & 0x7;
1943 uint32_t opc
= (opcode
>> 11) & 0x3;
1944 char *mnemonic
= NULL
;
1946 instruction
->info
.data_proc
.Rd
= Rd
;
1947 instruction
->info
.data_proc
.Rn
= Rd
;
1948 instruction
->info
.data_proc
.S
= 1;
1949 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1950 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1955 instruction
->type
= ARM_MOV
;
1957 instruction
->info
.data_proc
.Rn
= -1;
1960 instruction
->type
= ARM_CMP
;
1962 instruction
->info
.data_proc
.Rd
= -1;
1965 instruction
->type
= ARM_ADD
;
1969 instruction
->type
= ARM_SUB
;
1974 snprintf(instruction
->text
, 128,
1975 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1976 address
, opcode
, mnemonic
, Rd
, imm
);
1981 static int evaluate_data_proc_thumb(uint16_t opcode
,
1982 uint32_t address
, struct arm_instruction
*instruction
)
1984 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1985 char *mnemonic
= NULL
;
1988 high_reg
= (opcode
& 0x0400) >> 10;
1989 op
= (opcode
& 0x03C0) >> 6;
1991 Rd
= (opcode
& 0x0007);
1992 Rm
= (opcode
& 0x0038) >> 3;
1993 H1
= (opcode
& 0x0080) >> 7;
1994 H2
= (opcode
& 0x0040) >> 6;
1996 instruction
->info
.data_proc
.Rd
= Rd
;
1997 instruction
->info
.data_proc
.Rn
= Rd
;
1998 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1999 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2000 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2011 instruction
->type
= ARM_ADD
;
2015 instruction
->type
= ARM_CMP
;
2019 instruction
->type
= ARM_MOV
;
2025 if ((opcode
& 0x7) == 0x0)
2027 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2030 instruction
->type
= ARM_BLX
;
2031 snprintf(instruction
->text
, 128,
2033 " 0x%4.4x \tBLX\tr%i",
2034 address
, opcode
, Rm
);
2038 instruction
->type
= ARM_BX
;
2039 snprintf(instruction
->text
, 128,
2041 " 0x%4.4x \tBX\tr%i",
2042 address
, opcode
, Rm
);
2047 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2048 snprintf(instruction
->text
, 128,
2051 "UNDEFINED INSTRUCTION",
2063 instruction
->type
= ARM_AND
;
2067 instruction
->type
= ARM_EOR
;
2071 instruction
->type
= ARM_MOV
;
2073 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2074 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2075 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2076 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2079 instruction
->type
= ARM_MOV
;
2081 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2082 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2083 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2084 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2087 instruction
->type
= ARM_MOV
;
2089 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2090 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2091 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2092 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2095 instruction
->type
= ARM_ADC
;
2099 instruction
->type
= ARM_SBC
;
2103 instruction
->type
= ARM_MOV
;
2105 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2106 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2107 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2108 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2111 instruction
->type
= ARM_TST
;
2115 instruction
->type
= ARM_RSB
;
2117 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2118 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2119 instruction
->info
.data_proc
.Rn
= Rm
;
2122 instruction
->type
= ARM_CMP
;
2126 instruction
->type
= ARM_CMN
;
2130 instruction
->type
= ARM_ORR
;
2134 instruction
->type
= ARM_MUL
;
2138 instruction
->type
= ARM_BIC
;
2142 instruction
->type
= ARM_MVN
;
2149 snprintf(instruction
->text
, 128,
2150 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2152 address
, opcode
, mnemonic
, Rd
, Rm
);
2154 snprintf(instruction
->text
, 128,
2155 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2156 address
, opcode
, mnemonic
, Rd
, Rm
);
2161 /* PC-relative data addressing is word-aligned even with Thumb */
2162 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2164 return (addr
+ 4) & ~3;
2167 static int evaluate_load_literal_thumb(uint16_t opcode
,
2168 uint32_t address
, struct arm_instruction
*instruction
)
2171 uint8_t Rd
= (opcode
>> 8) & 0x7;
2173 instruction
->type
= ARM_LDR
;
2174 immediate
= opcode
& 0x000000ff;
2177 instruction
->info
.load_store
.Rd
= Rd
;
2178 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2179 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2180 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2181 instruction
->info
.load_store
.offset
.offset
= immediate
;
2183 snprintf(instruction
->text
, 128,
2184 "0x%8.8" PRIx32
" 0x%4.4x \t"
2185 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2186 address
, opcode
, Rd
, immediate
,
2187 thumb_alignpc4(address
) + immediate
);
2192 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2193 uint32_t address
, struct arm_instruction
*instruction
)
2195 uint8_t Rd
= (opcode
>> 0) & 0x7;
2196 uint8_t Rn
= (opcode
>> 3) & 0x7;
2197 uint8_t Rm
= (opcode
>> 6) & 0x7;
2198 uint8_t opc
= (opcode
>> 9) & 0x7;
2199 char *mnemonic
= NULL
;
2204 instruction
->type
= ARM_STR
;
2208 instruction
->type
= ARM_STRH
;
2212 instruction
->type
= ARM_STRB
;
2216 instruction
->type
= ARM_LDRSB
;
2220 instruction
->type
= ARM_LDR
;
2224 instruction
->type
= ARM_LDRH
;
2228 instruction
->type
= ARM_LDRB
;
2232 instruction
->type
= ARM_LDRSH
;
2237 snprintf(instruction
->text
, 128,
2238 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2239 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2241 instruction
->info
.load_store
.Rd
= Rd
;
2242 instruction
->info
.load_store
.Rn
= Rn
;
2243 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2244 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2245 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2250 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2251 uint32_t address
, struct arm_instruction
*instruction
)
2253 uint32_t offset
= (opcode
>> 6) & 0x1f;
2254 uint8_t Rd
= (opcode
>> 0) & 0x7;
2255 uint8_t Rn
= (opcode
>> 3) & 0x7;
2256 uint32_t L
= opcode
& (1 << 11);
2257 uint32_t B
= opcode
& (1 << 12);
2264 instruction
->type
= ARM_LDR
;
2269 instruction
->type
= ARM_STR
;
2273 if ((opcode
&0xF000) == 0x8000)
2284 snprintf(instruction
->text
, 128,
2285 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2286 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2288 instruction
->info
.load_store
.Rd
= Rd
;
2289 instruction
->info
.load_store
.Rn
= Rn
;
2290 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2291 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2292 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2297 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2298 uint32_t address
, struct arm_instruction
*instruction
)
2300 uint32_t offset
= opcode
& 0xff;
2301 uint8_t Rd
= (opcode
>> 8) & 0x7;
2302 uint32_t L
= opcode
& (1 << 11);
2307 instruction
->type
= ARM_LDR
;
2312 instruction
->type
= ARM_STR
;
2316 snprintf(instruction
->text
, 128,
2317 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2318 address
, opcode
, mnemonic
, Rd
, offset
*4);
2320 instruction
->info
.load_store
.Rd
= Rd
;
2321 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2322 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2323 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2324 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2329 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2330 uint32_t address
, struct arm_instruction
*instruction
)
2332 uint32_t imm
= opcode
& 0xff;
2333 uint8_t Rd
= (opcode
>> 8) & 0x7;
2335 uint32_t SP
= opcode
& (1 << 11);
2338 instruction
->type
= ARM_ADD
;
2351 snprintf(instruction
->text
, 128,
2352 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2353 address
, opcode
, Rd
, reg_name
, imm
* 4);
2355 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2356 instruction
->info
.data_proc
.Rd
= Rd
;
2357 instruction
->info
.data_proc
.Rn
= Rn
;
2358 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2363 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2364 uint32_t address
, struct arm_instruction
*instruction
)
2366 uint32_t imm
= opcode
& 0x7f;
2367 uint8_t opc
= opcode
& (1 << 7);
2373 instruction
->type
= ARM_SUB
;
2378 instruction
->type
= ARM_ADD
;
2382 snprintf(instruction
->text
, 128,
2383 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2384 address
, opcode
, mnemonic
, imm
*4);
2386 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2387 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2388 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2389 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2394 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2395 uint32_t address
, struct arm_instruction
*instruction
)
2397 uint32_t imm
= opcode
& 0xff;
2399 instruction
->type
= ARM_BKPT
;
2401 snprintf(instruction
->text
, 128,
2402 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2403 address
, opcode
, imm
);
2408 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2409 uint32_t address
, struct arm_instruction
*instruction
)
2411 uint32_t reg_list
= opcode
& 0xff;
2412 uint32_t L
= opcode
& (1 << 11);
2413 uint32_t R
= opcode
& (1 << 8);
2414 uint8_t Rn
= (opcode
>> 8) & 7;
2415 uint8_t addr_mode
= 0 /* IA */;
2419 char ptr_name
[7] = "";
2422 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2423 * The STMIA and LDMIA opcodes are used for other instructions.
2426 if ((opcode
& 0xf000) == 0xc000)
2427 { /* generic load/store multiple */
2432 instruction
->type
= ARM_LDM
;
2434 if (opcode
& (1 << Rn
))
2439 instruction
->type
= ARM_STM
;
2442 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2449 instruction
->type
= ARM_LDM
;
2452 reg_list
|= (1 << 15) /*PC*/;
2456 instruction
->type
= ARM_STM
;
2458 addr_mode
= 3; /*DB*/
2460 reg_list
|= (1 << 14) /*LR*/;
2464 reg_names_p
= reg_names
;
2465 for (i
= 0; i
<= 15; i
++)
2467 if (reg_list
& (1 << i
))
2468 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2470 if (reg_names_p
> reg_names
)
2471 reg_names_p
[-2] = '\0';
2472 else /* invalid op : no registers */
2473 reg_names
[0] = '\0';
2475 snprintf(instruction
->text
, 128,
2476 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2477 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2479 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2480 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2481 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2486 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2487 uint32_t address
, struct arm_instruction
*instruction
)
2489 uint32_t offset
= opcode
& 0xff;
2490 uint8_t cond
= (opcode
>> 8) & 0xf;
2491 uint32_t target_address
;
2495 instruction
->type
= ARM_SWI
;
2496 snprintf(instruction
->text
, 128,
2497 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2498 address
, opcode
, offset
);
2501 else if (cond
== 0xe)
2503 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2504 snprintf(instruction
->text
, 128,
2505 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2510 /* sign extend 8-bit offset */
2511 if (offset
& 0x00000080)
2512 offset
= 0xffffff00 | offset
;
2514 target_address
= address
+ 4 + (offset
<< 1);
2516 snprintf(instruction
->text
, 128,
2517 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2519 arm_condition_strings
[cond
], target_address
);
2521 instruction
->type
= ARM_B
;
2522 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2523 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2528 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2529 struct arm_instruction
*instruction
)
2533 /* added in Thumb2 */
2534 offset
= (opcode
>> 3) & 0x1f;
2535 offset
|= (opcode
& 0x0200) >> 4;
2537 snprintf(instruction
->text
, 128,
2538 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2540 (opcode
& 0x0800) ? "N" : "",
2541 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2546 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2547 struct arm_instruction
*instruction
)
2549 /* added in ARMv6 */
2550 snprintf(instruction
->text
, 128,
2551 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2553 (opcode
& 0x0080) ? 'U' : 'S',
2554 (opcode
& 0x0040) ? 'B' : 'H',
2555 opcode
& 0x7, (opcode
>> 3) & 0x7);
2560 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2561 struct arm_instruction
*instruction
)
2563 /* added in ARMv6 */
2564 if ((opcode
& 0x0ff0) == 0x0650)
2565 snprintf(instruction
->text
, 128,
2566 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2568 (opcode
& 0x80) ? "BE" : "LE");
2569 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2570 snprintf(instruction
->text
, 128,
2571 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2573 (opcode
& 0x0010) ? 'D' : 'E',
2574 (opcode
& 0x0004) ? "A" : "",
2575 (opcode
& 0x0002) ? "I" : "",
2576 (opcode
& 0x0001) ? "F" : "");
2581 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2582 struct arm_instruction
*instruction
)
2586 /* added in ARMv6 */
2587 switch ((opcode
>> 6) & 3) {
2598 snprintf(instruction
->text
, 128,
2599 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2600 address
, opcode
, suffix
,
2601 opcode
& 0x7, (opcode
>> 3) & 0x7);
2606 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2607 struct arm_instruction
*instruction
)
2611 switch ((opcode
>> 4) & 0x0f) {
2628 hint
= "HINT (UNRECOGNIZED)";
2632 snprintf(instruction
->text
, 128,
2633 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2634 address
, opcode
, hint
);
2639 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2640 struct arm_instruction
*instruction
)
2642 unsigned cond
= (opcode
>> 4) & 0x0f;
2643 char *x
= "", *y
= "", *z
= "";
2646 z
= (opcode
& 0x02) ? "T" : "E";
2648 y
= (opcode
& 0x04) ? "T" : "E";
2650 x
= (opcode
& 0x08) ? "T" : "E";
2652 snprintf(instruction
->text
, 128,
2653 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2655 x
, y
, z
, arm_condition_strings
[cond
]);
2657 /* NOTE: strictly speaking, the next 1-4 instructions should
2658 * now be displayed with the relevant conditional suffix...
2664 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2666 /* clear fields, to avoid confusion */
2667 memset(instruction
, 0, sizeof(struct arm_instruction
));
2668 instruction
->opcode
= opcode
;
2669 instruction
->instruction_size
= 2;
2671 if ((opcode
& 0xe000) == 0x0000)
2673 /* add/substract register or immediate */
2674 if ((opcode
& 0x1800) == 0x1800)
2675 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2676 /* shift by immediate */
2678 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2681 /* Add/substract/compare/move immediate */
2682 if ((opcode
& 0xe000) == 0x2000)
2684 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2687 /* Data processing instructions */
2688 if ((opcode
& 0xf800) == 0x4000)
2690 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2693 /* Load from literal pool */
2694 if ((opcode
& 0xf800) == 0x4800)
2696 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2699 /* Load/Store register offset */
2700 if ((opcode
& 0xf000) == 0x5000)
2702 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2705 /* Load/Store immediate offset */
2706 if (((opcode
& 0xe000) == 0x6000)
2707 ||((opcode
& 0xf000) == 0x8000))
2709 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2712 /* Load/Store from/to stack */
2713 if ((opcode
& 0xf000) == 0x9000)
2715 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2719 if ((opcode
& 0xf000) == 0xa000)
2721 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2725 if ((opcode
& 0xf000) == 0xb000)
2727 switch ((opcode
>> 8) & 0x0f) {
2729 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2734 return evaluate_cb_thumb(opcode
, address
, instruction
);
2736 return evaluate_extend_thumb(opcode
, address
, instruction
);
2741 return evaluate_load_store_multiple_thumb(opcode
, address
,
2744 return evaluate_cps_thumb(opcode
, address
, instruction
);
2746 if ((opcode
& 0x00c0) == 0x0080)
2748 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2750 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2752 if (opcode
& 0x000f)
2753 return evaluate_ifthen_thumb(opcode
, address
,
2756 return evaluate_hint_thumb(opcode
, address
,
2760 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2761 snprintf(instruction
->text
, 128,
2762 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2767 /* Load/Store multiple */
2768 if ((opcode
& 0xf000) == 0xc000)
2770 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2773 /* Conditional branch + SWI */
2774 if ((opcode
& 0xf000) == 0xd000)
2776 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2779 if ((opcode
& 0xe000) == 0xe000)
2781 /* Undefined instructions */
2782 if ((opcode
& 0xf801) == 0xe801)
2784 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2785 snprintf(instruction
->text
, 128,
2786 "0x%8.8" PRIx32
" 0x%8.8x\t"
2787 "UNDEFINED INSTRUCTION",
2792 { /* Branch to offset */
2793 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2797 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2801 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2802 struct arm_instruction
*instruction
, char *cp
)
2805 unsigned b21
= 1 << 21;
2806 unsigned b22
= 1 << 22;
2808 /* instead of combining two smaller 16-bit branch instructions,
2809 * Thumb2 uses only one larger 32-bit instruction.
2811 offset
= opcode
& 0x7ff;
2812 offset
|= (opcode
& 0x03ff0000) >> 5;
2813 if (opcode
& (1 << 26)) {
2814 offset
|= 0xff << 23;
2815 if ((opcode
& (1 << 11)) == 0)
2817 if ((opcode
& (1 << 13)) == 0)
2820 if (opcode
& (1 << 11))
2822 if (opcode
& (1 << 13))
2830 address
+= offset
<< 1;
2832 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2833 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2834 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2835 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2836 (opcode
& (1 << 14)) ? "BL" : "B.W",
2842 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2843 struct arm_instruction
*instruction
, char *cp
)
2846 unsigned b17
= 1 << 17;
2847 unsigned b18
= 1 << 18;
2848 unsigned cond
= (opcode
>> 22) & 0x0f;
2850 offset
= opcode
& 0x7ff;
2851 offset
|= (opcode
& 0x003f0000) >> 5;
2852 if (opcode
& (1 << 26)) {
2853 offset
|= 0xffff << 19;
2854 if ((opcode
& (1 << 11)) == 0)
2856 if ((opcode
& (1 << 13)) == 0)
2859 if (opcode
& (1 << 11))
2861 if (opcode
& (1 << 13))
2868 address
+= offset
<< 1;
2870 instruction
->type
= ARM_B
;
2871 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2872 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2873 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2874 arm_condition_strings
[cond
],
2880 static const char *special_name(int number
)
2882 char *special
= "(RESERVED)";
2913 special
= "primask";
2916 special
= "basepri";
2919 special
= "basepri_max";
2922 special
= "faultmask";
2925 special
= "control";
2931 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2932 struct arm_instruction
*instruction
, char *cp
)
2934 const char *mnemonic
;
2936 if (opcode
& 0x0700) {
2937 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2938 strcpy(cp
, "UNDEFINED");
2942 if (opcode
& 0x00f0) {
2943 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2947 switch (opcode
& 0x0f) {
2952 mnemonic
= "YIELD.W";
2964 mnemonic
= "HINT.W (UNRECOGNIZED)";
2967 strcpy(cp
, mnemonic
);
2971 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2972 struct arm_instruction
*instruction
, char *cp
)
2974 const char *mnemonic
;
2976 switch ((opcode
>> 4) & 0x0f) {
2978 mnemonic
= "LEAVEX";
2981 mnemonic
= "ENTERX";
2996 return ERROR_INVALID_ARGUMENTS
;
2998 strcpy(cp
, mnemonic
);
3002 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3003 struct arm_instruction
*instruction
, char *cp
)
3005 /* permanently undefined */
3006 if ((opcode
& 0x07f07000) == 0x07f02000) {
3007 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3008 strcpy(cp
, "UNDEFINED");
3012 switch ((opcode
>> 12) & 0x5) {
3015 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3019 if (((opcode
>> 23) & 0x07) != 0x07)
3020 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3021 if (opcode
& (1 << 26))
3026 switch ((opcode
>> 20) & 0x7f) {
3029 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3030 (int) (opcode
>> 16) & 0x0f);
3033 return t2ev_hint(opcode
, address
, instruction
, cp
);
3035 return t2ev_misc(opcode
, address
, instruction
, cp
);
3037 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3041 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3042 special_name(opcode
& 0xff));
3047 return ERROR_INVALID_ARGUMENTS
;
3050 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3051 struct arm_instruction
*instruction
, char *cp
)
3053 char *mnemonic
= NULL
;
3054 int rn
= (opcode
>> 16) & 0xf;
3055 int rd
= (opcode
>> 8) & 0xf;
3056 unsigned immed
= opcode
& 0xff;
3062 /* ARMv7-M: A5.3.2 Modified immediate constants */
3063 func
= (opcode
>> 11) & 0x0e;
3066 if (opcode
& (1 << 26))
3069 /* "Modified" immediates */
3070 switch (func
>> 1) {
3077 immed
+= immed
<< 16;
3080 immed
+= immed
<< 8;
3081 immed
+= immed
<< 16;
3085 immed
= ror(immed
, func
);
3088 if (opcode
& (1 << 20))
3091 switch ((opcode
>> 21) & 0xf) {
3094 instruction
->type
= ARM_TST
;
3100 instruction
->type
= ARM_AND
;
3105 instruction
->type
= ARM_BIC
;
3110 instruction
->type
= ARM_MOV
;
3115 instruction
->type
= ARM_ORR
;
3121 instruction
->type
= ARM_MVN
;
3125 // instruction->type = ARM_ORN;
3131 instruction
->type
= ARM_TEQ
;
3137 instruction
->type
= ARM_EOR
;
3143 instruction
->type
= ARM_CMN
;
3149 instruction
->type
= ARM_ADD
;
3155 instruction
->type
= ARM_ADC
;
3160 instruction
->type
= ARM_SBC
;
3165 instruction
->type
= ARM_CMP
;
3171 instruction
->type
= ARM_SUB
;
3177 instruction
->type
= ARM_RSB
;
3182 return ERROR_INVALID_ARGUMENTS
;
3186 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3187 mnemonic
, suffix2
,rd
, immed
, immed
);
3189 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3190 mnemonic
, suffix
, suffix2
,
3191 rd
, rn
, immed
, immed
);
3196 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3197 struct arm_instruction
*instruction
, char *cp
)
3199 char *mnemonic
= NULL
;
3200 int rn
= (opcode
>> 16) & 0xf;
3201 int rd
= (opcode
>> 8) & 0xf;
3204 bool is_signed
= false;
3206 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3207 if (opcode
& (1 << 26))
3210 switch ((opcode
>> 20) & 0x1f) {
3219 immed
|= (opcode
>> 4) & 0xf000;
3220 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3228 /* move constant to top 16 bits of register */
3229 immed
|= (opcode
>> 4) & 0xf000;
3230 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3237 /* signed/unsigned saturated add */
3238 immed
= (opcode
>> 6) & 0x03;
3239 immed
|= (opcode
>> 10) & 0x1c;
3240 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3241 is_signed
? "S" : "U",
3242 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3243 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3244 immed
? immed
: 32);
3250 /* signed/unsigned bitfield extract */
3251 immed
= (opcode
>> 6) & 0x03;
3252 immed
|= (opcode
>> 10) & 0x1c;
3253 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3254 is_signed
? "S" : "U",
3256 (int) (opcode
& 0x1f) + 1);
3259 immed
= (opcode
>> 6) & 0x03;
3260 immed
|= (opcode
>> 10) & 0x1c;
3261 if (rn
== 0xf) /* bitfield clear */
3262 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3264 (int) (opcode
& 0x1f) + 1 - immed
);
3265 else /* bitfield insert */
3266 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3268 (int) (opcode
& 0x1f) + 1 - immed
);
3271 return ERROR_INVALID_ARGUMENTS
;
3274 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3275 rd
, rn
, immed
, immed
);
3279 address
= thumb_alignpc4(address
);
3284 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3285 * not hiding the pc-relative stuff will sometimes be useful.
3287 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3291 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3292 struct arm_instruction
*instruction
, char *cp
)
3294 unsigned op
= (opcode
>> 20) & 0xf;
3300 unsigned rn
= (opcode
>> 16) & 0x0f;
3301 unsigned rt
= (opcode
>> 12) & 0x0f;
3304 return ERROR_INVALID_ARGUMENTS
;
3306 if (opcode
& 0x0800)
3341 return ERROR_INVALID_ARGUMENTS
;
3344 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3345 size
, rt
, rn
, (int) opcode
& 0x0f,
3346 (int) (opcode
>> 4) & 0x03);
3350 immed
= opcode
& 0x0fff;
3351 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3352 size
, rt
, rn
, immed
, immed
);
3356 immed
= opcode
& 0x00ff;
3358 switch (opcode
& 0x700) {
3364 return ERROR_INVALID_ARGUMENTS
;
3367 /* two indexed modes will write back rn */
3368 if (opcode
& 0x100) {
3369 if (opcode
& 0x400) /* pre-indexed */
3371 else { /* post-indexed */
3377 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3378 size
, suffix
, rt
, rn
, p1
,
3379 (opcode
& 0x200) ? "" : "-",
3384 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3385 struct arm_instruction
*instruction
, char *cp
)
3387 int ra
= (opcode
>> 12) & 0xf;
3389 switch (opcode
& 0x007000f0) {
3392 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3393 (int) (opcode
>> 8) & 0xf,
3394 (int) (opcode
>> 16) & 0xf,
3395 (int) (opcode
>> 0) & 0xf);
3397 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3398 (int) (opcode
>> 8) & 0xf,
3399 (int) (opcode
>> 16) & 0xf,
3400 (int) (opcode
>> 0) & 0xf, ra
);
3403 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3404 (int) (opcode
>> 8) & 0xf,
3405 (int) (opcode
>> 16) & 0xf,
3406 (int) (opcode
>> 0) & 0xf, ra
);
3409 return ERROR_INVALID_ARGUMENTS
;
3414 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3415 struct arm_instruction
*instruction
, char *cp
)
3417 int op
= (opcode
>> 4) & 0xf;
3418 char *infix
= "MUL";
3420 op
+= (opcode
>> 16) & 0x70;
3428 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3429 (op
& 0x20) ? 'U' : 'S',
3431 (int) (opcode
>> 12) & 0xf,
3432 (int) (opcode
>> 8) & 0xf,
3433 (int) (opcode
>> 16) & 0xf,
3434 (int) (opcode
>> 0) & 0xf);
3438 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3439 (op
& 0x20) ? 'U' : 'S',
3440 (int) (opcode
>> 8) & 0xf,
3441 (int) (opcode
>> 16) & 0xf,
3442 (int) (opcode
>> 0) & 0xf);
3445 return ERROR_INVALID_ARGUMENTS
;
3451 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3452 struct arm_instruction
*instruction
, char *cp
)
3454 int rn
= (opcode
>> 16) & 0xf;
3455 int op
= (opcode
>> 22) & 0x6;
3456 int t
= (opcode
>> 21) & 1;
3457 unsigned registers
= opcode
& 0xffff;
3460 if (opcode
& (1 << 20))
3468 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3476 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3477 (opcode
>> 16) & 0xf,
3481 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3485 sprintf(cp
, "POP.W\t");
3487 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3491 sprintf(cp
, "PUSH.W\t");
3493 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3496 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3499 return ERROR_INVALID_ARGUMENTS
;
3504 for (t
= 0; registers
; t
++, registers
>>= 1) {
3505 if ((registers
& 1) == 0)
3508 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3517 /* load/store dual or exclusive, table branch */
3518 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3519 struct arm_instruction
*instruction
, char *cp
)
3521 unsigned op1op2
= (opcode
>> 20) & 0x3;
3522 unsigned op3
= (opcode
>> 4) & 0xf;
3524 unsigned rn
= (opcode
>> 16) & 0xf;
3525 unsigned rt
= (opcode
>> 12) & 0xf;
3526 unsigned rd
= (opcode
>> 8) & 0xf;
3527 unsigned imm
= opcode
& 0xff;
3531 op1op2
|= (opcode
>> 21) & 0xc;
3561 mnemonic
= "STREXB";
3564 mnemonic
= "STREXH";
3567 return ERROR_INVALID_ARGUMENTS
;
3575 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3578 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3581 mnemonic
= "LDREXB";
3584 mnemonic
= "LDREXH";
3587 return ERROR_INVALID_ARGUMENTS
;
3592 return ERROR_INVALID_ARGUMENTS
;
3597 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3598 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3600 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3601 mnemonic
, rd
, rt
, rn
);
3607 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3608 mnemonic
, rt
, rn
, imm
, imm
);
3610 sprintf(cp
, "%s\tr%u, [r%u]",
3615 /* two indexed modes will write back rn */
3616 if (opcode
& (1 << 21)) {
3617 if (opcode
& (1 << 24)) /* pre-indexed */
3619 else { /* post-indexed */
3626 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3627 mnemonic
, rt
, rd
, rn
, p1
,
3628 (opcode
& (1 << 23)) ? "" : "-",
3633 address
= thumb_alignpc4(address
);
3635 if (opcode
& (1 << 23))
3639 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3640 mnemonic
, rt
, rd
, address
);
3644 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3645 struct arm_instruction
*instruction
, char *cp
)
3647 int op
= (opcode
>> 21) & 0xf;
3648 int rd
= (opcode
>> 8) & 0xf;
3649 int rn
= (opcode
>> 16) & 0xf;
3650 int type
= (opcode
>> 4) & 0x3;
3651 int immed
= (opcode
>> 6) & 0x3;
3655 immed
|= (opcode
>> 10) & 0x1c;
3656 if (opcode
& (1 << 20))
3662 if (!(opcode
& (1 << 20)))
3663 return ERROR_INVALID_ARGUMENTS
;
3664 instruction
->type
= ARM_TST
;
3669 instruction
->type
= ARM_AND
;
3673 instruction
->type
= ARM_BIC
;
3678 instruction
->type
= ARM_MOV
;
3682 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3684 (int) (opcode
& 0xf));
3697 sprintf(cp
, "RRX%s\tr%d, r%d",
3699 (int) (opcode
& 0xf));
3707 instruction
->type
= ARM_ORR
;
3713 instruction
->type
= ARM_MVN
;
3718 // instruction->type = ARM_ORN;
3724 if (!(opcode
& (1 << 20)))
3725 return ERROR_INVALID_ARGUMENTS
;
3726 instruction
->type
= ARM_TEQ
;
3731 instruction
->type
= ARM_EOR
;
3736 if (!(opcode
& (1 << 20)))
3737 return ERROR_INVALID_ARGUMENTS
;
3738 instruction
->type
= ARM_CMN
;
3743 instruction
->type
= ARM_ADD
;
3747 instruction
->type
= ARM_ADC
;
3751 instruction
->type
= ARM_SBC
;
3756 if (!(opcode
& (1 << 21)))
3757 return ERROR_INVALID_ARGUMENTS
;
3758 instruction
->type
= ARM_CMP
;
3763 instruction
->type
= ARM_SUB
;
3767 instruction
->type
= ARM_RSB
;
3771 return ERROR_INVALID_ARGUMENTS
;
3774 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3775 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3798 strcpy(cp
, ", RRX");
3804 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3808 sprintf(cp
, "%s%s.W\tr%d, r%d",
3809 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3813 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3814 mnemonic
, suffix
, rd
,
3815 (int) (opcode
& 0xf), immed
? immed
: 32);
3819 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3820 struct arm_instruction
*instruction
, char *cp
)
3825 if (((opcode
>> 4) & 0xf) == 0) {
3826 switch ((opcode
>> 21) & 0x7) {
3840 return ERROR_INVALID_ARGUMENTS
;
3843 instruction
->type
= ARM_MOV
;
3844 if (opcode
& (1 << 20))
3846 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3848 (int) (opcode
>> 8) & 0xf,
3849 (int) (opcode
>> 16) & 0xf,
3850 (int) (opcode
>> 0) & 0xf);
3852 } else if (opcode
& (1 << 7)) {
3853 switch ((opcode
>> 20) & 0xf) {
3858 switch ((opcode
>> 4) & 0x3) {
3860 suffix
= ", ROR #8";
3863 suffix
= ", ROR #16";
3866 suffix
= ", ROR #24";
3869 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3870 (opcode
& (1 << 24)) ? 'U' : 'S',
3871 (opcode
& (1 << 26)) ? 'B' : 'H',
3872 (int) (opcode
>> 8) & 0xf,
3873 (int) (opcode
>> 0) & 0xf,
3880 if (opcode
& (1 << 6))
3881 return ERROR_INVALID_ARGUMENTS
;
3882 if (((opcode
>> 12) & 0xf) != 0xf)
3883 return ERROR_INVALID_ARGUMENTS
;
3884 if (!(opcode
& (1 << 20)))
3885 return ERROR_INVALID_ARGUMENTS
;
3887 switch (((opcode
>> 19) & 0x04)
3888 | ((opcode
>> 4) & 0x3)) {
3893 mnemonic
= "REV16.W";
3899 mnemonic
= "REVSH.W";
3905 return ERROR_INVALID_ARGUMENTS
;
3907 sprintf(cp
, "%s\tr%d, r%d",
3909 (int) (opcode
>> 8) & 0xf,
3910 (int) (opcode
>> 0) & 0xf);
3913 return ERROR_INVALID_ARGUMENTS
;
3920 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3921 struct arm_instruction
*instruction
, char *cp
)
3923 int rn
= (opcode
>> 16) & 0xf;
3926 instruction
->type
= ARM_LDR
;
3929 immed
= opcode
& 0x0fff;
3930 if ((opcode
& (1 << 23)) == 0)
3932 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3933 (int) (opcode
>> 12) & 0xf,
3934 thumb_alignpc4(address
) + immed
);
3938 if (opcode
& (1 << 23)) {
3939 immed
= opcode
& 0x0fff;
3940 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3941 (int) (opcode
>> 12) & 0xf,
3946 if (!(opcode
& (0x3f << 6))) {
3947 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3948 (int) (opcode
>> 12) & 0xf,
3950 (int) (opcode
>> 0) & 0xf,
3951 (int) (opcode
>> 4) & 0x3);
3956 if (((opcode
>> 8) & 0xf) == 0xe) {
3957 immed
= opcode
& 0x00ff;
3959 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3960 (int) (opcode
>> 12) & 0xf,
3965 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3966 char *p1
= "]", *p2
= "";
3968 if (!(opcode
& 0x0500))
3969 return ERROR_INVALID_ARGUMENTS
;
3971 immed
= opcode
& 0x00ff;
3973 /* two indexed modes will write back rn */
3974 if (opcode
& 0x100) {
3975 if (opcode
& 0x400) /* pre-indexed */
3977 else { /* post-indexed */
3983 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3984 (int) (opcode
>> 12) & 0xf,
3986 (opcode
& 0x200) ? "" : "-",
3991 return ERROR_INVALID_ARGUMENTS
;
3994 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3995 struct arm_instruction
*instruction
, char *cp
)
3997 int rn
= (opcode
>> 16) & 0xf;
3998 int rt
= (opcode
>> 12) & 0xf;
3999 int op2
= (opcode
>> 6) & 0x3f;
4001 char *p1
= "", *p2
= "]";
4004 switch ((opcode
>> 23) & 0x3) {
4006 if ((rn
& rt
) == 0xf) {
4008 immed
= opcode
& 0xfff;
4009 address
= thumb_alignpc4(address
);
4010 if (opcode
& (1 << 23))
4014 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4018 if (rn
== 0x0f && rt
!= 0x0f) {
4020 immed
= opcode
& 0xfff;
4021 address
= thumb_alignpc4(address
);
4022 if (opcode
& (1 << 23))
4026 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4032 if ((op2
& 0x3c) == 0x38) {
4033 immed
= opcode
& 0xff;
4034 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4035 rt
, rn
, immed
, immed
);
4038 if ((op2
& 0x3c) == 0x30) {
4040 immed
= opcode
& 0xff;
4043 p1
= (opcode
& (1 << 21)) ? "W" : "";
4044 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4045 p1
, rn
, immed
, immed
);
4050 immed
= opcode
& 0xff;
4051 if (!(opcode
& 0x200))
4054 /* two indexed modes will write back rn */
4055 if (opcode
& 0x100) {
4056 if (opcode
& 0x400) /* pre-indexed */
4058 else { /* post-indexed */
4064 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4065 mnemonic
, rt
, rn
, p1
,
4069 if ((op2
& 0x24) == 0x24) {
4071 goto ldrxb_immediate_t3
;
4074 int rm
= opcode
& 0xf;
4077 sprintf(cp
, "PLD\t");
4079 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4080 immed
= (opcode
>> 4) & 0x3;
4082 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4087 if ((rn
& rt
) == 0xf)
4090 immed
= opcode
& 0xfff;
4091 goto preload_immediate
;
4095 mnemonic
= "LDRB.W";
4096 immed
= opcode
& 0xfff;
4097 goto ldrxb_immediate_t2
;
4099 if ((rn
& rt
) == 0xf) {
4100 immed
= opcode
& 0xfff;
4101 address
= thumb_alignpc4(address
);
4102 if (opcode
& (1 << 23))
4106 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4109 if (rn
== 0xf && rt
!= 0xf) {
4111 immed
= opcode
& 0xfff;
4112 address
= thumb_alignpc4(address
);
4113 if (opcode
& (1 << 23))
4117 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4122 if ((op2
& 0x3c) == 0x38) {
4123 immed
= opcode
& 0xff;
4124 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4125 rt
, rn
, immed
, immed
);
4128 if ((op2
& 0x3c) == 0x30) {
4130 immed
= opcode
& 0xff;
4131 immed
= -immed
; // pli
4132 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4137 goto ldrxb_immediate_t3
;
4139 if ((op2
& 0x24) == 0x24) {
4141 goto ldrxb_immediate_t3
;
4144 int rm
= opcode
& 0xf;
4147 sprintf(cp
, "PLI\t");
4149 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4150 immed
= (opcode
>> 4) & 0x3;
4152 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4158 immed
= opcode
& 0xfff;
4159 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4165 immed
= opcode
& 0xfff;
4167 goto ldrxb_immediate_t2
;
4170 return ERROR_INVALID_ARGUMENTS
;
4173 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4174 struct arm_instruction
*instruction
, char *cp
)
4176 int rn
= (opcode
>> 16) & 0xf;
4177 int rt
= (opcode
>> 12) & 0xf;
4178 int op2
= (opcode
>> 6) & 0x3f;
4183 sprintf(cp
, "HINT (UNALLOCATED)");
4187 if (opcode
& (1 << 24))
4190 if ((opcode
& (1 << 23)) == 0) {
4193 immed
= opcode
& 0xfff;
4194 address
= thumb_alignpc4(address
);
4195 if (opcode
& (1 << 23))
4199 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4204 int rm
= opcode
& 0xf;
4206 immed
= (opcode
>> 4) & 0x3;
4207 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4208 sign
, rt
, rn
, rm
, immed
);
4211 if ((op2
& 0x3c) == 0x38) {
4212 immed
= opcode
& 0xff;
4213 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4214 sign
, rt
, rn
, immed
, immed
);
4217 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4218 char *p1
= "", *p2
= "]";
4220 immed
= opcode
& 0xff;
4221 if (!(opcode
& 0x200))
4224 /* two indexed modes will write back rn */
4225 if (opcode
& 0x100) {
4226 if (opcode
& 0x400) /* pre-indexed */
4228 else { /* post-indexed */
4233 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4234 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4241 immed
= opcode
& 0xfff;
4242 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4243 sign
, *sign
? "" : ".W",
4244 rt
, rn
, immed
, immed
);
4248 return ERROR_INVALID_ARGUMENTS
;
4252 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4253 * always set. That means eventual arm_simulate_step() support for Thumb2
4254 * will need work in this area.
4256 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4263 /* clear low bit ... it's set on function pointers */
4266 /* clear fields, to avoid confusion */
4267 memset(instruction
, 0, sizeof(struct arm_instruction
));
4269 /* read first halfword, see if this is the only one */
4270 retval
= target_read_u16(target
, address
, &op
);
4271 if (retval
!= ERROR_OK
)
4274 switch (op
& 0xf800) {
4278 /* 32-bit instructions */
4279 instruction
->instruction_size
= 4;
4281 retval
= target_read_u16(target
, address
+ 2, &op
);
4282 if (retval
!= ERROR_OK
)
4285 instruction
->opcode
= opcode
;
4288 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4289 return thumb_evaluate_opcode(op
, address
, instruction
);
4292 snprintf(instruction
->text
, 128,
4293 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4295 cp
= strchr(instruction
->text
, 0);
4296 retval
= ERROR_FAIL
;
4298 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4299 if ((opcode
& 0x1a008000) == 0x10000000)
4300 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4302 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4303 else if ((opcode
& 0x1a008000) == 0x12000000)
4304 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4306 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4307 else if ((opcode
& 0x18008000) == 0x10008000)
4308 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4310 /* ARMv7-M: A5.3.5 Load/store multiple */
4311 else if ((opcode
& 0x1e400000) == 0x08000000)
4312 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4314 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4315 else if ((opcode
& 0x1e400000) == 0x08400000)
4316 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4318 /* ARMv7-M: A5.3.7 Load word */
4319 else if ((opcode
& 0x1f700000) == 0x18500000)
4320 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4322 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4323 else if ((opcode
& 0x1e700000) == 0x18300000)
4324 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4326 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4327 else if ((opcode
& 0x1e700000) == 0x18100000)
4328 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4330 /* ARMv7-M: A5.3.10 Store single data item */
4331 else if ((opcode
& 0x1f100000) == 0x18000000)
4332 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4334 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4335 else if ((opcode
& 0x1e000000) == 0x0a000000)
4336 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4338 /* ARMv7-M: A5.3.12 Data processing (register)
4339 * and A5.3.13 Miscellaneous operations
4341 else if ((opcode
& 0x1f000000) == 0x1a000000)
4342 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4344 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4345 else if ((opcode
& 0x1f800000) == 0x1b000000)
4346 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4348 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4349 else if ((opcode
& 0x1f800000) == 0x1b800000)
4350 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4352 if (retval
== ERROR_OK
)
4356 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4357 * instructions; not yet handled here.
4360 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4361 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4362 strcpy(cp
, "UNDEFINED OPCODE");
4366 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4369 strcpy(cp
, "(32-bit Thumb2 ...)");
4373 int arm_access_size(struct arm_instruction
*instruction
)
4375 if ((instruction
->type
== ARM_LDRB
)
4376 || (instruction
->type
== ARM_LDRBT
)
4377 || (instruction
->type
== ARM_LDRSB
)
4378 || (instruction
->type
== ARM_STRB
)
4379 || (instruction
->type
== ARM_STRBT
))
4383 else if ((instruction
->type
== ARM_LDRH
)
4384 || (instruction
->type
== ARM_LDRSH
)
4385 || (instruction
->type
== ARM_STRH
))
4389 else if ((instruction
->type
== ARM_LDR
)
4390 || (instruction
->type
== ARM_LDRT
)
4391 || (instruction
->type
== ARM_STR
)
4392 || (instruction
->type
== ARM_STRT
))
4396 else if ((instruction
->type
== ARM_LDRD
)
4397 || (instruction
->type
== ARM_STRD
))
4403 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)