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 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
54 * * NEON instructions are not understood (ARMv7-A)
56 * - Thumb/Thumb2 decoding
57 * * UAL syntax should be consistently used
58 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
59 * be handled properly. Accordingly, so should the subset
60 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
62 * * Conditional effects of Thumb2 "IT" (if-then) instructions
63 * are not handled: the affected instructions are not shown
64 * with their now-conditional suffixes.
65 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
66 * handled (minimally for coprocessor access).
67 * * SIMD instructions, and some other Thumb2 instructions
68 * from ARMv7-A, are not understood.
71 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
72 * * Opcodes changed by ThumbEE mode are not handled; these
73 * instructions wrongly decode as LDM and STM.
75 * - Jazelle decoding ... no support whatsoever for Jazelle mode
76 * or decoding. ARM encourages use of the more generic ThumbEE
77 * mode, instead of Jazelle mode, in current chips.
79 * - Single-step/emulation ... spotty support, which is only weakly
80 * tested. Thumb2 is not supported. (Arguably a full simulator
81 * is not needed to support just single stepping. Recognizing
82 * branch vs non-branch instructions suffices, except when the
83 * instruction faults and triggers a synchronous exception which
84 * can be intercepted using other means.)
86 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
87 * ARM v7-R edition" gives the most complete coverage of the various
88 * generations of ARM instructions. At this writing it is publicly
89 * accessible to anyone willing to create an account at the ARM
90 * web site; see http://www.arm.com/documentation/ for information.
92 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
93 * more details relevant to the Thumb2-only processors (such as
94 * the Cortex-M implementations).
97 /* textual represenation of the condition field */
98 /* ALways (default) is ommitted (empty string) */
99 static const char *arm_condition_strings
[] =
101 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
104 /* make up for C's missing ROR */
105 static uint32_t ror(uint32_t value
, int places
)
107 return (value
>> places
) | (value
<< (32 - places
));
110 static int evaluate_unknown(uint32_t opcode
,
111 uint32_t address
, struct arm_instruction
*instruction
)
113 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
114 snprintf(instruction
->text
, 128,
115 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
116 "\tUNDEFINED INSTRUCTION", address
, opcode
);
120 static int evaluate_pld(uint32_t opcode
,
121 uint32_t address
, struct arm_instruction
*instruction
)
124 if ((opcode
& 0x0d70f000) == 0x0550f000)
126 instruction
->type
= ARM_PLD
;
128 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
132 return evaluate_unknown(opcode
, address
, instruction
);
135 static int evaluate_srs(uint32_t opcode
,
136 uint32_t address
, struct arm_instruction
*instruction
)
138 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
139 const char *mode
= "";
141 switch ((opcode
>> 23) & 0x3) {
146 /* "IA" is default */
156 switch (opcode
& 0x0e500000) {
158 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
160 "\tSRS%s\tSP%s, #%d",
163 (unsigned)(opcode
& 0x1f));
166 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
171 (unsigned)((opcode
>> 16) & 0xf), wback
);
174 return evaluate_unknown(opcode
, address
, instruction
);
179 static int evaluate_swi(uint32_t opcode
,
180 uint32_t address
, struct arm_instruction
*instruction
)
182 instruction
->type
= ARM_SWI
;
184 snprintf(instruction
->text
, 128,
185 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
186 address
, opcode
, (opcode
& 0xffffff));
191 static int evaluate_blx_imm(uint32_t opcode
,
192 uint32_t address
, struct arm_instruction
*instruction
)
196 uint32_t target_address
;
198 instruction
->type
= ARM_BLX
;
199 immediate
= opcode
& 0x00ffffff;
201 /* sign extend 24-bit immediate */
202 if (immediate
& 0x00800000)
203 offset
= 0xff000000 | immediate
;
207 /* shift two bits left */
210 /* odd/event halfword */
211 if (opcode
& 0x01000000)
214 target_address
= address
+ 8 + offset
;
216 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
218 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
219 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
224 static int evaluate_b_bl(uint32_t opcode
,
225 uint32_t address
, struct arm_instruction
*instruction
)
230 uint32_t target_address
;
232 immediate
= opcode
& 0x00ffffff;
233 L
= (opcode
& 0x01000000) >> 24;
235 /* sign extend 24-bit immediate */
236 if (immediate
& 0x00800000)
237 offset
= 0xff000000 | immediate
;
241 /* shift two bits left */
244 target_address
= address
+ 8 + offset
;
247 instruction
->type
= ARM_BL
;
249 instruction
->type
= ARM_B
;
251 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
252 (L
) ? "L" : "", COND(opcode
), target_address
);
254 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
255 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
260 /* Coprocessor load/store and double register transfers */
261 /* both normal and extended instruction space (condition field b1111) */
262 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
263 uint32_t address
, struct arm_instruction
*instruction
)
265 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
268 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
270 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
273 cp_opcode
= (opcode
& 0xf0) >> 4;
274 Rd
= (opcode
& 0xf000) >> 12;
275 Rn
= (opcode
& 0xf0000) >> 16;
276 CRm
= (opcode
& 0xf);
279 if ((opcode
& 0x0ff00000) == 0x0c400000)
281 instruction
->type
= ARM_MCRR
;
286 if ((opcode
& 0x0ff00000) == 0x0c500000)
288 instruction
->type
= ARM_MRRC
;
292 snprintf(instruction
->text
, 128,
293 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
294 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
295 address
, opcode
, mnemonic
,
296 ((opcode
& 0xf0000000) == 0xf0000000)
297 ? "2" : COND(opcode
),
298 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
300 else /* LDC or STC */
302 uint8_t CRd
, Rn
, offset
;
305 char addressing_mode
[32];
307 CRd
= (opcode
& 0xf000) >> 12;
308 Rn
= (opcode
& 0xf0000) >> 16;
309 offset
= (opcode
& 0xff) << 2;
312 if (opcode
& 0x00100000)
314 instruction
->type
= ARM_LDC
;
319 instruction
->type
= ARM_STC
;
323 U
= (opcode
& 0x00800000) >> 23;
324 N
= (opcode
& 0x00400000) >> 22;
326 /* addressing modes */
327 if ((opcode
& 0x01200000) == 0x01000000) /* offset */
328 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
329 Rn
, U
? "" : "-", offset
);
330 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
331 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
332 Rn
, U
? "" : "-", offset
);
333 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
334 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
335 Rn
, U
? "" : "-", offset
);
336 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
337 snprintf(addressing_mode
, 32, "[r%i], {%d}",
340 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
342 "\t%s%s%s p%i, c%i, %s",
343 address
, opcode
, mnemonic
,
344 ((opcode
& 0xf0000000) == 0xf0000000)
345 ? "2" : COND(opcode
),
346 (opcode
& (1 << 22)) ? "L" : "",
347 cp_num
, CRd
, addressing_mode
);
353 /* Coprocessor data processing instructions */
354 /* Coprocessor register transfer instructions */
355 /* both normal and extended instruction space (condition field b1111) */
356 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
357 uint32_t address
, struct arm_instruction
*instruction
)
361 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
363 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
364 cp_num
= (opcode
& 0xf00) >> 8;
365 CRd_Rd
= (opcode
& 0xf000) >> 12;
366 CRn
= (opcode
& 0xf0000) >> 16;
367 CRm
= (opcode
& 0xf);
368 opcode_2
= (opcode
& 0xe0) >> 5;
371 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
373 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
375 instruction
->type
= ARM_MRC
;
378 else /* bit 20 not set -> MCR */
380 instruction
->type
= ARM_MCR
;
384 opcode_1
= (opcode
& 0x00e00000) >> 21;
386 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",
387 address
, opcode
, mnemonic
, cond
,
388 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
390 else /* bit 4 not set -> CDP */
392 instruction
->type
= ARM_CDP
;
395 opcode_1
= (opcode
& 0x00f00000) >> 20;
397 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",
398 address
, opcode
, mnemonic
, cond
,
399 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
405 /* Load/store instructions */
406 static int evaluate_load_store(uint32_t opcode
,
407 uint32_t address
, struct arm_instruction
*instruction
)
409 uint8_t I
, P
, U
, B
, W
, L
;
411 char *operation
; /* "LDR" or "STR" */
412 char *suffix
; /* "", "B", "T", "BT" */
416 I
= (opcode
& 0x02000000) >> 25;
417 P
= (opcode
& 0x01000000) >> 24;
418 U
= (opcode
& 0x00800000) >> 23;
419 B
= (opcode
& 0x00400000) >> 22;
420 W
= (opcode
& 0x00200000) >> 21;
421 L
= (opcode
& 0x00100000) >> 20;
423 /* target register */
424 Rd
= (opcode
& 0xf000) >> 12;
427 Rn
= (opcode
& 0xf0000) >> 16;
429 instruction
->info
.load_store
.Rd
= Rd
;
430 instruction
->info
.load_store
.Rn
= Rn
;
431 instruction
->info
.load_store
.U
= U
;
433 /* determine operation */
439 /* determine instruction type and suffix */
442 if ((P
== 0) && (W
== 1))
445 instruction
->type
= ARM_LDRBT
;
447 instruction
->type
= ARM_STRBT
;
453 instruction
->type
= ARM_LDRB
;
455 instruction
->type
= ARM_STRB
;
461 if ((P
== 0) && (W
== 1))
464 instruction
->type
= ARM_LDRT
;
466 instruction
->type
= ARM_STRT
;
472 instruction
->type
= ARM_LDR
;
474 instruction
->type
= ARM_STR
;
479 if (!I
) /* #+-<offset_12> */
481 uint32_t offset_12
= (opcode
& 0xfff);
483 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
485 snprintf(offset
, 32, "%s", "");
487 instruction
->info
.load_store
.offset_mode
= 0;
488 instruction
->info
.load_store
.offset
.offset
= offset_12
;
490 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
492 uint8_t shift_imm
, shift
;
495 shift_imm
= (opcode
& 0xf80) >> 7;
496 shift
= (opcode
& 0x60) >> 5;
499 /* LSR encodes a shift by 32 bit as 0x0 */
500 if ((shift
== 0x1) && (shift_imm
== 0x0))
503 /* ASR encodes a shift by 32 bit as 0x0 */
504 if ((shift
== 0x2) && (shift_imm
== 0x0))
507 /* ROR by 32 bit is actually a RRX */
508 if ((shift
== 0x3) && (shift_imm
== 0x0))
511 instruction
->info
.load_store
.offset_mode
= 1;
512 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
513 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
514 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
516 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
518 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
520 else /* +-<Rm>, <Shift>, #<shift_imm> */
525 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
528 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
531 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
534 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
537 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
545 if (W
== 0) /* offset */
547 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
548 address
, opcode
, operation
, COND(opcode
), suffix
,
551 instruction
->info
.load_store
.index_mode
= 0;
553 else /* pre-indexed */
555 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
556 address
, opcode
, operation
, COND(opcode
), suffix
,
559 instruction
->info
.load_store
.index_mode
= 1;
562 else /* post-indexed */
564 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
565 address
, opcode
, operation
, COND(opcode
), suffix
,
568 instruction
->info
.load_store
.index_mode
= 2;
574 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
576 unsigned rm
= (opcode
>> 0) & 0xf;
577 unsigned rd
= (opcode
>> 12) & 0xf;
578 unsigned rn
= (opcode
>> 16) & 0xf;
581 switch ((opcode
>> 24) & 0x3) {
586 sprintf(cp
, "UNDEFINED");
587 return ARM_UNDEFINED_INSTRUCTION
;
596 switch ((opcode
>> 10) & 0x3) {
612 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
613 (opcode
& (1 << 22)) ? 'U' : 'S',
618 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
619 (opcode
& (1 << 22)) ? 'U' : 'S',
626 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
632 switch ((opcode
>> 20) & 0x7) {
655 switch ((opcode
>> 5) & 0x7) {
684 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
685 (int) (opcode
>> 12) & 0xf,
686 (int) (opcode
>> 16) & 0xf,
687 (int) (opcode
>> 0) & 0xf);
691 /* these opcodes might be used someday */
692 sprintf(cp
, "UNDEFINED");
693 return ARM_UNDEFINED_INSTRUCTION
;
696 /* ARMv6 and later support "media" instructions (includes SIMD) */
697 static int evaluate_media(uint32_t opcode
, uint32_t address
,
698 struct arm_instruction
*instruction
)
700 char *cp
= instruction
->text
;
701 char *mnemonic
= NULL
;
704 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
708 /* parallel add/subtract */
709 if ((opcode
& 0x01800000) == 0x00000000) {
710 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
715 if ((opcode
& 0x01f00020) == 0x00800000) {
717 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
719 if (opcode
& (1 << 6)) {
728 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
730 (int) (opcode
>> 12) & 0xf,
731 (int) (opcode
>> 16) & 0xf,
732 (int) (opcode
>> 0) & 0xf,
738 if ((opcode
& 0x01a00020) == 0x00a00000) {
740 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
742 if (opcode
& (1 << 6)) {
750 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
751 (opcode
& (1 << 22)) ? 'U' : 'S',
753 (int) (opcode
>> 12) & 0xf,
754 (int) (opcode
>> 16) & 0x1f,
755 (int) (opcode
>> 0) & 0xf,
761 if ((opcode
& 0x018000f0) == 0x00800070) {
762 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
767 if ((opcode
& 0x01f00080) == 0x01000000) {
768 unsigned rn
= (opcode
>> 12) & 0xf;
771 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
772 (opcode
& (1 << 6)) ? 'S' : 'A',
773 (opcode
& (1 << 5)) ? "X" : "",
775 (int) (opcode
>> 16) & 0xf,
776 (int) (opcode
>> 0) & 0xf,
777 (int) (opcode
>> 8) & 0xf,
780 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
781 (opcode
& (1 << 6)) ? 'S' : 'A',
782 (opcode
& (1 << 5)) ? "X" : "",
784 (int) (opcode
>> 16) & 0xf,
785 (int) (opcode
>> 0) & 0xf,
786 (int) (opcode
>> 8) & 0xf);
789 if ((opcode
& 0x01f00000) == 0x01400000) {
790 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
791 (opcode
& (1 << 6)) ? 'S' : 'A',
792 (opcode
& (1 << 5)) ? "X" : "",
794 (int) (opcode
>> 12) & 0xf,
795 (int) (opcode
>> 16) & 0xf,
796 (int) (opcode
>> 0) & 0xf,
797 (int) (opcode
>> 8) & 0xf);
800 if ((opcode
& 0x01f00000) == 0x01500000) {
801 unsigned rn
= (opcode
>> 12) & 0xf;
803 switch (opcode
& 0xc0) {
815 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
816 (opcode
& (1 << 6)) ? 'S' : 'A',
817 (opcode
& (1 << 5)) ? "R" : "",
819 (int) (opcode
>> 16) & 0xf,
820 (int) (opcode
>> 0) & 0xf,
821 (int) (opcode
>> 8) & 0xf,
824 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
825 (opcode
& (1 << 5)) ? "R" : "",
827 (int) (opcode
>> 16) & 0xf,
828 (int) (opcode
>> 0) & 0xf,
829 (int) (opcode
>> 8) & 0xf);
834 /* simple matches against the remaining decode bits */
835 switch (opcode
& 0x01f000f0) {
838 /* parallel halfword saturate */
839 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
840 (opcode
& (1 << 22)) ? 'U' : 'S',
842 (int) (opcode
>> 12) & 0xf,
843 (int) (opcode
>> 16) & 0xf,
844 (int) (opcode
>> 0) & 0xf);
857 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
858 (int) (opcode
>> 12) & 0xf,
859 (int) (opcode
>> 16) & 0xf,
860 (int) (opcode
>> 0) & 0xf);
863 /* unsigned sum of absolute differences */
864 if (((opcode
>> 12) & 0xf) == 0xf)
865 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
866 (int) (opcode
>> 16) & 0xf,
867 (int) (opcode
>> 0) & 0xf,
868 (int) (opcode
>> 8) & 0xf);
870 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
871 (int) (opcode
>> 16) & 0xf,
872 (int) (opcode
>> 0) & 0xf,
873 (int) (opcode
>> 8) & 0xf,
874 (int) (opcode
>> 12) & 0xf);
878 unsigned rm
= (opcode
>> 0) & 0xf;
879 unsigned rd
= (opcode
>> 12) & 0xf;
881 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
886 /* these opcodes might be used someday */
887 sprintf(cp
, "UNDEFINED");
891 /* Miscellaneous load/store instructions */
892 static int evaluate_misc_load_store(uint32_t opcode
,
893 uint32_t address
, struct arm_instruction
*instruction
)
895 uint8_t P
, U
, I
, W
, L
, S
, H
;
897 char *operation
; /* "LDR" or "STR" */
898 char *suffix
; /* "H", "SB", "SH", "D" */
902 P
= (opcode
& 0x01000000) >> 24;
903 U
= (opcode
& 0x00800000) >> 23;
904 I
= (opcode
& 0x00400000) >> 22;
905 W
= (opcode
& 0x00200000) >> 21;
906 L
= (opcode
& 0x00100000) >> 20;
907 S
= (opcode
& 0x00000040) >> 6;
908 H
= (opcode
& 0x00000020) >> 5;
910 /* target register */
911 Rd
= (opcode
& 0xf000) >> 12;
914 Rn
= (opcode
& 0xf0000) >> 16;
916 instruction
->info
.load_store
.Rd
= Rd
;
917 instruction
->info
.load_store
.Rn
= Rn
;
918 instruction
->info
.load_store
.U
= U
;
920 /* determine instruction type and suffix */
928 instruction
->type
= ARM_LDRSH
;
934 instruction
->type
= ARM_LDRSB
;
938 else /* there are no signed stores, so this is used to encode double-register load/stores */
944 instruction
->type
= ARM_STRD
;
949 instruction
->type
= ARM_LDRD
;
959 instruction
->type
= ARM_LDRH
;
964 instruction
->type
= ARM_STRH
;
968 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
970 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
971 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
973 instruction
->info
.load_store
.offset_mode
= 0;
974 instruction
->info
.load_store
.offset
.offset
= offset_8
;
976 else /* Register offset/index (+-<Rm>) */
980 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
982 instruction
->info
.load_store
.offset_mode
= 1;
983 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
984 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
985 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
990 if (W
== 0) /* offset */
992 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
993 address
, opcode
, operation
, COND(opcode
), suffix
,
996 instruction
->info
.load_store
.index_mode
= 0;
998 else /* pre-indexed */
1000 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1001 address
, opcode
, operation
, COND(opcode
), suffix
,
1004 instruction
->info
.load_store
.index_mode
= 1;
1007 else /* post-indexed */
1009 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1010 address
, opcode
, operation
, COND(opcode
), suffix
,
1013 instruction
->info
.load_store
.index_mode
= 2;
1019 /* Load/store multiples instructions */
1020 static int evaluate_ldm_stm(uint32_t opcode
,
1021 uint32_t address
, struct arm_instruction
*instruction
)
1023 uint8_t P
, U
, S
, W
, L
, Rn
;
1024 uint32_t register_list
;
1025 char *addressing_mode
;
1032 P
= (opcode
& 0x01000000) >> 24;
1033 U
= (opcode
& 0x00800000) >> 23;
1034 S
= (opcode
& 0x00400000) >> 22;
1035 W
= (opcode
& 0x00200000) >> 21;
1036 L
= (opcode
& 0x00100000) >> 20;
1037 register_list
= (opcode
& 0xffff);
1038 Rn
= (opcode
& 0xf0000) >> 16;
1040 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1041 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1042 instruction
->info
.load_store_multiple
.S
= S
;
1043 instruction
->info
.load_store_multiple
.W
= W
;
1047 instruction
->type
= ARM_LDM
;
1052 instruction
->type
= ARM_STM
;
1060 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1061 addressing_mode
= "IB";
1065 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1066 addressing_mode
= "DB";
1073 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1074 /* "IA" is the default in UAL syntax */
1075 addressing_mode
= "";
1079 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1080 addressing_mode
= "DA";
1084 reg_list_p
= reg_list
;
1085 for (i
= 0; i
<= 15; i
++)
1087 if ((register_list
>> i
) & 1)
1092 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1096 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1101 snprintf(instruction
->text
, 128,
1102 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1103 "\t%s%s%s r%i%s, {%s}%s",
1105 mnemonic
, addressing_mode
, COND(opcode
),
1106 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1111 /* Multiplies, extra load/stores */
1112 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1113 uint32_t address
, struct arm_instruction
*instruction
)
1115 /* Multiply (accumulate) (long) and Swap/swap byte */
1116 if ((opcode
& 0x000000f0) == 0x00000090)
1118 /* Multiply (accumulate) */
1119 if ((opcode
& 0x0f800000) == 0x00000000)
1121 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1123 Rs
= (opcode
& 0xf00) >> 8;
1124 Rn
= (opcode
& 0xf000) >> 12;
1125 Rd
= (opcode
& 0xf0000) >> 16;
1126 S
= (opcode
& 0x00100000) >> 20;
1128 /* examine A bit (accumulate) */
1129 if (opcode
& 0x00200000)
1131 instruction
->type
= ARM_MLA
;
1132 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1133 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1137 instruction
->type
= ARM_MUL
;
1138 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1139 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1145 /* Multiply (accumulate) long */
1146 if ((opcode
& 0x0f800000) == 0x00800000)
1148 char* mnemonic
= NULL
;
1149 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1151 Rs
= (opcode
& 0xf00) >> 8;
1152 RdHi
= (opcode
& 0xf000) >> 12;
1153 RdLow
= (opcode
& 0xf0000) >> 16;
1154 S
= (opcode
& 0x00100000) >> 20;
1156 switch ((opcode
& 0x00600000) >> 21)
1159 instruction
->type
= ARM_UMULL
;
1163 instruction
->type
= ARM_UMLAL
;
1167 instruction
->type
= ARM_SMULL
;
1171 instruction
->type
= ARM_SMLAL
;
1176 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1177 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1178 RdLow
, RdHi
, Rm
, Rs
);
1183 /* Swap/swap byte */
1184 if ((opcode
& 0x0f800000) == 0x01000000)
1188 Rd
= (opcode
& 0xf000) >> 12;
1189 Rn
= (opcode
& 0xf0000) >> 16;
1191 /* examine B flag */
1192 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1194 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1195 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1201 return evaluate_misc_load_store(opcode
, address
, instruction
);
1204 static int evaluate_mrs_msr(uint32_t opcode
,
1205 uint32_t address
, struct arm_instruction
*instruction
)
1207 int R
= (opcode
& 0x00400000) >> 22;
1208 char *PSR
= (R
) ? "SPSR" : "CPSR";
1210 /* Move register to status register (MSR) */
1211 if (opcode
& 0x00200000)
1213 instruction
->type
= ARM_MSR
;
1215 /* immediate variant */
1216 if (opcode
& 0x02000000)
1218 uint8_t immediate
= (opcode
& 0xff);
1219 uint8_t rotate
= (opcode
& 0xf00);
1221 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1222 address
, opcode
, COND(opcode
), PSR
,
1223 (opcode
& 0x10000) ? "c" : "",
1224 (opcode
& 0x20000) ? "x" : "",
1225 (opcode
& 0x40000) ? "s" : "",
1226 (opcode
& 0x80000) ? "f" : "",
1227 ror(immediate
, (rotate
* 2))
1230 else /* register variant */
1232 uint8_t Rm
= opcode
& 0xf;
1233 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1234 address
, opcode
, COND(opcode
), PSR
,
1235 (opcode
& 0x10000) ? "c" : "",
1236 (opcode
& 0x20000) ? "x" : "",
1237 (opcode
& 0x40000) ? "s" : "",
1238 (opcode
& 0x80000) ? "f" : "",
1244 else /* Move status register to register (MRS) */
1248 instruction
->type
= ARM_MRS
;
1249 Rd
= (opcode
& 0x0000f000) >> 12;
1251 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1252 address
, opcode
, COND(opcode
), Rd
, PSR
);
1258 /* Miscellaneous instructions */
1259 static int evaluate_misc_instr(uint32_t opcode
,
1260 uint32_t address
, struct arm_instruction
*instruction
)
1263 if ((opcode
& 0x000000f0) == 0x00000000)
1265 evaluate_mrs_msr(opcode
, address
, instruction
);
1269 if ((opcode
& 0x006000f0) == 0x00200010)
1272 instruction
->type
= ARM_BX
;
1275 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1276 address
, opcode
, COND(opcode
), Rm
);
1278 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1279 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1282 /* BXJ - "Jazelle" support (ARMv5-J) */
1283 if ((opcode
& 0x006000f0) == 0x00200020)
1286 instruction
->type
= ARM_BX
;
1289 snprintf(instruction
->text
, 128,
1290 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1291 address
, opcode
, COND(opcode
), Rm
);
1293 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1294 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1298 if ((opcode
& 0x006000f0) == 0x00600010)
1301 instruction
->type
= ARM_CLZ
;
1303 Rd
= (opcode
& 0xf000) >> 12;
1305 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1306 address
, opcode
, COND(opcode
), Rd
, Rm
);
1310 if ((opcode
& 0x006000f0) == 0x00200030)
1313 instruction
->type
= ARM_BLX
;
1316 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1317 address
, opcode
, COND(opcode
), Rm
);
1319 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1320 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1323 /* Enhanced DSP add/subtracts */
1324 if ((opcode
& 0x0000000f0) == 0x00000050)
1327 char *mnemonic
= NULL
;
1329 Rd
= (opcode
& 0xf000) >> 12;
1330 Rn
= (opcode
& 0xf0000) >> 16;
1332 switch ((opcode
& 0x00600000) >> 21)
1335 instruction
->type
= ARM_QADD
;
1339 instruction
->type
= ARM_QSUB
;
1343 instruction
->type
= ARM_QDADD
;
1347 instruction
->type
= ARM_QDSUB
;
1352 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1353 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1356 /* Software breakpoints */
1357 if ((opcode
& 0x0000000f0) == 0x00000070)
1360 instruction
->type
= ARM_BKPT
;
1361 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1363 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1364 address
, opcode
, immediate
);
1367 /* Enhanced DSP multiplies */
1368 if ((opcode
& 0x000000090) == 0x00000080)
1370 int x
= (opcode
& 0x20) >> 5;
1371 int y
= (opcode
& 0x40) >> 6;
1374 if ((opcode
& 0x00600000) == 0x00000000)
1376 uint8_t Rd
, Rm
, Rs
, Rn
;
1377 instruction
->type
= ARM_SMLAxy
;
1378 Rd
= (opcode
& 0xf0000) >> 16;
1379 Rm
= (opcode
& 0xf);
1380 Rs
= (opcode
& 0xf00) >> 8;
1381 Rn
= (opcode
& 0xf000) >> 12;
1383 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1384 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1389 if ((opcode
& 0x00600000) == 0x00400000)
1391 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1392 instruction
->type
= ARM_SMLAxy
;
1393 RdHi
= (opcode
& 0xf0000) >> 16;
1394 RdLow
= (opcode
& 0xf000) >> 12;
1395 Rm
= (opcode
& 0xf);
1396 Rs
= (opcode
& 0xf00) >> 8;
1398 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1399 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1400 RdLow
, RdHi
, Rm
, Rs
);
1404 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1406 uint8_t Rd
, Rm
, Rs
, Rn
;
1407 instruction
->type
= ARM_SMLAWy
;
1408 Rd
= (opcode
& 0xf0000) >> 16;
1409 Rm
= (opcode
& 0xf);
1410 Rs
= (opcode
& 0xf00) >> 8;
1411 Rn
= (opcode
& 0xf000) >> 12;
1413 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1414 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1419 if ((opcode
& 0x00600000) == 0x00300000)
1422 instruction
->type
= ARM_SMULxy
;
1423 Rd
= (opcode
& 0xf0000) >> 16;
1424 Rm
= (opcode
& 0xf);
1425 Rs
= (opcode
& 0xf00) >> 8;
1427 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1428 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1433 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1436 instruction
->type
= ARM_SMULWy
;
1437 Rd
= (opcode
& 0xf0000) >> 16;
1438 Rm
= (opcode
& 0xf);
1439 Rs
= (opcode
& 0xf00) >> 8;
1441 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1442 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1450 static int evaluate_data_proc(uint32_t opcode
,
1451 uint32_t address
, struct arm_instruction
*instruction
)
1453 uint8_t I
, op
, S
, Rn
, Rd
;
1454 char *mnemonic
= NULL
;
1455 char shifter_operand
[32];
1457 I
= (opcode
& 0x02000000) >> 25;
1458 op
= (opcode
& 0x01e00000) >> 21;
1459 S
= (opcode
& 0x00100000) >> 20;
1461 Rd
= (opcode
& 0xf000) >> 12;
1462 Rn
= (opcode
& 0xf0000) >> 16;
1464 instruction
->info
.data_proc
.Rd
= Rd
;
1465 instruction
->info
.data_proc
.Rn
= Rn
;
1466 instruction
->info
.data_proc
.S
= S
;
1471 instruction
->type
= ARM_AND
;
1475 instruction
->type
= ARM_EOR
;
1479 instruction
->type
= ARM_SUB
;
1483 instruction
->type
= ARM_RSB
;
1487 instruction
->type
= ARM_ADD
;
1491 instruction
->type
= ARM_ADC
;
1495 instruction
->type
= ARM_SBC
;
1499 instruction
->type
= ARM_RSC
;
1503 instruction
->type
= ARM_TST
;
1507 instruction
->type
= ARM_TEQ
;
1511 instruction
->type
= ARM_CMP
;
1515 instruction
->type
= ARM_CMN
;
1519 instruction
->type
= ARM_ORR
;
1523 instruction
->type
= ARM_MOV
;
1527 instruction
->type
= ARM_BIC
;
1531 instruction
->type
= ARM_MVN
;
1536 if (I
) /* immediate shifter operand (#<immediate>)*/
1538 uint8_t immed_8
= opcode
& 0xff;
1539 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1542 immediate
= ror(immed_8
, rotate_imm
* 2);
1544 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1546 instruction
->info
.data_proc
.variant
= 0;
1547 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1549 else /* register-based shifter operand */
1552 shift
= (opcode
& 0x60) >> 5;
1553 Rm
= (opcode
& 0xf);
1555 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1558 shift_imm
= (opcode
& 0xf80) >> 7;
1560 instruction
->info
.data_proc
.variant
= 1;
1561 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1562 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1563 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1565 /* LSR encodes a shift by 32 bit as 0x0 */
1566 if ((shift
== 0x1) && (shift_imm
== 0x0))
1569 /* ASR encodes a shift by 32 bit as 0x0 */
1570 if ((shift
== 0x2) && (shift_imm
== 0x0))
1573 /* ROR by 32 bit is actually a RRX */
1574 if ((shift
== 0x3) && (shift_imm
== 0x0))
1577 if ((shift_imm
== 0x0) && (shift
== 0x0))
1579 snprintf(shifter_operand
, 32, "r%i", Rm
);
1583 if (shift
== 0x0) /* LSL */
1585 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1587 else if (shift
== 0x1) /* LSR */
1589 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1591 else if (shift
== 0x2) /* ASR */
1593 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1595 else if (shift
== 0x3) /* ROR */
1597 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1599 else if (shift
== 0x4) /* RRX */
1601 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1605 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1607 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1609 instruction
->info
.data_proc
.variant
= 2;
1610 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1611 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1612 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1614 if (shift
== 0x0) /* LSL */
1616 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1618 else if (shift
== 0x1) /* LSR */
1620 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1622 else if (shift
== 0x2) /* ASR */
1624 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1626 else if (shift
== 0x3) /* ROR */
1628 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1633 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1635 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1636 address
, opcode
, mnemonic
, COND(opcode
),
1637 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1639 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1641 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1642 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1644 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1645 address
, opcode
, mnemonic
, COND(opcode
),
1646 (S
) ? "S" : "", Rd
, shifter_operand
);
1648 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1650 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1651 address
, opcode
, mnemonic
, COND(opcode
),
1652 Rn
, shifter_operand
);
1658 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1659 struct arm_instruction
*instruction
)
1661 /* clear fields, to avoid confusion */
1662 memset(instruction
, 0, sizeof(struct arm_instruction
));
1663 instruction
->opcode
= opcode
;
1664 instruction
->instruction_size
= 4;
1666 /* catch opcodes with condition field [31:28] = b1111 */
1667 if ((opcode
& 0xf0000000) == 0xf0000000)
1669 /* Undefined instruction (or ARMv5E cache preload PLD) */
1670 if ((opcode
& 0x08000000) == 0x00000000)
1671 return evaluate_pld(opcode
, address
, instruction
);
1673 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1674 if ((opcode
& 0x0e000000) == 0x08000000)
1675 return evaluate_srs(opcode
, address
, instruction
);
1677 /* Branch and branch with link and change to Thumb */
1678 if ((opcode
& 0x0e000000) == 0x0a000000)
1679 return evaluate_blx_imm(opcode
, address
, instruction
);
1681 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1682 /* Coprocessor load/store and double register transfers */
1683 if ((opcode
& 0x0e000000) == 0x0c000000)
1684 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1686 /* Coprocessor data processing */
1687 if ((opcode
& 0x0f000100) == 0x0c000000)
1688 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1690 /* Coprocessor register transfers */
1691 if ((opcode
& 0x0f000010) == 0x0c000010)
1692 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1694 /* Undefined instruction */
1695 if ((opcode
& 0x0f000000) == 0x0f000000)
1697 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1698 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1703 /* catch opcodes with [27:25] = b000 */
1704 if ((opcode
& 0x0e000000) == 0x00000000)
1706 /* Multiplies, extra load/stores */
1707 if ((opcode
& 0x00000090) == 0x00000090)
1708 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1710 /* Miscellaneous instructions */
1711 if ((opcode
& 0x0f900000) == 0x01000000)
1712 return evaluate_misc_instr(opcode
, address
, instruction
);
1714 return evaluate_data_proc(opcode
, address
, instruction
);
1717 /* catch opcodes with [27:25] = b001 */
1718 if ((opcode
& 0x0e000000) == 0x02000000)
1720 /* Undefined instruction */
1721 if ((opcode
& 0x0fb00000) == 0x03000000)
1723 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1724 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1728 /* Move immediate to status register */
1729 if ((opcode
& 0x0fb00000) == 0x03200000)
1730 return evaluate_mrs_msr(opcode
, address
, instruction
);
1732 return evaluate_data_proc(opcode
, address
, instruction
);
1736 /* catch opcodes with [27:25] = b010 */
1737 if ((opcode
& 0x0e000000) == 0x04000000)
1739 /* Load/store immediate offset */
1740 return evaluate_load_store(opcode
, address
, instruction
);
1743 /* catch opcodes with [27:25] = b011 */
1744 if ((opcode
& 0x0e000000) == 0x06000000)
1746 /* Load/store register offset */
1747 if ((opcode
& 0x00000010) == 0x00000000)
1748 return evaluate_load_store(opcode
, address
, instruction
);
1750 /* Architecturally Undefined instruction
1751 * ... don't expect these to ever be used
1753 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1755 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1756 snprintf(instruction
->text
, 128,
1757 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1762 /* "media" instructions */
1763 return evaluate_media(opcode
, address
, instruction
);
1766 /* catch opcodes with [27:25] = b100 */
1767 if ((opcode
& 0x0e000000) == 0x08000000)
1769 /* Load/store multiple */
1770 return evaluate_ldm_stm(opcode
, address
, instruction
);
1773 /* catch opcodes with [27:25] = b101 */
1774 if ((opcode
& 0x0e000000) == 0x0a000000)
1776 /* Branch and branch with link */
1777 return evaluate_b_bl(opcode
, address
, instruction
);
1780 /* catch opcodes with [27:25] = b110 */
1781 if ((opcode
& 0x0e000000) == 0x0c000000)
1783 /* Coprocessor load/store and double register transfers */
1784 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1787 /* catch opcodes with [27:25] = b111 */
1788 if ((opcode
& 0x0e000000) == 0x0e000000)
1790 /* Software interrupt */
1791 if ((opcode
& 0x0f000000) == 0x0f000000)
1792 return evaluate_swi(opcode
, address
, instruction
);
1794 /* Coprocessor data processing */
1795 if ((opcode
& 0x0f000010) == 0x0e000000)
1796 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1798 /* Coprocessor register transfers */
1799 if ((opcode
& 0x0f000010) == 0x0e000010)
1800 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1803 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1808 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1809 uint32_t address
, struct arm_instruction
*instruction
)
1811 uint32_t offset
= opcode
& 0x7ff;
1812 uint32_t opc
= (opcode
>> 11) & 0x3;
1813 uint32_t target_address
;
1814 char *mnemonic
= NULL
;
1816 /* sign extend 11-bit offset */
1817 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1818 offset
= 0xfffff800 | offset
;
1820 target_address
= address
+ 4 + (offset
<< 1);
1824 /* unconditional branch */
1826 instruction
->type
= ARM_B
;
1831 instruction
->type
= ARM_BLX
;
1833 target_address
&= 0xfffffffc;
1837 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1838 mnemonic
= "prefix";
1839 target_address
= offset
<< 12;
1843 instruction
->type
= ARM_BL
;
1848 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1849 * these are effectively 32-bit instructions even in Thumb1. For
1850 * disassembly, it's simplest to always use the Thumb2 decoder.
1852 * But some cores will evidently handle them as two instructions,
1853 * where exceptions may occur between the two. The ETMv3.2+ ID
1854 * register has a bit which exposes this behavior.
1857 snprintf(instruction
->text
, 128,
1858 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1859 address
, opcode
, mnemonic
, target_address
);
1861 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1862 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1867 static int evaluate_add_sub_thumb(uint16_t opcode
,
1868 uint32_t address
, struct arm_instruction
*instruction
)
1870 uint8_t Rd
= (opcode
>> 0) & 0x7;
1871 uint8_t Rn
= (opcode
>> 3) & 0x7;
1872 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1873 uint32_t opc
= opcode
& (1 << 9);
1874 uint32_t reg_imm
= opcode
& (1 << 10);
1879 instruction
->type
= ARM_SUB
;
1884 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1885 instruction
->type
= ARM_ADD
;
1889 instruction
->info
.data_proc
.Rd
= Rd
;
1890 instruction
->info
.data_proc
.Rn
= Rn
;
1891 instruction
->info
.data_proc
.S
= 1;
1895 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1896 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1897 snprintf(instruction
->text
, 128,
1898 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1899 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1903 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1904 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1905 snprintf(instruction
->text
, 128,
1906 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1907 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1913 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1914 uint32_t address
, struct arm_instruction
*instruction
)
1916 uint8_t Rd
= (opcode
>> 0) & 0x7;
1917 uint8_t Rm
= (opcode
>> 3) & 0x7;
1918 uint8_t imm
= (opcode
>> 6) & 0x1f;
1919 uint8_t opc
= (opcode
>> 11) & 0x3;
1920 char *mnemonic
= NULL
;
1925 instruction
->type
= ARM_MOV
;
1927 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1930 instruction
->type
= ARM_MOV
;
1932 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1935 instruction
->type
= ARM_MOV
;
1937 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1941 if ((imm
== 0) && (opc
!= 0))
1944 instruction
->info
.data_proc
.Rd
= Rd
;
1945 instruction
->info
.data_proc
.Rn
= -1;
1946 instruction
->info
.data_proc
.S
= 1;
1948 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1949 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1950 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1952 snprintf(instruction
->text
, 128,
1953 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1954 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1959 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1960 uint32_t address
, struct arm_instruction
*instruction
)
1962 uint8_t imm
= opcode
& 0xff;
1963 uint8_t Rd
= (opcode
>> 8) & 0x7;
1964 uint32_t opc
= (opcode
>> 11) & 0x3;
1965 char *mnemonic
= NULL
;
1967 instruction
->info
.data_proc
.Rd
= Rd
;
1968 instruction
->info
.data_proc
.Rn
= Rd
;
1969 instruction
->info
.data_proc
.S
= 1;
1970 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1971 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1976 instruction
->type
= ARM_MOV
;
1978 instruction
->info
.data_proc
.Rn
= -1;
1981 instruction
->type
= ARM_CMP
;
1983 instruction
->info
.data_proc
.Rd
= -1;
1986 instruction
->type
= ARM_ADD
;
1990 instruction
->type
= ARM_SUB
;
1995 snprintf(instruction
->text
, 128,
1996 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1997 address
, opcode
, mnemonic
, Rd
, imm
);
2002 static int evaluate_data_proc_thumb(uint16_t opcode
,
2003 uint32_t address
, struct arm_instruction
*instruction
)
2005 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
2006 char *mnemonic
= NULL
;
2009 high_reg
= (opcode
& 0x0400) >> 10;
2010 op
= (opcode
& 0x03C0) >> 6;
2012 Rd
= (opcode
& 0x0007);
2013 Rm
= (opcode
& 0x0038) >> 3;
2014 H1
= (opcode
& 0x0080) >> 7;
2015 H2
= (opcode
& 0x0040) >> 6;
2017 instruction
->info
.data_proc
.Rd
= Rd
;
2018 instruction
->info
.data_proc
.Rn
= Rd
;
2019 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2020 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2021 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2032 instruction
->type
= ARM_ADD
;
2036 instruction
->type
= ARM_CMP
;
2040 instruction
->type
= ARM_MOV
;
2046 if ((opcode
& 0x7) == 0x0)
2048 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2051 instruction
->type
= ARM_BLX
;
2052 snprintf(instruction
->text
, 128,
2054 " 0x%4.4x \tBLX\tr%i",
2055 address
, opcode
, Rm
);
2059 instruction
->type
= ARM_BX
;
2060 snprintf(instruction
->text
, 128,
2062 " 0x%4.4x \tBX\tr%i",
2063 address
, opcode
, Rm
);
2068 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2069 snprintf(instruction
->text
, 128,
2072 "UNDEFINED INSTRUCTION",
2084 instruction
->type
= ARM_AND
;
2088 instruction
->type
= ARM_EOR
;
2092 instruction
->type
= ARM_MOV
;
2094 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2095 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2096 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2097 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2100 instruction
->type
= ARM_MOV
;
2102 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2103 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2104 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2105 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2108 instruction
->type
= ARM_MOV
;
2110 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2111 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2112 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2113 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2116 instruction
->type
= ARM_ADC
;
2120 instruction
->type
= ARM_SBC
;
2124 instruction
->type
= ARM_MOV
;
2126 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2127 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2128 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2129 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2132 instruction
->type
= ARM_TST
;
2136 instruction
->type
= ARM_RSB
;
2138 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2139 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2140 instruction
->info
.data_proc
.Rn
= Rm
;
2143 instruction
->type
= ARM_CMP
;
2147 instruction
->type
= ARM_CMN
;
2151 instruction
->type
= ARM_ORR
;
2155 instruction
->type
= ARM_MUL
;
2159 instruction
->type
= ARM_BIC
;
2163 instruction
->type
= ARM_MVN
;
2170 snprintf(instruction
->text
, 128,
2171 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2173 address
, opcode
, mnemonic
, Rd
, Rm
);
2175 snprintf(instruction
->text
, 128,
2176 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2177 address
, opcode
, mnemonic
, Rd
, Rm
);
2182 /* PC-relative data addressing is word-aligned even with Thumb */
2183 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2185 return (addr
+ 4) & ~3;
2188 static int evaluate_load_literal_thumb(uint16_t opcode
,
2189 uint32_t address
, struct arm_instruction
*instruction
)
2192 uint8_t Rd
= (opcode
>> 8) & 0x7;
2194 instruction
->type
= ARM_LDR
;
2195 immediate
= opcode
& 0x000000ff;
2198 instruction
->info
.load_store
.Rd
= Rd
;
2199 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2200 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2201 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2202 instruction
->info
.load_store
.offset
.offset
= immediate
;
2204 snprintf(instruction
->text
, 128,
2205 "0x%8.8" PRIx32
" 0x%4.4x \t"
2206 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2207 address
, opcode
, Rd
, immediate
,
2208 thumb_alignpc4(address
) + immediate
);
2213 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2214 uint32_t address
, struct arm_instruction
*instruction
)
2216 uint8_t Rd
= (opcode
>> 0) & 0x7;
2217 uint8_t Rn
= (opcode
>> 3) & 0x7;
2218 uint8_t Rm
= (opcode
>> 6) & 0x7;
2219 uint8_t opc
= (opcode
>> 9) & 0x7;
2220 char *mnemonic
= NULL
;
2225 instruction
->type
= ARM_STR
;
2229 instruction
->type
= ARM_STRH
;
2233 instruction
->type
= ARM_STRB
;
2237 instruction
->type
= ARM_LDRSB
;
2241 instruction
->type
= ARM_LDR
;
2245 instruction
->type
= ARM_LDRH
;
2249 instruction
->type
= ARM_LDRB
;
2253 instruction
->type
= ARM_LDRSH
;
2258 snprintf(instruction
->text
, 128,
2259 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2260 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2262 instruction
->info
.load_store
.Rd
= Rd
;
2263 instruction
->info
.load_store
.Rn
= Rn
;
2264 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2265 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2266 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2271 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2272 uint32_t address
, struct arm_instruction
*instruction
)
2274 uint32_t offset
= (opcode
>> 6) & 0x1f;
2275 uint8_t Rd
= (opcode
>> 0) & 0x7;
2276 uint8_t Rn
= (opcode
>> 3) & 0x7;
2277 uint32_t L
= opcode
& (1 << 11);
2278 uint32_t B
= opcode
& (1 << 12);
2285 instruction
->type
= ARM_LDR
;
2290 instruction
->type
= ARM_STR
;
2294 if ((opcode
&0xF000) == 0x8000)
2305 snprintf(instruction
->text
, 128,
2306 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2307 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2309 instruction
->info
.load_store
.Rd
= Rd
;
2310 instruction
->info
.load_store
.Rn
= Rn
;
2311 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2312 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2313 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2318 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2319 uint32_t address
, struct arm_instruction
*instruction
)
2321 uint32_t offset
= opcode
& 0xff;
2322 uint8_t Rd
= (opcode
>> 8) & 0x7;
2323 uint32_t L
= opcode
& (1 << 11);
2328 instruction
->type
= ARM_LDR
;
2333 instruction
->type
= ARM_STR
;
2337 snprintf(instruction
->text
, 128,
2338 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2339 address
, opcode
, mnemonic
, Rd
, offset
*4);
2341 instruction
->info
.load_store
.Rd
= Rd
;
2342 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2343 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2344 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2345 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2350 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2351 uint32_t address
, struct arm_instruction
*instruction
)
2353 uint32_t imm
= opcode
& 0xff;
2354 uint8_t Rd
= (opcode
>> 8) & 0x7;
2356 uint32_t SP
= opcode
& (1 << 11);
2357 const char *reg_name
;
2359 instruction
->type
= ARM_ADD
;
2372 snprintf(instruction
->text
, 128,
2373 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2374 address
, opcode
, Rd
, reg_name
, imm
* 4);
2376 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2377 instruction
->info
.data_proc
.Rd
= Rd
;
2378 instruction
->info
.data_proc
.Rn
= Rn
;
2379 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2384 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2385 uint32_t address
, struct arm_instruction
*instruction
)
2387 uint32_t imm
= opcode
& 0x7f;
2388 uint8_t opc
= opcode
& (1 << 7);
2394 instruction
->type
= ARM_SUB
;
2399 instruction
->type
= ARM_ADD
;
2403 snprintf(instruction
->text
, 128,
2404 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2405 address
, opcode
, mnemonic
, imm
*4);
2407 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2408 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2409 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2410 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2415 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2416 uint32_t address
, struct arm_instruction
*instruction
)
2418 uint32_t imm
= opcode
& 0xff;
2420 instruction
->type
= ARM_BKPT
;
2422 snprintf(instruction
->text
, 128,
2423 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2424 address
, opcode
, imm
);
2429 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2430 uint32_t address
, struct arm_instruction
*instruction
)
2432 uint32_t reg_list
= opcode
& 0xff;
2433 uint32_t L
= opcode
& (1 << 11);
2434 uint32_t R
= opcode
& (1 << 8);
2435 uint8_t Rn
= (opcode
>> 8) & 7;
2436 uint8_t addr_mode
= 0 /* IA */;
2440 char ptr_name
[7] = "";
2443 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2444 * The STMIA and LDMIA opcodes are used for other instructions.
2447 if ((opcode
& 0xf000) == 0xc000)
2448 { /* generic load/store multiple */
2453 instruction
->type
= ARM_LDM
;
2455 if (opcode
& (1 << Rn
))
2460 instruction
->type
= ARM_STM
;
2463 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2470 instruction
->type
= ARM_LDM
;
2473 reg_list
|= (1 << 15) /*PC*/;
2477 instruction
->type
= ARM_STM
;
2479 addr_mode
= 3; /*DB*/
2481 reg_list
|= (1 << 14) /*LR*/;
2485 reg_names_p
= reg_names
;
2486 for (i
= 0; i
<= 15; i
++)
2488 if (reg_list
& (1 << i
))
2489 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2491 if (reg_names_p
> reg_names
)
2492 reg_names_p
[-2] = '\0';
2493 else /* invalid op : no registers */
2494 reg_names
[0] = '\0';
2496 snprintf(instruction
->text
, 128,
2497 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2498 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2500 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2501 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2502 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2507 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2508 uint32_t address
, struct arm_instruction
*instruction
)
2510 uint32_t offset
= opcode
& 0xff;
2511 uint8_t cond
= (opcode
>> 8) & 0xf;
2512 uint32_t target_address
;
2516 instruction
->type
= ARM_SWI
;
2517 snprintf(instruction
->text
, 128,
2518 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2519 address
, opcode
, offset
);
2522 else if (cond
== 0xe)
2524 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2525 snprintf(instruction
->text
, 128,
2526 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2531 /* sign extend 8-bit offset */
2532 if (offset
& 0x00000080)
2533 offset
= 0xffffff00 | offset
;
2535 target_address
= address
+ 4 + (offset
<< 1);
2537 snprintf(instruction
->text
, 128,
2538 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2540 arm_condition_strings
[cond
], target_address
);
2542 instruction
->type
= ARM_B
;
2543 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2544 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2549 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2550 struct arm_instruction
*instruction
)
2554 /* added in Thumb2 */
2555 offset
= (opcode
>> 3) & 0x1f;
2556 offset
|= (opcode
& 0x0200) >> 4;
2558 snprintf(instruction
->text
, 128,
2559 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2561 (opcode
& 0x0800) ? "N" : "",
2562 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2567 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2568 struct arm_instruction
*instruction
)
2570 /* added in ARMv6 */
2571 snprintf(instruction
->text
, 128,
2572 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2574 (opcode
& 0x0080) ? 'U' : 'S',
2575 (opcode
& 0x0040) ? 'B' : 'H',
2576 opcode
& 0x7, (opcode
>> 3) & 0x7);
2581 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2582 struct arm_instruction
*instruction
)
2584 /* added in ARMv6 */
2585 if ((opcode
& 0x0ff0) == 0x0650)
2586 snprintf(instruction
->text
, 128,
2587 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2589 (opcode
& 0x80) ? "BE" : "LE");
2590 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2591 snprintf(instruction
->text
, 128,
2592 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2594 (opcode
& 0x0010) ? 'D' : 'E',
2595 (opcode
& 0x0004) ? "A" : "",
2596 (opcode
& 0x0002) ? "I" : "",
2597 (opcode
& 0x0001) ? "F" : "");
2602 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2603 struct arm_instruction
*instruction
)
2607 /* added in ARMv6 */
2608 switch ((opcode
>> 6) & 3) {
2619 snprintf(instruction
->text
, 128,
2620 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2621 address
, opcode
, suffix
,
2622 opcode
& 0x7, (opcode
>> 3) & 0x7);
2627 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2628 struct arm_instruction
*instruction
)
2632 switch ((opcode
>> 4) & 0x0f) {
2649 hint
= "HINT (UNRECOGNIZED)";
2653 snprintf(instruction
->text
, 128,
2654 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2655 address
, opcode
, hint
);
2660 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2661 struct arm_instruction
*instruction
)
2663 unsigned cond
= (opcode
>> 4) & 0x0f;
2664 char *x
= "", *y
= "", *z
= "";
2667 z
= (opcode
& 0x02) ? "T" : "E";
2669 y
= (opcode
& 0x04) ? "T" : "E";
2671 x
= (opcode
& 0x08) ? "T" : "E";
2673 snprintf(instruction
->text
, 128,
2674 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2676 x
, y
, z
, arm_condition_strings
[cond
]);
2678 /* NOTE: strictly speaking, the next 1-4 instructions should
2679 * now be displayed with the relevant conditional suffix...
2685 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2687 /* clear fields, to avoid confusion */
2688 memset(instruction
, 0, sizeof(struct arm_instruction
));
2689 instruction
->opcode
= opcode
;
2690 instruction
->instruction_size
= 2;
2692 if ((opcode
& 0xe000) == 0x0000)
2694 /* add/substract register or immediate */
2695 if ((opcode
& 0x1800) == 0x1800)
2696 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2697 /* shift by immediate */
2699 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2702 /* Add/substract/compare/move immediate */
2703 if ((opcode
& 0xe000) == 0x2000)
2705 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2708 /* Data processing instructions */
2709 if ((opcode
& 0xf800) == 0x4000)
2711 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2714 /* Load from literal pool */
2715 if ((opcode
& 0xf800) == 0x4800)
2717 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2720 /* Load/Store register offset */
2721 if ((opcode
& 0xf000) == 0x5000)
2723 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2726 /* Load/Store immediate offset */
2727 if (((opcode
& 0xe000) == 0x6000)
2728 ||((opcode
& 0xf000) == 0x8000))
2730 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2733 /* Load/Store from/to stack */
2734 if ((opcode
& 0xf000) == 0x9000)
2736 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2740 if ((opcode
& 0xf000) == 0xa000)
2742 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2746 if ((opcode
& 0xf000) == 0xb000)
2748 switch ((opcode
>> 8) & 0x0f) {
2750 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2755 return evaluate_cb_thumb(opcode
, address
, instruction
);
2757 return evaluate_extend_thumb(opcode
, address
, instruction
);
2762 return evaluate_load_store_multiple_thumb(opcode
, address
,
2765 return evaluate_cps_thumb(opcode
, address
, instruction
);
2767 if ((opcode
& 0x00c0) == 0x0080)
2769 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2771 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2773 if (opcode
& 0x000f)
2774 return evaluate_ifthen_thumb(opcode
, address
,
2777 return evaluate_hint_thumb(opcode
, address
,
2781 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2782 snprintf(instruction
->text
, 128,
2783 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2788 /* Load/Store multiple */
2789 if ((opcode
& 0xf000) == 0xc000)
2791 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2794 /* Conditional branch + SWI */
2795 if ((opcode
& 0xf000) == 0xd000)
2797 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2800 if ((opcode
& 0xe000) == 0xe000)
2802 /* Undefined instructions */
2803 if ((opcode
& 0xf801) == 0xe801)
2805 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2806 snprintf(instruction
->text
, 128,
2807 "0x%8.8" PRIx32
" 0x%8.8x\t"
2808 "UNDEFINED INSTRUCTION",
2813 { /* Branch to offset */
2814 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2818 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2822 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2823 struct arm_instruction
*instruction
, char *cp
)
2826 unsigned b21
= 1 << 21;
2827 unsigned b22
= 1 << 22;
2829 /* instead of combining two smaller 16-bit branch instructions,
2830 * Thumb2 uses only one larger 32-bit instruction.
2832 offset
= opcode
& 0x7ff;
2833 offset
|= (opcode
& 0x03ff0000) >> 5;
2834 if (opcode
& (1 << 26)) {
2835 offset
|= 0xff << 23;
2836 if ((opcode
& (1 << 11)) == 0)
2838 if ((opcode
& (1 << 13)) == 0)
2841 if (opcode
& (1 << 11))
2843 if (opcode
& (1 << 13))
2851 address
+= offset
<< 1;
2853 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2854 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2855 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2856 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2857 (opcode
& (1 << 14)) ? "BL" : "B.W",
2863 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2864 struct arm_instruction
*instruction
, char *cp
)
2867 unsigned b17
= 1 << 17;
2868 unsigned b18
= 1 << 18;
2869 unsigned cond
= (opcode
>> 22) & 0x0f;
2871 offset
= opcode
& 0x7ff;
2872 offset
|= (opcode
& 0x003f0000) >> 5;
2873 if (opcode
& (1 << 26)) {
2874 offset
|= 0xffff << 19;
2875 if ((opcode
& (1 << 11)) == 0)
2877 if ((opcode
& (1 << 13)) == 0)
2880 if (opcode
& (1 << 11))
2882 if (opcode
& (1 << 13))
2889 address
+= offset
<< 1;
2891 instruction
->type
= ARM_B
;
2892 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2893 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2894 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2895 arm_condition_strings
[cond
],
2901 static const char *special_name(int number
)
2903 char *special
= "(RESERVED)";
2934 special
= "primask";
2937 special
= "basepri";
2940 special
= "basepri_max";
2943 special
= "faultmask";
2946 special
= "control";
2952 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2953 struct arm_instruction
*instruction
, char *cp
)
2955 const char *mnemonic
;
2957 if (opcode
& 0x0700) {
2958 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2959 strcpy(cp
, "UNDEFINED");
2963 if (opcode
& 0x00f0) {
2964 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2968 switch (opcode
& 0x0f) {
2973 mnemonic
= "YIELD.W";
2985 mnemonic
= "HINT.W (UNRECOGNIZED)";
2988 strcpy(cp
, mnemonic
);
2992 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2993 struct arm_instruction
*instruction
, char *cp
)
2995 const char *mnemonic
;
2997 switch ((opcode
>> 4) & 0x0f) {
2999 mnemonic
= "LEAVEX";
3002 mnemonic
= "ENTERX";
3017 return ERROR_INVALID_ARGUMENTS
;
3019 strcpy(cp
, mnemonic
);
3023 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3024 struct arm_instruction
*instruction
, char *cp
)
3026 /* permanently undefined */
3027 if ((opcode
& 0x07f07000) == 0x07f02000) {
3028 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3029 strcpy(cp
, "UNDEFINED");
3033 switch ((opcode
>> 12) & 0x5) {
3036 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3040 if (((opcode
>> 23) & 0x07) != 0x07)
3041 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3042 if (opcode
& (1 << 26))
3047 switch ((opcode
>> 20) & 0x7f) {
3050 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3051 (int) (opcode
>> 16) & 0x0f);
3054 return t2ev_hint(opcode
, address
, instruction
, cp
);
3056 return t2ev_misc(opcode
, address
, instruction
, cp
);
3058 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3062 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3063 special_name(opcode
& 0xff));
3068 return ERROR_INVALID_ARGUMENTS
;
3071 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3072 struct arm_instruction
*instruction
, char *cp
)
3074 char *mnemonic
= NULL
;
3075 int rn
= (opcode
>> 16) & 0xf;
3076 int rd
= (opcode
>> 8) & 0xf;
3077 unsigned immed
= opcode
& 0xff;
3083 /* ARMv7-M: A5.3.2 Modified immediate constants */
3084 func
= (opcode
>> 11) & 0x0e;
3087 if (opcode
& (1 << 26))
3090 /* "Modified" immediates */
3091 switch (func
>> 1) {
3098 immed
+= immed
<< 16;
3101 immed
+= immed
<< 8;
3102 immed
+= immed
<< 16;
3106 immed
= ror(immed
, func
);
3109 if (opcode
& (1 << 20))
3112 switch ((opcode
>> 21) & 0xf) {
3115 instruction
->type
= ARM_TST
;
3121 instruction
->type
= ARM_AND
;
3126 instruction
->type
= ARM_BIC
;
3131 instruction
->type
= ARM_MOV
;
3136 instruction
->type
= ARM_ORR
;
3142 instruction
->type
= ARM_MVN
;
3146 // instruction->type = ARM_ORN;
3152 instruction
->type
= ARM_TEQ
;
3158 instruction
->type
= ARM_EOR
;
3164 instruction
->type
= ARM_CMN
;
3170 instruction
->type
= ARM_ADD
;
3176 instruction
->type
= ARM_ADC
;
3181 instruction
->type
= ARM_SBC
;
3186 instruction
->type
= ARM_CMP
;
3192 instruction
->type
= ARM_SUB
;
3198 instruction
->type
= ARM_RSB
;
3203 return ERROR_INVALID_ARGUMENTS
;
3207 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3208 mnemonic
, suffix2
,rd
, immed
, immed
);
3210 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3211 mnemonic
, suffix
, suffix2
,
3212 rd
, rn
, immed
, immed
);
3217 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3218 struct arm_instruction
*instruction
, char *cp
)
3220 char *mnemonic
= NULL
;
3221 int rn
= (opcode
>> 16) & 0xf;
3222 int rd
= (opcode
>> 8) & 0xf;
3225 bool is_signed
= false;
3227 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3228 if (opcode
& (1 << 26))
3231 switch ((opcode
>> 20) & 0x1f) {
3240 immed
|= (opcode
>> 4) & 0xf000;
3241 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3249 /* move constant to top 16 bits of register */
3250 immed
|= (opcode
>> 4) & 0xf000;
3251 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3258 /* signed/unsigned saturated add */
3259 immed
= (opcode
>> 6) & 0x03;
3260 immed
|= (opcode
>> 10) & 0x1c;
3261 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3262 is_signed
? "S" : "U",
3263 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3264 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3265 immed
? immed
: 32);
3271 /* signed/unsigned bitfield extract */
3272 immed
= (opcode
>> 6) & 0x03;
3273 immed
|= (opcode
>> 10) & 0x1c;
3274 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3275 is_signed
? "S" : "U",
3277 (int) (opcode
& 0x1f) + 1);
3280 immed
= (opcode
>> 6) & 0x03;
3281 immed
|= (opcode
>> 10) & 0x1c;
3282 if (rn
== 0xf) /* bitfield clear */
3283 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3285 (int) (opcode
& 0x1f) + 1 - immed
);
3286 else /* bitfield insert */
3287 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3289 (int) (opcode
& 0x1f) + 1 - immed
);
3292 return ERROR_INVALID_ARGUMENTS
;
3295 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3296 rd
, rn
, immed
, immed
);
3300 address
= thumb_alignpc4(address
);
3305 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3306 * not hiding the pc-relative stuff will sometimes be useful.
3308 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3312 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3313 struct arm_instruction
*instruction
, char *cp
)
3315 unsigned op
= (opcode
>> 20) & 0xf;
3321 unsigned rn
= (opcode
>> 16) & 0x0f;
3322 unsigned rt
= (opcode
>> 12) & 0x0f;
3325 return ERROR_INVALID_ARGUMENTS
;
3327 if (opcode
& 0x0800)
3362 return ERROR_INVALID_ARGUMENTS
;
3365 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3366 size
, rt
, rn
, (int) opcode
& 0x0f,
3367 (int) (opcode
>> 4) & 0x03);
3371 immed
= opcode
& 0x0fff;
3372 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3373 size
, rt
, rn
, immed
, immed
);
3377 immed
= opcode
& 0x00ff;
3379 switch (opcode
& 0x700) {
3385 return ERROR_INVALID_ARGUMENTS
;
3388 /* two indexed modes will write back rn */
3389 if (opcode
& 0x100) {
3390 if (opcode
& 0x400) /* pre-indexed */
3392 else { /* post-indexed */
3398 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3399 size
, suffix
, rt
, rn
, p1
,
3400 (opcode
& 0x200) ? "" : "-",
3405 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3406 struct arm_instruction
*instruction
, char *cp
)
3408 int ra
= (opcode
>> 12) & 0xf;
3410 switch (opcode
& 0x007000f0) {
3413 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3414 (int) (opcode
>> 8) & 0xf,
3415 (int) (opcode
>> 16) & 0xf,
3416 (int) (opcode
>> 0) & 0xf);
3418 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3419 (int) (opcode
>> 8) & 0xf,
3420 (int) (opcode
>> 16) & 0xf,
3421 (int) (opcode
>> 0) & 0xf, ra
);
3424 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3425 (int) (opcode
>> 8) & 0xf,
3426 (int) (opcode
>> 16) & 0xf,
3427 (int) (opcode
>> 0) & 0xf, ra
);
3430 return ERROR_INVALID_ARGUMENTS
;
3435 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3436 struct arm_instruction
*instruction
, char *cp
)
3438 int op
= (opcode
>> 4) & 0xf;
3439 char *infix
= "MUL";
3441 op
+= (opcode
>> 16) & 0x70;
3449 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3450 (op
& 0x20) ? 'U' : 'S',
3452 (int) (opcode
>> 12) & 0xf,
3453 (int) (opcode
>> 8) & 0xf,
3454 (int) (opcode
>> 16) & 0xf,
3455 (int) (opcode
>> 0) & 0xf);
3459 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3460 (op
& 0x20) ? 'U' : 'S',
3461 (int) (opcode
>> 8) & 0xf,
3462 (int) (opcode
>> 16) & 0xf,
3463 (int) (opcode
>> 0) & 0xf);
3466 return ERROR_INVALID_ARGUMENTS
;
3472 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3473 struct arm_instruction
*instruction
, char *cp
)
3475 int rn
= (opcode
>> 16) & 0xf;
3476 int op
= (opcode
>> 22) & 0x6;
3477 int t
= (opcode
>> 21) & 1;
3478 unsigned registers
= opcode
& 0xffff;
3481 if (opcode
& (1 << 20))
3489 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3491 (unsigned) (opcode
& 0x1f));
3497 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3498 (unsigned) ((opcode
>> 16) & 0xf),
3502 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3506 sprintf(cp
, "POP.W\t");
3508 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3512 sprintf(cp
, "PUSH.W\t");
3514 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3517 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3520 return ERROR_INVALID_ARGUMENTS
;
3525 for (t
= 0; registers
; t
++, registers
>>= 1) {
3526 if ((registers
& 1) == 0)
3529 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3538 /* load/store dual or exclusive, table branch */
3539 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3540 struct arm_instruction
*instruction
, char *cp
)
3542 unsigned op1op2
= (opcode
>> 20) & 0x3;
3543 unsigned op3
= (opcode
>> 4) & 0xf;
3545 unsigned rn
= (opcode
>> 16) & 0xf;
3546 unsigned rt
= (opcode
>> 12) & 0xf;
3547 unsigned rd
= (opcode
>> 8) & 0xf;
3548 unsigned imm
= opcode
& 0xff;
3552 op1op2
|= (opcode
>> 21) & 0xc;
3582 mnemonic
= "STREXB";
3585 mnemonic
= "STREXH";
3588 return ERROR_INVALID_ARGUMENTS
;
3596 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3599 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3602 mnemonic
= "LDREXB";
3605 mnemonic
= "LDREXH";
3608 return ERROR_INVALID_ARGUMENTS
;
3613 return ERROR_INVALID_ARGUMENTS
;
3618 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3619 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3621 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3622 mnemonic
, rd
, rt
, rn
);
3628 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3629 mnemonic
, rt
, rn
, imm
, imm
);
3631 sprintf(cp
, "%s\tr%u, [r%u]",
3636 /* two indexed modes will write back rn */
3637 if (opcode
& (1 << 21)) {
3638 if (opcode
& (1 << 24)) /* pre-indexed */
3640 else { /* post-indexed */
3647 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3648 mnemonic
, rt
, rd
, rn
, p1
,
3649 (opcode
& (1 << 23)) ? "" : "-",
3654 address
= thumb_alignpc4(address
);
3656 if (opcode
& (1 << 23))
3660 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3661 mnemonic
, rt
, rd
, address
);
3665 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3666 struct arm_instruction
*instruction
, char *cp
)
3668 int op
= (opcode
>> 21) & 0xf;
3669 int rd
= (opcode
>> 8) & 0xf;
3670 int rn
= (opcode
>> 16) & 0xf;
3671 int type
= (opcode
>> 4) & 0x3;
3672 int immed
= (opcode
>> 6) & 0x3;
3676 immed
|= (opcode
>> 10) & 0x1c;
3677 if (opcode
& (1 << 20))
3683 if (!(opcode
& (1 << 20)))
3684 return ERROR_INVALID_ARGUMENTS
;
3685 instruction
->type
= ARM_TST
;
3690 instruction
->type
= ARM_AND
;
3694 instruction
->type
= ARM_BIC
;
3699 instruction
->type
= ARM_MOV
;
3703 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3705 (int) (opcode
& 0xf));
3718 sprintf(cp
, "RRX%s\tr%d, r%d",
3720 (int) (opcode
& 0xf));
3728 instruction
->type
= ARM_ORR
;
3734 instruction
->type
= ARM_MVN
;
3739 // instruction->type = ARM_ORN;
3745 if (!(opcode
& (1 << 20)))
3746 return ERROR_INVALID_ARGUMENTS
;
3747 instruction
->type
= ARM_TEQ
;
3752 instruction
->type
= ARM_EOR
;
3757 if (!(opcode
& (1 << 20)))
3758 return ERROR_INVALID_ARGUMENTS
;
3759 instruction
->type
= ARM_CMN
;
3764 instruction
->type
= ARM_ADD
;
3768 instruction
->type
= ARM_ADC
;
3772 instruction
->type
= ARM_SBC
;
3777 if (!(opcode
& (1 << 21)))
3778 return ERROR_INVALID_ARGUMENTS
;
3779 instruction
->type
= ARM_CMP
;
3784 instruction
->type
= ARM_SUB
;
3788 instruction
->type
= ARM_RSB
;
3792 return ERROR_INVALID_ARGUMENTS
;
3795 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3796 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3819 strcpy(cp
, ", RRX");
3825 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3829 sprintf(cp
, "%s%s.W\tr%d, r%d",
3830 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3834 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3835 mnemonic
, suffix
, rd
,
3836 (int) (opcode
& 0xf), immed
? immed
: 32);
3840 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3841 struct arm_instruction
*instruction
, char *cp
)
3846 if (((opcode
>> 4) & 0xf) == 0) {
3847 switch ((opcode
>> 21) & 0x7) {
3861 return ERROR_INVALID_ARGUMENTS
;
3864 instruction
->type
= ARM_MOV
;
3865 if (opcode
& (1 << 20))
3867 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3869 (int) (opcode
>> 8) & 0xf,
3870 (int) (opcode
>> 16) & 0xf,
3871 (int) (opcode
>> 0) & 0xf);
3873 } else if (opcode
& (1 << 7)) {
3874 switch ((opcode
>> 20) & 0xf) {
3879 switch ((opcode
>> 4) & 0x3) {
3881 suffix
= ", ROR #8";
3884 suffix
= ", ROR #16";
3887 suffix
= ", ROR #24";
3890 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3891 (opcode
& (1 << 24)) ? 'U' : 'S',
3892 (opcode
& (1 << 26)) ? 'B' : 'H',
3893 (int) (opcode
>> 8) & 0xf,
3894 (int) (opcode
>> 0) & 0xf,
3901 if (opcode
& (1 << 6))
3902 return ERROR_INVALID_ARGUMENTS
;
3903 if (((opcode
>> 12) & 0xf) != 0xf)
3904 return ERROR_INVALID_ARGUMENTS
;
3905 if (!(opcode
& (1 << 20)))
3906 return ERROR_INVALID_ARGUMENTS
;
3908 switch (((opcode
>> 19) & 0x04)
3909 | ((opcode
>> 4) & 0x3)) {
3914 mnemonic
= "REV16.W";
3920 mnemonic
= "REVSH.W";
3926 return ERROR_INVALID_ARGUMENTS
;
3928 sprintf(cp
, "%s\tr%d, r%d",
3930 (int) (opcode
>> 8) & 0xf,
3931 (int) (opcode
>> 0) & 0xf);
3934 return ERROR_INVALID_ARGUMENTS
;
3941 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3942 struct arm_instruction
*instruction
, char *cp
)
3944 int rn
= (opcode
>> 16) & 0xf;
3947 instruction
->type
= ARM_LDR
;
3950 immed
= opcode
& 0x0fff;
3951 if ((opcode
& (1 << 23)) == 0)
3953 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3954 (int) (opcode
>> 12) & 0xf,
3955 thumb_alignpc4(address
) + immed
);
3959 if (opcode
& (1 << 23)) {
3960 immed
= opcode
& 0x0fff;
3961 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3962 (int) (opcode
>> 12) & 0xf,
3967 if (!(opcode
& (0x3f << 6))) {
3968 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3969 (int) (opcode
>> 12) & 0xf,
3971 (int) (opcode
>> 0) & 0xf,
3972 (int) (opcode
>> 4) & 0x3);
3977 if (((opcode
>> 8) & 0xf) == 0xe) {
3978 immed
= opcode
& 0x00ff;
3980 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3981 (int) (opcode
>> 12) & 0xf,
3986 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3987 char *p1
= "]", *p2
= "";
3989 if (!(opcode
& 0x0500))
3990 return ERROR_INVALID_ARGUMENTS
;
3992 immed
= opcode
& 0x00ff;
3994 /* two indexed modes will write back rn */
3995 if (opcode
& 0x100) {
3996 if (opcode
& 0x400) /* pre-indexed */
3998 else { /* post-indexed */
4004 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4005 (int) (opcode
>> 12) & 0xf,
4007 (opcode
& 0x200) ? "" : "-",
4012 return ERROR_INVALID_ARGUMENTS
;
4015 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4016 struct arm_instruction
*instruction
, char *cp
)
4018 int rn
= (opcode
>> 16) & 0xf;
4019 int rt
= (opcode
>> 12) & 0xf;
4020 int op2
= (opcode
>> 6) & 0x3f;
4022 char *p1
= "", *p2
= "]";
4025 switch ((opcode
>> 23) & 0x3) {
4027 if ((rn
& rt
) == 0xf) {
4029 immed
= opcode
& 0xfff;
4030 address
= thumb_alignpc4(address
);
4031 if (opcode
& (1 << 23))
4035 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4039 if (rn
== 0x0f && rt
!= 0x0f) {
4041 immed
= opcode
& 0xfff;
4042 address
= thumb_alignpc4(address
);
4043 if (opcode
& (1 << 23))
4047 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4053 if ((op2
& 0x3c) == 0x38) {
4054 immed
= opcode
& 0xff;
4055 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4056 rt
, rn
, immed
, immed
);
4059 if ((op2
& 0x3c) == 0x30) {
4061 immed
= opcode
& 0xff;
4064 p1
= (opcode
& (1 << 21)) ? "W" : "";
4065 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4066 p1
, rn
, immed
, immed
);
4071 immed
= opcode
& 0xff;
4072 if (!(opcode
& 0x200))
4075 /* two indexed modes will write back rn */
4076 if (opcode
& 0x100) {
4077 if (opcode
& 0x400) /* pre-indexed */
4079 else { /* post-indexed */
4085 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4086 mnemonic
, rt
, rn
, p1
,
4090 if ((op2
& 0x24) == 0x24) {
4092 goto ldrxb_immediate_t3
;
4095 int rm
= opcode
& 0xf;
4098 sprintf(cp
, "PLD\t");
4100 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4101 immed
= (opcode
>> 4) & 0x3;
4103 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4108 if ((rn
& rt
) == 0xf)
4111 immed
= opcode
& 0xfff;
4112 goto preload_immediate
;
4116 mnemonic
= "LDRB.W";
4117 immed
= opcode
& 0xfff;
4118 goto ldrxb_immediate_t2
;
4120 if ((rn
& rt
) == 0xf) {
4121 immed
= opcode
& 0xfff;
4122 address
= thumb_alignpc4(address
);
4123 if (opcode
& (1 << 23))
4127 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4130 if (rn
== 0xf && rt
!= 0xf) {
4132 immed
= opcode
& 0xfff;
4133 address
= thumb_alignpc4(address
);
4134 if (opcode
& (1 << 23))
4138 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4143 if ((op2
& 0x3c) == 0x38) {
4144 immed
= opcode
& 0xff;
4145 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4146 rt
, rn
, immed
, immed
);
4149 if ((op2
& 0x3c) == 0x30) {
4151 immed
= opcode
& 0xff;
4152 immed
= -immed
; // pli
4153 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4158 goto ldrxb_immediate_t3
;
4160 if ((op2
& 0x24) == 0x24) {
4162 goto ldrxb_immediate_t3
;
4165 int rm
= opcode
& 0xf;
4168 sprintf(cp
, "PLI\t");
4170 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4171 immed
= (opcode
>> 4) & 0x3;
4173 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4179 immed
= opcode
& 0xfff;
4180 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4186 immed
= opcode
& 0xfff;
4188 goto ldrxb_immediate_t2
;
4191 return ERROR_INVALID_ARGUMENTS
;
4194 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4195 struct arm_instruction
*instruction
, char *cp
)
4197 int rn
= (opcode
>> 16) & 0xf;
4198 int rt
= (opcode
>> 12) & 0xf;
4199 int op2
= (opcode
>> 6) & 0x3f;
4204 sprintf(cp
, "HINT (UNALLOCATED)");
4208 if (opcode
& (1 << 24))
4211 if ((opcode
& (1 << 23)) == 0) {
4214 immed
= opcode
& 0xfff;
4215 address
= thumb_alignpc4(address
);
4216 if (opcode
& (1 << 23))
4220 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4225 int rm
= opcode
& 0xf;
4227 immed
= (opcode
>> 4) & 0x3;
4228 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4229 sign
, rt
, rn
, rm
, immed
);
4232 if ((op2
& 0x3c) == 0x38) {
4233 immed
= opcode
& 0xff;
4234 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4235 sign
, rt
, rn
, immed
, immed
);
4238 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4239 char *p1
= "", *p2
= "]";
4241 immed
= opcode
& 0xff;
4242 if (!(opcode
& 0x200))
4245 /* two indexed modes will write back rn */
4246 if (opcode
& 0x100) {
4247 if (opcode
& 0x400) /* pre-indexed */
4249 else { /* post-indexed */
4254 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4255 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4262 immed
= opcode
& 0xfff;
4263 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4264 sign
, *sign
? "" : ".W",
4265 rt
, rn
, immed
, immed
);
4269 return ERROR_INVALID_ARGUMENTS
;
4273 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4274 * always set. That means eventual arm_simulate_step() support for Thumb2
4275 * will need work in this area.
4277 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4284 /* clear low bit ... it's set on function pointers */
4287 /* clear fields, to avoid confusion */
4288 memset(instruction
, 0, sizeof(struct arm_instruction
));
4290 /* read first halfword, see if this is the only one */
4291 retval
= target_read_u16(target
, address
, &op
);
4292 if (retval
!= ERROR_OK
)
4295 switch (op
& 0xf800) {
4299 /* 32-bit instructions */
4300 instruction
->instruction_size
= 4;
4302 retval
= target_read_u16(target
, address
+ 2, &op
);
4303 if (retval
!= ERROR_OK
)
4306 instruction
->opcode
= opcode
;
4309 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4310 return thumb_evaluate_opcode(op
, address
, instruction
);
4313 snprintf(instruction
->text
, 128,
4314 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4316 cp
= strchr(instruction
->text
, 0);
4317 retval
= ERROR_FAIL
;
4319 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4320 if ((opcode
& 0x1a008000) == 0x10000000)
4321 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4323 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4324 else if ((opcode
& 0x1a008000) == 0x12000000)
4325 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4327 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4328 else if ((opcode
& 0x18008000) == 0x10008000)
4329 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4331 /* ARMv7-M: A5.3.5 Load/store multiple */
4332 else if ((opcode
& 0x1e400000) == 0x08000000)
4333 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4335 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4336 else if ((opcode
& 0x1e400000) == 0x08400000)
4337 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4339 /* ARMv7-M: A5.3.7 Load word */
4340 else if ((opcode
& 0x1f700000) == 0x18500000)
4341 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4343 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4344 else if ((opcode
& 0x1e700000) == 0x18300000)
4345 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4347 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4348 else if ((opcode
& 0x1e700000) == 0x18100000)
4349 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4351 /* ARMv7-M: A5.3.10 Store single data item */
4352 else if ((opcode
& 0x1f100000) == 0x18000000)
4353 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4355 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4356 else if ((opcode
& 0x1e000000) == 0x0a000000)
4357 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4359 /* ARMv7-M: A5.3.12 Data processing (register)
4360 * and A5.3.13 Miscellaneous operations
4362 else if ((opcode
& 0x1f000000) == 0x1a000000)
4363 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4365 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4366 else if ((opcode
& 0x1f800000) == 0x1b000000)
4367 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4369 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4370 else if ((opcode
& 0x1f800000) == 0x1b800000)
4371 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4373 if (retval
== ERROR_OK
)
4377 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4378 * instructions; not yet handled here.
4381 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4382 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4383 strcpy(cp
, "UNDEFINED OPCODE");
4387 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4390 strcpy(cp
, "(32-bit Thumb2 ...)");
4394 int arm_access_size(struct arm_instruction
*instruction
)
4396 if ((instruction
->type
== ARM_LDRB
)
4397 || (instruction
->type
== ARM_LDRBT
)
4398 || (instruction
->type
== ARM_LDRSB
)
4399 || (instruction
->type
== ARM_STRB
)
4400 || (instruction
->type
== ARM_STRBT
))
4404 else if ((instruction
->type
== ARM_LDRH
)
4405 || (instruction
->type
== ARM_LDRSH
)
4406 || (instruction
->type
== ARM_STRH
))
4410 else if ((instruction
->type
== ARM_LDR
)
4411 || (instruction
->type
== ARM_LDRT
)
4412 || (instruction
->type
== ARM_STR
)
4413 || (instruction
->type
== ARM_STRT
))
4417 else if ((instruction
->type
== ARM_LDRD
)
4418 || (instruction
->type
== ARM_STRD
))
4424 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)