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"
31 /* textual represenation of the condition field */
32 /* ALways (default) is ommitted (empty string) */
33 char *arm_condition_strings
[] =
35 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
38 /* make up for C's missing ROR */
39 uint32_t ror(uint32_t value
, int places
)
41 return (value
>> places
) | (value
<< (32 - places
));
44 int evaluate_pld(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
47 if ((opcode
& 0x0d70f0000) == 0x0550f000)
49 instruction
->type
= ARM_PLD
;
51 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
57 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
61 LOG_ERROR("should never reach this point");
65 int evaluate_swi(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
67 instruction
->type
= ARM_SWI
;
69 snprintf(instruction
->text
, 128,
70 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
71 address
, opcode
, (opcode
& 0xffffff));
76 int evaluate_blx_imm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
80 uint32_t target_address
;
82 instruction
->type
= ARM_BLX
;
83 immediate
= opcode
& 0x00ffffff;
85 /* sign extend 24-bit immediate */
86 if (immediate
& 0x00800000)
87 offset
= 0xff000000 | immediate
;
91 /* shift two bits left */
94 /* odd/event halfword */
95 if (opcode
& 0x01000000)
98 target_address
= address
+ 8 + offset
;
100 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
102 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
103 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
108 int evaluate_b_bl(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
113 uint32_t target_address
;
115 immediate
= opcode
& 0x00ffffff;
116 L
= (opcode
& 0x01000000) >> 24;
118 /* sign extend 24-bit immediate */
119 if (immediate
& 0x00800000)
120 offset
= 0xff000000 | immediate
;
124 /* shift two bits left */
127 target_address
= address
+ 8 + offset
;
130 instruction
->type
= ARM_BL
;
132 instruction
->type
= ARM_B
;
134 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
135 (L
) ? "L" : "", COND(opcode
), target_address
);
137 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
138 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
143 /* Coprocessor load/store and double register transfers */
144 /* both normal and extended instruction space (condition field b1111) */
145 int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
147 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
150 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
152 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
155 cp_opcode
= (opcode
& 0xf0) >> 4;
156 Rd
= (opcode
& 0xf000) >> 12;
157 Rn
= (opcode
& 0xf0000) >> 16;
158 CRm
= (opcode
& 0xf);
161 if ((opcode
& 0x0ff00000) == 0x0c400000)
163 instruction
->type
= ARM_MCRR
;
168 if ((opcode
& 0x0ff00000) == 0x0c500000)
170 instruction
->type
= ARM_MRRC
;
174 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
175 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
177 else /* LDC or STC */
179 uint8_t CRd
, Rn
, offset
;
182 char addressing_mode
[32];
184 CRd
= (opcode
& 0xf000) >> 12;
185 Rn
= (opcode
& 0xf0000) >> 16;
186 offset
= (opcode
& 0xff);
189 if (opcode
& 0x00100000)
191 instruction
->type
= ARM_LDC
;
196 instruction
->type
= ARM_STC
;
200 U
= (opcode
& 0x00800000) >> 23;
201 N
= (opcode
& 0x00400000) >> 22;
203 /* addressing modes */
204 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
205 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
206 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
207 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
208 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
209 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
210 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
211 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
213 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
214 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
216 cp_num
, CRd
, addressing_mode
);
222 /* Coprocessor data processing instructions */
223 /* Coprocessor register transfer instructions */
224 /* both normal and extended instruction space (condition field b1111) */
225 int evaluate_cdp_mcr_mrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
229 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
231 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
232 cp_num
= (opcode
& 0xf00) >> 8;
233 CRd_Rd
= (opcode
& 0xf000) >> 12;
234 CRn
= (opcode
& 0xf0000) >> 16;
235 CRm
= (opcode
& 0xf);
236 opcode_2
= (opcode
& 0xe0) >> 5;
239 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
241 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
243 instruction
->type
= ARM_MRC
;
246 else /* bit 20 not set -> MCR */
248 instruction
->type
= ARM_MCR
;
252 opcode_1
= (opcode
& 0x00e00000) >> 21;
254 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",
255 address
, opcode
, mnemonic
, cond
,
256 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
258 else /* bit 4 not set -> CDP */
260 instruction
->type
= ARM_CDP
;
263 opcode_1
= (opcode
& 0x00f00000) >> 20;
265 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",
266 address
, opcode
, mnemonic
, cond
,
267 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
273 /* Load/store instructions */
274 int evaluate_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
276 uint8_t I
, P
, U
, B
, W
, L
;
278 char *operation
; /* "LDR" or "STR" */
279 char *suffix
; /* "", "B", "T", "BT" */
283 I
= (opcode
& 0x02000000) >> 25;
284 P
= (opcode
& 0x01000000) >> 24;
285 U
= (opcode
& 0x00800000) >> 23;
286 B
= (opcode
& 0x00400000) >> 22;
287 W
= (opcode
& 0x00200000) >> 21;
288 L
= (opcode
& 0x00100000) >> 20;
290 /* target register */
291 Rd
= (opcode
& 0xf000) >> 12;
294 Rn
= (opcode
& 0xf0000) >> 16;
296 instruction
->info
.load_store
.Rd
= Rd
;
297 instruction
->info
.load_store
.Rn
= Rn
;
298 instruction
->info
.load_store
.U
= U
;
300 /* determine operation */
306 /* determine instruction type and suffix */
309 if ((P
== 0) && (W
== 1))
312 instruction
->type
= ARM_LDRBT
;
314 instruction
->type
= ARM_STRBT
;
320 instruction
->type
= ARM_LDRB
;
322 instruction
->type
= ARM_STRB
;
328 if ((P
== 0) && (W
== 1))
331 instruction
->type
= ARM_LDRT
;
333 instruction
->type
= ARM_STRT
;
339 instruction
->type
= ARM_LDR
;
341 instruction
->type
= ARM_STR
;
346 if (!I
) /* #+-<offset_12> */
348 uint32_t offset_12
= (opcode
& 0xfff);
350 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
352 snprintf(offset
, 32, "%s", "");
354 instruction
->info
.load_store
.offset_mode
= 0;
355 instruction
->info
.load_store
.offset
.offset
= offset_12
;
357 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
359 uint8_t shift_imm
, shift
;
362 shift_imm
= (opcode
& 0xf80) >> 7;
363 shift
= (opcode
& 0x60) >> 5;
366 /* LSR encodes a shift by 32 bit as 0x0 */
367 if ((shift
== 0x1) && (shift_imm
== 0x0))
370 /* ASR encodes a shift by 32 bit as 0x0 */
371 if ((shift
== 0x2) && (shift_imm
== 0x0))
374 /* ROR by 32 bit is actually a RRX */
375 if ((shift
== 0x3) && (shift_imm
== 0x0))
378 instruction
->info
.load_store
.offset_mode
= 1;
379 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
380 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
381 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
383 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
385 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
387 else /* +-<Rm>, <Shift>, #<shift_imm> */
392 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
395 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
398 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
401 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
404 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
412 if (W
== 0) /* offset */
414 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
415 address
, opcode
, operation
, COND(opcode
), suffix
,
418 instruction
->info
.load_store
.index_mode
= 0;
420 else /* pre-indexed */
422 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
423 address
, opcode
, operation
, COND(opcode
), suffix
,
426 instruction
->info
.load_store
.index_mode
= 1;
429 else /* post-indexed */
431 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
432 address
, opcode
, operation
, COND(opcode
), suffix
,
435 instruction
->info
.load_store
.index_mode
= 2;
441 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
443 unsigned rm
= (opcode
>> 0) & 0xf;
444 unsigned rd
= (opcode
>> 12) & 0xf;
445 unsigned rn
= (opcode
>> 16) & 0xf;
448 /* GCC 'uninitialized warning removal' */
451 switch ((opcode
>> 24) & 0x3) {
456 sprintf(cp
, "UNDEFINED");
457 return ARM_UNDEFINED_INSTRUCTION
;
466 switch ((opcode
>> 10) & 0x3) {
482 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
483 (opcode
& (1 << 22)) ? 'U' : 'S',
488 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
489 (opcode
& (1 << 22)) ? 'U' : 'S',
496 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
502 switch ((opcode
>> 20) & 0x7) {
525 switch ((opcode
>> 5) & 0x7) {
554 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
555 (int) (opcode
>> 12) & 0xf,
556 (int) (opcode
>> 16) & 0xf,
557 (int) (opcode
>> 0) & 0xf);
561 /* these opcodes might be used someday */
562 sprintf(cp
, "UNDEFINED");
563 return ARM_UNDEFINED_INSTRUCTION
;
566 /* ARMv6 and later support "media" instructions (includes SIMD) */
567 static int evaluate_media(uint32_t opcode
, uint32_t address
,
568 arm_instruction_t
*instruction
)
570 char *cp
= instruction
->text
;
571 char *mnemonic
= NULL
;
574 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
578 /* parallel add/subtract */
579 if ((opcode
& 0x01800000) == 0x00000000) {
580 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
585 if ((opcode
& 0x01f00020) == 0x00800000) {
587 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
589 if (opcode
& (1 << 6)) {
598 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
600 (int) (opcode
>> 12) & 0xf,
601 (int) (opcode
>> 16) & 0xf,
602 (int) (opcode
>> 0) & 0xf,
608 if ((opcode
& 0x01a00020) == 0x00a00000) {
610 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
612 if (opcode
& (1 << 6)) {
620 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
621 (opcode
& (1 << 22)) ? 'U' : 'S',
623 (int) (opcode
>> 12) & 0xf,
624 (int) (opcode
>> 16) & 0x1f,
625 (int) (opcode
>> 0) & 0xf,
631 if ((opcode
& 0x018000f0) == 0x00800070) {
632 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
637 if ((opcode
& 0x01f00080) == 0x01000000) {
638 unsigned rn
= (opcode
>> 12) & 0xf;
641 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
642 (opcode
& (1 << 6)) ? 'S' : 'A',
643 (opcode
& (1 << 5)) ? "X" : "",
645 (int) (opcode
>> 16) & 0xf,
646 (int) (opcode
>> 0) & 0xf,
647 (int) (opcode
>> 8) & 0xf,
650 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
651 (opcode
& (1 << 6)) ? 'S' : 'A',
652 (opcode
& (1 << 5)) ? "X" : "",
654 (int) (opcode
>> 16) & 0xf,
655 (int) (opcode
>> 0) & 0xf,
656 (int) (opcode
>> 8) & 0xf);
659 if ((opcode
& 0x01f00000) == 0x01400000) {
660 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
661 (opcode
& (1 << 6)) ? 'S' : 'A',
662 (opcode
& (1 << 5)) ? "X" : "",
664 (int) (opcode
>> 12) & 0xf,
665 (int) (opcode
>> 16) & 0xf,
666 (int) (opcode
>> 0) & 0xf,
667 (int) (opcode
>> 8) & 0xf);
670 if ((opcode
& 0x01f00000) == 0x01500000) {
671 unsigned rn
= (opcode
>> 12) & 0xf;
673 switch (opcode
& 0xc0) {
685 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
686 (opcode
& (1 << 6)) ? 'S' : 'A',
687 (opcode
& (1 << 5)) ? "R" : "",
689 (int) (opcode
>> 16) & 0xf,
690 (int) (opcode
>> 0) & 0xf,
691 (int) (opcode
>> 8) & 0xf,
694 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
695 (opcode
& (1 << 5)) ? "R" : "",
697 (int) (opcode
>> 16) & 0xf,
698 (int) (opcode
>> 0) & 0xf,
699 (int) (opcode
>> 8) & 0xf);
704 /* simple matches against the remaining decode bits */
705 switch (opcode
& 0x01f000f0) {
708 /* parallel halfword saturate */
709 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
710 (opcode
& (1 << 22)) ? 'U' : 'S',
712 (int) (opcode
>> 12) & 0xf,
713 (int) (opcode
>> 16) & 0xf,
714 (int) (opcode
>> 0) & 0xf);
727 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
728 (int) (opcode
>> 12) & 0xf,
729 (int) (opcode
>> 16) & 0xf,
730 (int) (opcode
>> 0) & 0xf);
733 /* unsigned sum of absolute differences */
734 if (((opcode
>> 12) & 0xf) == 0xf)
735 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
736 (int) (opcode
>> 16) & 0xf,
737 (int) (opcode
>> 0) & 0xf,
738 (int) (opcode
>> 8) & 0xf);
740 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
741 (int) (opcode
>> 16) & 0xf,
742 (int) (opcode
>> 0) & 0xf,
743 (int) (opcode
>> 8) & 0xf,
744 (int) (opcode
>> 12) & 0xf);
748 unsigned rm
= (opcode
>> 0) & 0xf;
749 unsigned rd
= (opcode
>> 12) & 0xf;
751 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
756 /* these opcodes might be used someday */
757 sprintf(cp
, "UNDEFINED");
761 /* Miscellaneous load/store instructions */
762 int evaluate_misc_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
764 uint8_t P
, U
, I
, W
, L
, S
, H
;
766 char *operation
; /* "LDR" or "STR" */
767 char *suffix
; /* "H", "SB", "SH", "D" */
771 P
= (opcode
& 0x01000000) >> 24;
772 U
= (opcode
& 0x00800000) >> 23;
773 I
= (opcode
& 0x00400000) >> 22;
774 W
= (opcode
& 0x00200000) >> 21;
775 L
= (opcode
& 0x00100000) >> 20;
776 S
= (opcode
& 0x00000040) >> 6;
777 H
= (opcode
& 0x00000020) >> 5;
779 /* target register */
780 Rd
= (opcode
& 0xf000) >> 12;
783 Rn
= (opcode
& 0xf0000) >> 16;
785 instruction
->info
.load_store
.Rd
= Rd
;
786 instruction
->info
.load_store
.Rn
= Rn
;
787 instruction
->info
.load_store
.U
= U
;
789 /* determine instruction type and suffix */
797 instruction
->type
= ARM_LDRSH
;
803 instruction
->type
= ARM_LDRSB
;
807 else /* there are no signed stores, so this is used to encode double-register load/stores */
813 instruction
->type
= ARM_STRD
;
818 instruction
->type
= ARM_LDRD
;
828 instruction
->type
= ARM_LDRH
;
833 instruction
->type
= ARM_STRH
;
837 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
839 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
840 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
842 instruction
->info
.load_store
.offset_mode
= 0;
843 instruction
->info
.load_store
.offset
.offset
= offset_8
;
845 else /* Register offset/index (+-<Rm>) */
849 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
851 instruction
->info
.load_store
.offset_mode
= 1;
852 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
853 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
854 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
859 if (W
== 0) /* offset */
861 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
862 address
, opcode
, operation
, COND(opcode
), suffix
,
865 instruction
->info
.load_store
.index_mode
= 0;
867 else /* pre-indexed */
869 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
870 address
, opcode
, operation
, COND(opcode
), suffix
,
873 instruction
->info
.load_store
.index_mode
= 1;
876 else /* post-indexed */
878 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
879 address
, opcode
, operation
, COND(opcode
), suffix
,
882 instruction
->info
.load_store
.index_mode
= 2;
888 /* Load/store multiples instructions */
889 int evaluate_ldm_stm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
891 uint8_t P
, U
, S
, W
, L
, Rn
;
892 uint32_t register_list
;
893 char *addressing_mode
;
900 P
= (opcode
& 0x01000000) >> 24;
901 U
= (opcode
& 0x00800000) >> 23;
902 S
= (opcode
& 0x00400000) >> 22;
903 W
= (opcode
& 0x00200000) >> 21;
904 L
= (opcode
& 0x00100000) >> 20;
905 register_list
= (opcode
& 0xffff);
906 Rn
= (opcode
& 0xf0000) >> 16;
908 instruction
->info
.load_store_multiple
.Rn
= Rn
;
909 instruction
->info
.load_store_multiple
.register_list
= register_list
;
910 instruction
->info
.load_store_multiple
.S
= S
;
911 instruction
->info
.load_store_multiple
.W
= W
;
915 instruction
->type
= ARM_LDM
;
920 instruction
->type
= ARM_STM
;
928 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
929 addressing_mode
= "IB";
933 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
934 addressing_mode
= "DB";
941 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
942 /* "IA" is the default in UAL syntax */
943 addressing_mode
= "";
947 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
948 addressing_mode
= "DA";
952 reg_list_p
= reg_list
;
953 for (i
= 0; i
<= 15; i
++)
955 if ((register_list
>> i
) & 1)
960 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
964 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
969 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
970 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
971 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
976 /* Multiplies, extra load/stores */
977 int evaluate_mul_and_extra_ld_st(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
979 /* Multiply (accumulate) (long) and Swap/swap byte */
980 if ((opcode
& 0x000000f0) == 0x00000090)
982 /* Multiply (accumulate) */
983 if ((opcode
& 0x0f800000) == 0x00000000)
985 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
987 Rs
= (opcode
& 0xf00) >> 8;
988 Rn
= (opcode
& 0xf000) >> 12;
989 Rd
= (opcode
& 0xf0000) >> 16;
990 S
= (opcode
& 0x00100000) >> 20;
992 /* examine A bit (accumulate) */
993 if (opcode
& 0x00200000)
995 instruction
->type
= ARM_MLA
;
996 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
997 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1001 instruction
->type
= ARM_MUL
;
1002 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1003 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1009 /* Multiply (accumulate) long */
1010 if ((opcode
& 0x0f800000) == 0x00800000)
1012 char* mnemonic
= NULL
;
1013 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1015 Rs
= (opcode
& 0xf00) >> 8;
1016 RdHi
= (opcode
& 0xf000) >> 12;
1017 RdLow
= (opcode
& 0xf0000) >> 16;
1018 S
= (opcode
& 0x00100000) >> 20;
1020 switch ((opcode
& 0x00600000) >> 21)
1023 instruction
->type
= ARM_UMULL
;
1027 instruction
->type
= ARM_UMLAL
;
1031 instruction
->type
= ARM_SMULL
;
1035 instruction
->type
= ARM_SMLAL
;
1040 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1041 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1042 RdLow
, RdHi
, Rm
, Rs
);
1047 /* Swap/swap byte */
1048 if ((opcode
& 0x0f800000) == 0x01000000)
1052 Rd
= (opcode
& 0xf000) >> 12;
1053 Rn
= (opcode
& 0xf0000) >> 16;
1055 /* examine B flag */
1056 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1058 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1059 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1065 return evaluate_misc_load_store(opcode
, address
, instruction
);
1068 int evaluate_mrs_msr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1070 int R
= (opcode
& 0x00400000) >> 22;
1071 char *PSR
= (R
) ? "SPSR" : "CPSR";
1073 /* Move register to status register (MSR) */
1074 if (opcode
& 0x00200000)
1076 instruction
->type
= ARM_MSR
;
1078 /* immediate variant */
1079 if (opcode
& 0x02000000)
1081 uint8_t immediate
= (opcode
& 0xff);
1082 uint8_t rotate
= (opcode
& 0xf00);
1084 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1085 address
, opcode
, COND(opcode
), PSR
,
1086 (opcode
& 0x10000) ? "c" : "",
1087 (opcode
& 0x20000) ? "x" : "",
1088 (opcode
& 0x40000) ? "s" : "",
1089 (opcode
& 0x80000) ? "f" : "",
1090 ror(immediate
, (rotate
* 2))
1093 else /* register variant */
1095 uint8_t Rm
= opcode
& 0xf;
1096 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1097 address
, opcode
, COND(opcode
), PSR
,
1098 (opcode
& 0x10000) ? "c" : "",
1099 (opcode
& 0x20000) ? "x" : "",
1100 (opcode
& 0x40000) ? "s" : "",
1101 (opcode
& 0x80000) ? "f" : "",
1107 else /* Move status register to register (MRS) */
1111 instruction
->type
= ARM_MRS
;
1112 Rd
= (opcode
& 0x0000f000) >> 12;
1114 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1115 address
, opcode
, COND(opcode
), Rd
, PSR
);
1121 /* Miscellaneous instructions */
1122 int evaluate_misc_instr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1125 if ((opcode
& 0x000000f0) == 0x00000000)
1127 evaluate_mrs_msr(opcode
, address
, instruction
);
1131 if ((opcode
& 0x006000f0) == 0x00200010)
1134 instruction
->type
= ARM_BX
;
1137 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1138 address
, opcode
, COND(opcode
), Rm
);
1140 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1141 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1144 /* BXJ - "Jazelle" support (ARMv5-J) */
1145 if ((opcode
& 0x006000f0) == 0x00200020)
1148 instruction
->type
= ARM_BX
;
1151 snprintf(instruction
->text
, 128,
1152 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1153 address
, opcode
, COND(opcode
), Rm
);
1155 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1156 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1160 if ((opcode
& 0x006000f0) == 0x00600010)
1163 instruction
->type
= ARM_CLZ
;
1165 Rd
= (opcode
& 0xf000) >> 12;
1167 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1168 address
, opcode
, COND(opcode
), Rd
, Rm
);
1172 if ((opcode
& 0x006000f0) == 0x00200030)
1175 instruction
->type
= ARM_BLX
;
1178 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1179 address
, opcode
, COND(opcode
), Rm
);
1181 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1182 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1185 /* Enhanced DSP add/subtracts */
1186 if ((opcode
& 0x0000000f0) == 0x00000050)
1189 char *mnemonic
= NULL
;
1191 Rd
= (opcode
& 0xf000) >> 12;
1192 Rn
= (opcode
& 0xf0000) >> 16;
1194 switch ((opcode
& 0x00600000) >> 21)
1197 instruction
->type
= ARM_QADD
;
1201 instruction
->type
= ARM_QSUB
;
1205 instruction
->type
= ARM_QDADD
;
1209 instruction
->type
= ARM_QDSUB
;
1214 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1215 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1218 /* Software breakpoints */
1219 if ((opcode
& 0x0000000f0) == 0x00000070)
1222 instruction
->type
= ARM_BKPT
;
1223 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1225 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1226 address
, opcode
, immediate
);
1229 /* Enhanced DSP multiplies */
1230 if ((opcode
& 0x000000090) == 0x00000080)
1232 int x
= (opcode
& 0x20) >> 5;
1233 int y
= (opcode
& 0x40) >> 6;
1236 if ((opcode
& 0x00600000) == 0x00000000)
1238 uint8_t Rd
, Rm
, Rs
, Rn
;
1239 instruction
->type
= ARM_SMLAxy
;
1240 Rd
= (opcode
& 0xf0000) >> 16;
1241 Rm
= (opcode
& 0xf);
1242 Rs
= (opcode
& 0xf00) >> 8;
1243 Rn
= (opcode
& 0xf000) >> 12;
1245 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1246 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1251 if ((opcode
& 0x00600000) == 0x00400000)
1253 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1254 instruction
->type
= ARM_SMLAxy
;
1255 RdHi
= (opcode
& 0xf0000) >> 16;
1256 RdLow
= (opcode
& 0xf000) >> 12;
1257 Rm
= (opcode
& 0xf);
1258 Rs
= (opcode
& 0xf00) >> 8;
1260 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1261 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1262 RdLow
, RdHi
, Rm
, Rs
);
1266 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1268 uint8_t Rd
, Rm
, Rs
, Rn
;
1269 instruction
->type
= ARM_SMLAWy
;
1270 Rd
= (opcode
& 0xf0000) >> 16;
1271 Rm
= (opcode
& 0xf);
1272 Rs
= (opcode
& 0xf00) >> 8;
1273 Rn
= (opcode
& 0xf000) >> 12;
1275 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1276 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1281 if ((opcode
& 0x00600000) == 0x00300000)
1284 instruction
->type
= ARM_SMULxy
;
1285 Rd
= (opcode
& 0xf0000) >> 16;
1286 Rm
= (opcode
& 0xf);
1287 Rs
= (opcode
& 0xf00) >> 8;
1289 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1290 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1295 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1298 instruction
->type
= ARM_SMULWy
;
1299 Rd
= (opcode
& 0xf0000) >> 16;
1300 Rm
= (opcode
& 0xf);
1301 Rs
= (opcode
& 0xf00) >> 8;
1303 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1304 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1312 int evaluate_data_proc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1314 uint8_t I
, op
, S
, Rn
, Rd
;
1315 char *mnemonic
= NULL
;
1316 char shifter_operand
[32];
1318 I
= (opcode
& 0x02000000) >> 25;
1319 op
= (opcode
& 0x01e00000) >> 21;
1320 S
= (opcode
& 0x00100000) >> 20;
1322 Rd
= (opcode
& 0xf000) >> 12;
1323 Rn
= (opcode
& 0xf0000) >> 16;
1325 instruction
->info
.data_proc
.Rd
= Rd
;
1326 instruction
->info
.data_proc
.Rn
= Rn
;
1327 instruction
->info
.data_proc
.S
= S
;
1332 instruction
->type
= ARM_AND
;
1336 instruction
->type
= ARM_EOR
;
1340 instruction
->type
= ARM_SUB
;
1344 instruction
->type
= ARM_RSB
;
1348 instruction
->type
= ARM_ADD
;
1352 instruction
->type
= ARM_ADC
;
1356 instruction
->type
= ARM_SBC
;
1360 instruction
->type
= ARM_RSC
;
1364 instruction
->type
= ARM_TST
;
1368 instruction
->type
= ARM_TEQ
;
1372 instruction
->type
= ARM_CMP
;
1376 instruction
->type
= ARM_CMN
;
1380 instruction
->type
= ARM_ORR
;
1384 instruction
->type
= ARM_MOV
;
1388 instruction
->type
= ARM_BIC
;
1392 instruction
->type
= ARM_MVN
;
1397 if (I
) /* immediate shifter operand (#<immediate>)*/
1399 uint8_t immed_8
= opcode
& 0xff;
1400 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1403 immediate
= ror(immed_8
, rotate_imm
* 2);
1405 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1407 instruction
->info
.data_proc
.variant
= 0;
1408 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1410 else /* register-based shifter operand */
1413 shift
= (opcode
& 0x60) >> 5;
1414 Rm
= (opcode
& 0xf);
1416 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1419 shift_imm
= (opcode
& 0xf80) >> 7;
1421 instruction
->info
.data_proc
.variant
= 1;
1422 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1423 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1424 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1426 /* LSR encodes a shift by 32 bit as 0x0 */
1427 if ((shift
== 0x1) && (shift_imm
== 0x0))
1430 /* ASR encodes a shift by 32 bit as 0x0 */
1431 if ((shift
== 0x2) && (shift_imm
== 0x0))
1434 /* ROR by 32 bit is actually a RRX */
1435 if ((shift
== 0x3) && (shift_imm
== 0x0))
1438 if ((shift_imm
== 0x0) && (shift
== 0x0))
1440 snprintf(shifter_operand
, 32, "r%i", Rm
);
1444 if (shift
== 0x0) /* LSL */
1446 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1448 else if (shift
== 0x1) /* LSR */
1450 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1452 else if (shift
== 0x2) /* ASR */
1454 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1456 else if (shift
== 0x3) /* ROR */
1458 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1460 else if (shift
== 0x4) /* RRX */
1462 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1466 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1468 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1470 instruction
->info
.data_proc
.variant
= 2;
1471 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1472 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1473 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1475 if (shift
== 0x0) /* LSL */
1477 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1479 else if (shift
== 0x1) /* LSR */
1481 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1483 else if (shift
== 0x2) /* ASR */
1485 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1487 else if (shift
== 0x3) /* ROR */
1489 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1494 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1496 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1497 address
, opcode
, mnemonic
, COND(opcode
),
1498 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1500 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1502 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1503 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1505 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1506 address
, opcode
, mnemonic
, COND(opcode
),
1507 (S
) ? "S" : "", Rd
, shifter_operand
);
1509 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1511 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1512 address
, opcode
, mnemonic
, COND(opcode
),
1513 Rn
, shifter_operand
);
1519 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1521 /* clear fields, to avoid confusion */
1522 memset(instruction
, 0, sizeof(arm_instruction_t
));
1523 instruction
->opcode
= opcode
;
1524 instruction
->instruction_size
= 4;
1526 /* catch opcodes with condition field [31:28] = b1111 */
1527 if ((opcode
& 0xf0000000) == 0xf0000000)
1529 /* Undefined instruction (or ARMv5E cache preload PLD) */
1530 if ((opcode
& 0x08000000) == 0x00000000)
1531 return evaluate_pld(opcode
, address
, instruction
);
1533 /* Undefined instruction */
1534 if ((opcode
& 0x0e000000) == 0x08000000)
1536 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1537 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1541 /* Branch and branch with link and change to Thumb */
1542 if ((opcode
& 0x0e000000) == 0x0a000000)
1543 return evaluate_blx_imm(opcode
, address
, instruction
);
1545 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1546 /* Coprocessor load/store and double register transfers */
1547 if ((opcode
& 0x0e000000) == 0x0c000000)
1548 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1550 /* Coprocessor data processing */
1551 if ((opcode
& 0x0f000100) == 0x0c000000)
1552 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1554 /* Coprocessor register transfers */
1555 if ((opcode
& 0x0f000010) == 0x0c000010)
1556 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1558 /* Undefined instruction */
1559 if ((opcode
& 0x0f000000) == 0x0f000000)
1561 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1562 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1567 /* catch opcodes with [27:25] = b000 */
1568 if ((opcode
& 0x0e000000) == 0x00000000)
1570 /* Multiplies, extra load/stores */
1571 if ((opcode
& 0x00000090) == 0x00000090)
1572 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1574 /* Miscellaneous instructions */
1575 if ((opcode
& 0x0f900000) == 0x01000000)
1576 return evaluate_misc_instr(opcode
, address
, instruction
);
1578 return evaluate_data_proc(opcode
, address
, instruction
);
1581 /* catch opcodes with [27:25] = b001 */
1582 if ((opcode
& 0x0e000000) == 0x02000000)
1584 /* Undefined instruction */
1585 if ((opcode
& 0x0fb00000) == 0x03000000)
1587 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1588 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1592 /* Move immediate to status register */
1593 if ((opcode
& 0x0fb00000) == 0x03200000)
1594 return evaluate_mrs_msr(opcode
, address
, instruction
);
1596 return evaluate_data_proc(opcode
, address
, instruction
);
1600 /* catch opcodes with [27:25] = b010 */
1601 if ((opcode
& 0x0e000000) == 0x04000000)
1603 /* Load/store immediate offset */
1604 return evaluate_load_store(opcode
, address
, instruction
);
1607 /* catch opcodes with [27:25] = b011 */
1608 if ((opcode
& 0x0e000000) == 0x06000000)
1610 /* Load/store register offset */
1611 if ((opcode
& 0x00000010) == 0x00000000)
1612 return evaluate_load_store(opcode
, address
, instruction
);
1614 /* Architecturally Undefined instruction
1615 * ... don't expect these to ever be used
1617 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1619 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1620 snprintf(instruction
->text
, 128,
1621 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1626 /* "media" instructions */
1627 return evaluate_media(opcode
, address
, instruction
);
1630 /* catch opcodes with [27:25] = b100 */
1631 if ((opcode
& 0x0e000000) == 0x08000000)
1633 /* Load/store multiple */
1634 return evaluate_ldm_stm(opcode
, address
, instruction
);
1637 /* catch opcodes with [27:25] = b101 */
1638 if ((opcode
& 0x0e000000) == 0x0a000000)
1640 /* Branch and branch with link */
1641 return evaluate_b_bl(opcode
, address
, instruction
);
1644 /* catch opcodes with [27:25] = b110 */
1645 if ((opcode
& 0x0e000000) == 0x0a000000)
1647 /* Coprocessor load/store and double register transfers */
1648 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1651 /* catch opcodes with [27:25] = b111 */
1652 if ((opcode
& 0x0e000000) == 0x0e000000)
1654 /* Software interrupt */
1655 if ((opcode
& 0x0f000000) == 0x0f000000)
1656 return evaluate_swi(opcode
, address
, instruction
);
1658 /* Coprocessor data processing */
1659 if ((opcode
& 0x0f000010) == 0x0e000000)
1660 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1662 /* Coprocessor register transfers */
1663 if ((opcode
& 0x0f000010) == 0x0e000010)
1664 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1667 LOG_ERROR("should never reach this point");
1671 int evaluate_b_bl_blx_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1673 uint32_t offset
= opcode
& 0x7ff;
1674 uint32_t opc
= (opcode
>> 11) & 0x3;
1675 uint32_t target_address
;
1676 char *mnemonic
= NULL
;
1678 /* sign extend 11-bit offset */
1679 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1680 offset
= 0xfffff800 | offset
;
1682 target_address
= address
+ 4 + (offset
<< 1);
1686 /* unconditional branch */
1688 instruction
->type
= ARM_B
;
1693 instruction
->type
= ARM_BLX
;
1698 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1699 mnemonic
= "prefix";
1700 target_address
= offset
<< 12;
1704 instruction
->type
= ARM_BL
;
1709 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1710 * these are effectively 32-bit instructions even in Thumb1.
1711 * Might be simplest to always use the Thumb2 decoder.
1714 snprintf(instruction
->text
, 128,
1715 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1716 address
, opcode
, mnemonic
, target_address
);
1718 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1719 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1724 int evaluate_add_sub_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1726 uint8_t Rd
= (opcode
>> 0) & 0x7;
1727 uint8_t Rn
= (opcode
>> 3) & 0x7;
1728 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1729 uint32_t opc
= opcode
& (1 << 9);
1730 uint32_t reg_imm
= opcode
& (1 << 10);
1735 instruction
->type
= ARM_SUB
;
1740 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1741 instruction
->type
= ARM_ADD
;
1745 instruction
->info
.data_proc
.Rd
= Rd
;
1746 instruction
->info
.data_proc
.Rn
= Rn
;
1747 instruction
->info
.data_proc
.S
= 1;
1751 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1752 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1753 snprintf(instruction
->text
, 128,
1754 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1755 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1759 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1760 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1761 snprintf(instruction
->text
, 128,
1762 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1763 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1769 int evaluate_shift_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1771 uint8_t Rd
= (opcode
>> 0) & 0x7;
1772 uint8_t Rm
= (opcode
>> 3) & 0x7;
1773 uint8_t imm
= (opcode
>> 6) & 0x1f;
1774 uint8_t opc
= (opcode
>> 11) & 0x3;
1775 char *mnemonic
= NULL
;
1780 instruction
->type
= ARM_MOV
;
1782 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1785 instruction
->type
= ARM_MOV
;
1787 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1790 instruction
->type
= ARM_MOV
;
1792 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1796 if ((imm
== 0) && (opc
!= 0))
1799 instruction
->info
.data_proc
.Rd
= Rd
;
1800 instruction
->info
.data_proc
.Rn
= -1;
1801 instruction
->info
.data_proc
.S
= 1;
1803 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1804 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1805 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1807 snprintf(instruction
->text
, 128,
1808 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1809 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1814 int evaluate_data_proc_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1816 uint8_t imm
= opcode
& 0xff;
1817 uint8_t Rd
= (opcode
>> 8) & 0x7;
1818 uint32_t opc
= (opcode
>> 11) & 0x3;
1819 char *mnemonic
= NULL
;
1821 instruction
->info
.data_proc
.Rd
= Rd
;
1822 instruction
->info
.data_proc
.Rn
= Rd
;
1823 instruction
->info
.data_proc
.S
= 1;
1824 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1825 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1830 instruction
->type
= ARM_MOV
;
1832 instruction
->info
.data_proc
.Rn
= -1;
1835 instruction
->type
= ARM_CMP
;
1837 instruction
->info
.data_proc
.Rd
= -1;
1840 instruction
->type
= ARM_ADD
;
1844 instruction
->type
= ARM_SUB
;
1849 snprintf(instruction
->text
, 128,
1850 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1851 address
, opcode
, mnemonic
, Rd
, imm
);
1856 int evaluate_data_proc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1858 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1859 char *mnemonic
= NULL
;
1862 high_reg
= (opcode
& 0x0400) >> 10;
1863 op
= (opcode
& 0x03C0) >> 6;
1865 Rd
= (opcode
& 0x0007);
1866 Rm
= (opcode
& 0x0038) >> 3;
1867 H1
= (opcode
& 0x0080) >> 7;
1868 H2
= (opcode
& 0x0040) >> 6;
1870 instruction
->info
.data_proc
.Rd
= Rd
;
1871 instruction
->info
.data_proc
.Rn
= Rd
;
1872 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1873 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1874 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1885 instruction
->type
= ARM_ADD
;
1889 instruction
->type
= ARM_CMP
;
1893 instruction
->type
= ARM_MOV
;
1899 if ((opcode
& 0x7) == 0x0)
1901 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1904 instruction
->type
= ARM_BLX
;
1905 snprintf(instruction
->text
, 128,
1907 " 0x%4.4x \tBLX\tr%i",
1908 address
, opcode
, Rm
);
1912 instruction
->type
= ARM_BX
;
1913 snprintf(instruction
->text
, 128,
1915 " 0x%4.4x \tBX\tr%i",
1916 address
, opcode
, Rm
);
1921 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1922 snprintf(instruction
->text
, 128,
1925 "UNDEFINED INSTRUCTION",
1937 instruction
->type
= ARM_AND
;
1941 instruction
->type
= ARM_EOR
;
1945 instruction
->type
= ARM_MOV
;
1947 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1948 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1949 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1950 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1953 instruction
->type
= ARM_MOV
;
1955 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1956 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1957 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1958 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1961 instruction
->type
= ARM_MOV
;
1963 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1964 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1965 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1966 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1969 instruction
->type
= ARM_ADC
;
1973 instruction
->type
= ARM_SBC
;
1977 instruction
->type
= ARM_MOV
;
1979 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1980 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1981 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1982 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1985 instruction
->type
= ARM_TST
;
1989 instruction
->type
= ARM_RSB
;
1991 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1992 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1993 instruction
->info
.data_proc
.Rn
= Rm
;
1996 instruction
->type
= ARM_CMP
;
2000 instruction
->type
= ARM_CMN
;
2004 instruction
->type
= ARM_ORR
;
2008 instruction
->type
= ARM_MUL
;
2012 instruction
->type
= ARM_BIC
;
2016 instruction
->type
= ARM_MVN
;
2023 snprintf(instruction
->text
, 128,
2024 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2026 address
, opcode
, mnemonic
, Rd
, Rm
);
2028 snprintf(instruction
->text
, 128,
2029 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2030 address
, opcode
, mnemonic
, Rd
, Rm
);
2035 /* PC-relative data addressing is word-aligned even with Thumb */
2036 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2038 return (addr
+ 4) & ~3;
2041 int evaluate_load_literal_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2044 uint8_t Rd
= (opcode
>> 8) & 0x7;
2046 instruction
->type
= ARM_LDR
;
2047 immediate
= opcode
& 0x000000ff;
2050 instruction
->info
.load_store
.Rd
= Rd
;
2051 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2052 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2053 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2054 instruction
->info
.load_store
.offset
.offset
= immediate
;
2056 snprintf(instruction
->text
, 128,
2057 "0x%8.8" PRIx32
" 0x%4.4x \t"
2058 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2059 address
, opcode
, Rd
, immediate
,
2060 thumb_alignpc4(address
) + immediate
);
2065 int evaluate_load_store_reg_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2067 uint8_t Rd
= (opcode
>> 0) & 0x7;
2068 uint8_t Rn
= (opcode
>> 3) & 0x7;
2069 uint8_t Rm
= (opcode
>> 6) & 0x7;
2070 uint8_t opc
= (opcode
>> 9) & 0x7;
2071 char *mnemonic
= NULL
;
2076 instruction
->type
= ARM_STR
;
2080 instruction
->type
= ARM_STRH
;
2084 instruction
->type
= ARM_STRB
;
2088 instruction
->type
= ARM_LDRSB
;
2092 instruction
->type
= ARM_LDR
;
2096 instruction
->type
= ARM_LDRH
;
2100 instruction
->type
= ARM_LDRB
;
2104 instruction
->type
= ARM_LDRSH
;
2109 snprintf(instruction
->text
, 128,
2110 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2111 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2113 instruction
->info
.load_store
.Rd
= Rd
;
2114 instruction
->info
.load_store
.Rn
= Rn
;
2115 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2116 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2117 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2122 int evaluate_load_store_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2124 uint32_t offset
= (opcode
>> 6) & 0x1f;
2125 uint8_t Rd
= (opcode
>> 0) & 0x7;
2126 uint8_t Rn
= (opcode
>> 3) & 0x7;
2127 uint32_t L
= opcode
& (1 << 11);
2128 uint32_t B
= opcode
& (1 << 12);
2135 instruction
->type
= ARM_LDR
;
2140 instruction
->type
= ARM_STR
;
2144 if ((opcode
&0xF000) == 0x8000)
2155 snprintf(instruction
->text
, 128,
2156 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2157 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2159 instruction
->info
.load_store
.Rd
= Rd
;
2160 instruction
->info
.load_store
.Rn
= Rn
;
2161 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2162 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2163 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2168 int evaluate_load_store_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2170 uint32_t offset
= opcode
& 0xff;
2171 uint8_t Rd
= (opcode
>> 8) & 0x7;
2172 uint32_t L
= opcode
& (1 << 11);
2177 instruction
->type
= ARM_LDR
;
2182 instruction
->type
= ARM_STR
;
2186 snprintf(instruction
->text
, 128,
2187 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2188 address
, opcode
, mnemonic
, Rd
, offset
*4);
2190 instruction
->info
.load_store
.Rd
= Rd
;
2191 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2192 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2193 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2194 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2199 int evaluate_add_sp_pc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2201 uint32_t imm
= opcode
& 0xff;
2202 uint8_t Rd
= (opcode
>> 8) & 0x7;
2204 uint32_t SP
= opcode
& (1 << 11);
2207 instruction
->type
= ARM_ADD
;
2220 snprintf(instruction
->text
, 128,
2221 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2222 address
, opcode
, Rd
, reg_name
, imm
* 4);
2224 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2225 instruction
->info
.data_proc
.Rd
= Rd
;
2226 instruction
->info
.data_proc
.Rn
= Rn
;
2227 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2232 int evaluate_adjust_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2234 uint32_t imm
= opcode
& 0x7f;
2235 uint8_t opc
= opcode
& (1 << 7);
2241 instruction
->type
= ARM_SUB
;
2246 instruction
->type
= ARM_ADD
;
2250 snprintf(instruction
->text
, 128,
2251 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2252 address
, opcode
, mnemonic
, imm
*4);
2254 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2255 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2256 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2257 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2262 int evaluate_breakpoint_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2264 uint32_t imm
= opcode
& 0xff;
2266 instruction
->type
= ARM_BKPT
;
2268 snprintf(instruction
->text
, 128,
2269 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2270 address
, opcode
, imm
);
2275 int evaluate_load_store_multiple_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2277 uint32_t reg_list
= opcode
& 0xff;
2278 uint32_t L
= opcode
& (1 << 11);
2279 uint32_t R
= opcode
& (1 << 8);
2280 uint8_t Rn
= (opcode
>> 8) & 7;
2281 uint8_t addr_mode
= 0 /* IA */;
2285 char ptr_name
[7] = "";
2288 if ((opcode
& 0xf000) == 0xc000)
2289 { /* generic load/store multiple */
2294 instruction
->type
= ARM_LDM
;
2296 if (opcode
& (1 << Rn
))
2301 instruction
->type
= ARM_STM
;
2304 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2311 instruction
->type
= ARM_LDM
;
2314 reg_list
|= (1 << 15) /*PC*/;
2318 instruction
->type
= ARM_STM
;
2320 addr_mode
= 3; /*DB*/
2322 reg_list
|= (1 << 14) /*LR*/;
2326 reg_names_p
= reg_names
;
2327 for (i
= 0; i
<= 15; i
++)
2329 if (reg_list
& (1 << i
))
2330 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2332 if (reg_names_p
> reg_names
)
2333 reg_names_p
[-2] = '\0';
2334 else /* invalid op : no registers */
2335 reg_names
[0] = '\0';
2337 snprintf(instruction
->text
, 128,
2338 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2339 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2341 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2342 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2343 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2348 int evaluate_cond_branch_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2350 uint32_t offset
= opcode
& 0xff;
2351 uint8_t cond
= (opcode
>> 8) & 0xf;
2352 uint32_t target_address
;
2356 instruction
->type
= ARM_SWI
;
2357 snprintf(instruction
->text
, 128,
2358 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2359 address
, opcode
, offset
);
2362 else if (cond
== 0xe)
2364 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2365 snprintf(instruction
->text
, 128,
2366 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2371 /* sign extend 8-bit offset */
2372 if (offset
& 0x00000080)
2373 offset
= 0xffffff00 | offset
;
2375 target_address
= address
+ 4 + (offset
<< 1);
2377 snprintf(instruction
->text
, 128,
2378 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2380 arm_condition_strings
[cond
], target_address
);
2382 instruction
->type
= ARM_B
;
2383 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2384 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2389 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2390 arm_instruction_t
*instruction
)
2394 /* added in Thumb2 */
2395 offset
= (opcode
>> 3) & 0x1f;
2396 offset
|= (opcode
& 0x0200) >> 4;
2398 snprintf(instruction
->text
, 128,
2399 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2401 (opcode
& 0x0800) ? "N" : "",
2402 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2407 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2408 arm_instruction_t
*instruction
)
2410 /* added in ARMv6 */
2411 snprintf(instruction
->text
, 128,
2412 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2414 (opcode
& 0x0080) ? 'U' : 'S',
2415 (opcode
& 0x0040) ? 'B' : 'H',
2416 opcode
& 0x7, (opcode
>> 3) & 0x7);
2421 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2422 arm_instruction_t
*instruction
)
2424 /* added in ARMv6 */
2425 if ((opcode
& 0x0ff0) == 0x0650)
2426 snprintf(instruction
->text
, 128,
2427 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2429 (opcode
& 0x80) ? "BE" : "LE");
2430 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2431 snprintf(instruction
->text
, 128,
2432 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2434 (opcode
& 0x0010) ? 'D' : 'E',
2435 (opcode
& 0x0004) ? "A" : "",
2436 (opcode
& 0x0002) ? "I" : "",
2437 (opcode
& 0x0001) ? "F" : "");
2442 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2443 arm_instruction_t
*instruction
)
2447 /* added in ARMv6 */
2448 switch ((opcode
>> 6) & 3) {
2459 snprintf(instruction
->text
, 128,
2460 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2461 address
, opcode
, suffix
,
2462 opcode
& 0x7, (opcode
>> 3) & 0x7);
2467 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2468 arm_instruction_t
*instruction
)
2472 switch ((opcode
>> 4) & 0x0f) {
2489 hint
= "HINT (UNRECOGNIZED)";
2493 snprintf(instruction
->text
, 128,
2494 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2495 address
, opcode
, hint
);
2500 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2501 arm_instruction_t
*instruction
)
2503 unsigned cond
= (opcode
>> 4) & 0x0f;
2504 char *x
= "", *y
= "", *z
= "";
2507 z
= (opcode
& 0x02) ? "T" : "E";
2509 y
= (opcode
& 0x04) ? "T" : "E";
2511 x
= (opcode
& 0x08) ? "T" : "E";
2513 snprintf(instruction
->text
, 128,
2514 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2516 x
, y
, z
, arm_condition_strings
[cond
]);
2518 /* NOTE: strictly speaking, the next 1-4 instructions should
2519 * now be displayed with the relevant conditional suffix...
2525 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2527 /* clear fields, to avoid confusion */
2528 memset(instruction
, 0, sizeof(arm_instruction_t
));
2529 instruction
->opcode
= opcode
;
2530 instruction
->instruction_size
= 2;
2532 if ((opcode
& 0xe000) == 0x0000)
2534 /* add/substract register or immediate */
2535 if ((opcode
& 0x1800) == 0x1800)
2536 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2537 /* shift by immediate */
2539 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2542 /* Add/substract/compare/move immediate */
2543 if ((opcode
& 0xe000) == 0x2000)
2545 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2548 /* Data processing instructions */
2549 if ((opcode
& 0xf800) == 0x4000)
2551 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2554 /* Load from literal pool */
2555 if ((opcode
& 0xf800) == 0x4800)
2557 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2560 /* Load/Store register offset */
2561 if ((opcode
& 0xf000) == 0x5000)
2563 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2566 /* Load/Store immediate offset */
2567 if (((opcode
& 0xe000) == 0x6000)
2568 ||((opcode
& 0xf000) == 0x8000))
2570 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2573 /* Load/Store from/to stack */
2574 if ((opcode
& 0xf000) == 0x9000)
2576 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2580 if ((opcode
& 0xf000) == 0xa000)
2582 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2586 if ((opcode
& 0xf000) == 0xb000)
2588 switch ((opcode
>> 8) & 0x0f) {
2590 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2595 return evaluate_cb_thumb(opcode
, address
, instruction
);
2597 return evaluate_extend_thumb(opcode
, address
, instruction
);
2602 return evaluate_load_store_multiple_thumb(opcode
, address
,
2605 return evaluate_cps_thumb(opcode
, address
, instruction
);
2607 if ((opcode
& 0x00c0) == 0x0080)
2609 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2611 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2613 if (opcode
& 0x000f)
2614 return evaluate_ifthen_thumb(opcode
, address
,
2617 return evaluate_hint_thumb(opcode
, address
,
2621 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2622 snprintf(instruction
->text
, 128,
2623 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2628 /* Load/Store multiple */
2629 if ((opcode
& 0xf000) == 0xc000)
2631 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2634 /* Conditional branch + SWI */
2635 if ((opcode
& 0xf000) == 0xd000)
2637 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2640 if ((opcode
& 0xe000) == 0xe000)
2642 /* Undefined instructions */
2643 if ((opcode
& 0xf801) == 0xe801)
2645 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2646 snprintf(instruction
->text
, 128,
2647 "0x%8.8" PRIx32
" 0x%8.8x\t"
2648 "UNDEFINED INSTRUCTION",
2653 { /* Branch to offset */
2654 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2658 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2662 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2663 arm_instruction_t
*instruction
, char *cp
)
2666 unsigned b21
= 1 << 21;
2667 unsigned b22
= 1 << 22;
2669 /* instead of combining two smaller 16-bit branch instructions,
2670 * Thumb2 uses only one larger 32-bit instruction.
2672 offset
= opcode
& 0x7ff;
2673 offset
|= (opcode
& 0x03ff0000) >> 5;
2674 if (opcode
& (1 << 26)) {
2675 offset
|= 0xff << 23;
2676 if ((opcode
& (1 << 11)) == 0)
2678 if ((opcode
& (1 << 13)) == 0)
2681 if (opcode
& (1 << 11))
2683 if (opcode
& (1 << 13))
2691 address
+= offset
<< 1;
2693 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2694 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2695 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2696 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2697 (opcode
& (1 << 14)) ? "BL" : "B.W",
2703 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2704 arm_instruction_t
*instruction
, char *cp
)
2707 unsigned b17
= 1 << 17;
2708 unsigned b18
= 1 << 18;
2709 unsigned cond
= (opcode
>> 22) & 0x0f;
2711 offset
= opcode
& 0x7ff;
2712 offset
|= (opcode
& 0x003f0000) >> 5;
2713 if (opcode
& (1 << 26)) {
2714 offset
|= 0xffff << 19;
2715 if ((opcode
& (1 << 11)) == 0)
2717 if ((opcode
& (1 << 13)) == 0)
2720 if (opcode
& (1 << 11))
2722 if (opcode
& (1 << 13))
2729 address
+= offset
<< 1;
2731 instruction
->type
= ARM_B
;
2732 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2733 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2734 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2735 arm_condition_strings
[cond
],
2741 static const char *special_name(int number
)
2743 char *special
= "(RESERVED)";
2774 special
= "primask";
2777 special
= "basepri";
2780 special
= "basepri_max";
2783 special
= "faultmask";
2786 special
= "control";
2792 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2793 arm_instruction_t
*instruction
, char *cp
)
2795 const char *mnemonic
;
2797 if (opcode
& 0x0700) {
2798 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2799 strcpy(cp
, "UNDEFINED");
2803 if (opcode
& 0x00f0) {
2804 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2808 switch (opcode
& 0x0f) {
2813 mnemonic
= "YIELD.W";
2825 mnemonic
= "HINT.W (UNRECOGNIZED)";
2828 strcpy(cp
, mnemonic
);
2832 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2833 arm_instruction_t
*instruction
, char *cp
)
2835 const char *mnemonic
;
2837 switch ((opcode
>> 4) & 0x0f) {
2851 return ERROR_INVALID_ARGUMENTS
;
2853 strcpy(cp
, mnemonic
);
2857 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2858 arm_instruction_t
*instruction
, char *cp
)
2860 /* permanently undefined */
2861 if ((opcode
& 0x07f07000) == 0x07f02000) {
2862 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2863 strcpy(cp
, "UNDEFINED");
2867 switch ((opcode
>> 12) & 0x5) {
2870 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2874 if (((opcode
>> 23) & 0x07) != 0x07)
2875 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2876 if (opcode
& (1 << 26))
2881 switch ((opcode
>> 20) & 0x7f) {
2884 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2885 (int) (opcode
>> 16) & 0x0f);
2888 return t2ev_hint(opcode
, address
, instruction
, cp
);
2890 return t2ev_misc(opcode
, address
, instruction
, cp
);
2893 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
2894 special_name(opcode
& 0xff));
2899 return ERROR_INVALID_ARGUMENTS
;
2902 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
2903 arm_instruction_t
*instruction
, char *cp
)
2905 char *mnemonic
= NULL
;
2906 int rn
= (opcode
>> 16) & 0xf;
2907 int rd
= (opcode
>> 8) & 0xf;
2908 unsigned immed
= opcode
& 0xff;
2914 /* ARMv7-M: A5.3.2 Modified immediate constants */
2915 func
= (opcode
>> 11) & 0x0e;
2918 if (opcode
& (1 << 26))
2921 /* "Modified" immediates */
2922 switch (func
>> 1) {
2929 immed
+= immed
<< 16;
2932 immed
+= immed
<< 8;
2933 immed
+= immed
<< 16;
2937 immed
= ror(immed
, func
);
2940 if (opcode
& (1 << 20))
2943 switch ((opcode
>> 21) & 0xf) {
2946 instruction
->type
= ARM_TST
;
2952 instruction
->type
= ARM_AND
;
2957 instruction
->type
= ARM_BIC
;
2962 instruction
->type
= ARM_MOV
;
2967 instruction
->type
= ARM_ORR
;
2973 instruction
->type
= ARM_MVN
;
2977 // instruction->type = ARM_ORN;
2983 instruction
->type
= ARM_TEQ
;
2989 instruction
->type
= ARM_EOR
;
2995 instruction
->type
= ARM_CMN
;
3001 instruction
->type
= ARM_ADD
;
3007 instruction
->type
= ARM_ADC
;
3012 instruction
->type
= ARM_SBC
;
3017 instruction
->type
= ARM_CMP
;
3023 instruction
->type
= ARM_SUB
;
3029 instruction
->type
= ARM_RSB
;
3034 return ERROR_INVALID_ARGUMENTS
;
3038 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3039 mnemonic
, suffix2
,rd
, immed
, immed
);
3041 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3042 mnemonic
, suffix
, suffix2
,
3043 rd
, rn
, immed
, immed
);
3048 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3049 arm_instruction_t
*instruction
, char *cp
)
3051 char *mnemonic
= NULL
;
3052 int rn
= (opcode
>> 16) & 0xf;
3053 int rd
= (opcode
>> 8) & 0xf;
3056 bool is_signed
= false;
3058 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3059 if (opcode
& (1 << 26))
3062 switch ((opcode
>> 20) & 0x1f) {
3071 immed
|= (opcode
>> 4) & 0xf000;
3072 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3080 /* move constant to top 16 bits of register */
3081 immed
|= (opcode
>> 4) & 0xf000;
3082 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3089 /* signed/unsigned saturated add */
3090 immed
= (opcode
>> 6) & 0x03;
3091 immed
|= (opcode
>> 10) & 0x1c;
3092 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3093 is_signed
? "S" : "U",
3094 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3095 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3096 immed
? immed
: 32);
3102 /* signed/unsigned bitfield extract */
3103 immed
= (opcode
>> 6) & 0x03;
3104 immed
|= (opcode
>> 10) & 0x1c;
3105 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3106 is_signed
? "S" : "U",
3108 (int) (opcode
& 0x1f) + 1);
3111 immed
= (opcode
>> 6) & 0x03;
3112 immed
|= (opcode
>> 10) & 0x1c;
3113 if (rn
== 0xf) /* bitfield clear */
3114 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3116 (int) (opcode
& 0x1f) + 1 - immed
);
3117 else /* bitfield insert */
3118 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3120 (int) (opcode
& 0x1f) + 1 - immed
);
3123 return ERROR_INVALID_ARGUMENTS
;
3126 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3127 rd
, rn
, immed
, immed
);
3131 address
= thumb_alignpc4(address
);
3136 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3137 * not hiding the pc-relative stuff will sometimes be useful.
3139 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3143 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3144 arm_instruction_t
*instruction
, char *cp
)
3146 unsigned op
= (opcode
>> 20) & 0xf;
3152 unsigned rn
= (opcode
>> 16) & 0x0f;
3153 unsigned rt
= (opcode
>> 12) & 0x0f;
3156 return ERROR_INVALID_ARGUMENTS
;
3158 if (opcode
& 0x0800)
3193 return ERROR_INVALID_ARGUMENTS
;
3196 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3197 size
, rt
, rn
, (int) opcode
& 0x0f,
3198 (int) (opcode
>> 4) & 0x03);
3202 immed
= opcode
& 0x0fff;
3203 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3204 size
, rt
, rn
, immed
, immed
);
3208 immed
= opcode
& 0x00ff;
3210 switch (opcode
& 0x700) {
3216 return ERROR_INVALID_ARGUMENTS
;
3219 /* two indexed modes will write back rn */
3220 if (opcode
& 0x100) {
3221 if (opcode
& 0x400) /* pre-indexed */
3223 else { /* post-indexed */
3229 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3230 size
, suffix
, rt
, rn
, p1
,
3231 (opcode
& 0x200) ? "" : "-",
3236 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3237 arm_instruction_t
*instruction
, char *cp
)
3239 int ra
= (opcode
>> 12) & 0xf;
3241 switch (opcode
& 0x007000f0) {
3244 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3245 (int) (opcode
>> 8) & 0xf,
3246 (int) (opcode
>> 16) & 0xf,
3247 (int) (opcode
>> 0) & 0xf);
3249 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3250 (int) (opcode
>> 8) & 0xf,
3251 (int) (opcode
>> 16) & 0xf,
3252 (int) (opcode
>> 0) & 0xf, ra
);
3255 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3256 (int) (opcode
>> 8) & 0xf,
3257 (int) (opcode
>> 16) & 0xf,
3258 (int) (opcode
>> 0) & 0xf, ra
);
3261 return ERROR_INVALID_ARGUMENTS
;
3266 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3267 arm_instruction_t
*instruction
, char *cp
)
3269 int op
= (opcode
>> 4) & 0xf;
3270 char *infix
= "MUL";
3272 op
+= (opcode
>> 16) & 0x70;
3280 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3281 (op
& 0x20) ? 'U' : 'S',
3283 (int) (opcode
>> 12) & 0xf,
3284 (int) (opcode
>> 8) & 0xf,
3285 (int) (opcode
>> 16) & 0xf,
3286 (int) (opcode
>> 0) & 0xf);
3290 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3291 (op
& 0x20) ? 'U' : 'S',
3292 (int) (opcode
>> 8) & 0xf,
3293 (int) (opcode
>> 16) & 0xf,
3294 (int) (opcode
>> 0) & 0xf);
3297 return ERROR_INVALID_ARGUMENTS
;
3303 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3304 arm_instruction_t
*instruction
, char *cp
)
3306 int rn
= (opcode
>> 16) & 0xf;
3307 int op
= (opcode
>> 22) & 0x6;
3308 int t
= (opcode
>> 21) & 1;
3309 unsigned registers
= opcode
& 0xffff;
3311 if (opcode
& (1 << 20))
3316 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3320 sprintf(cp
, "POP.W\t");
3322 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3326 sprintf(cp
, "PUSH.W\t");
3328 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3331 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3334 return ERROR_INVALID_ARGUMENTS
;
3339 for (t
= 0; registers
; t
++, registers
>>= 1) {
3340 if ((registers
& 1) == 0)
3343 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3352 /* load/store dual or exclusive, table branch */
3353 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3354 arm_instruction_t
*instruction
, char *cp
)
3356 unsigned op1op2
= (opcode
>> 20) & 0x3;
3357 unsigned op3
= (opcode
>> 4) & 0xf;
3359 unsigned rn
= (opcode
>> 16) & 0xf;
3360 unsigned rt
= (opcode
>> 12) & 0xf;
3361 unsigned rd
= (opcode
>> 8) & 0xf;
3362 unsigned imm
= opcode
& 0xff;
3366 op1op2
|= (opcode
>> 21) & 0xc;
3396 mnemonic
= "STREXB";
3399 mnemonic
= "STREXH";
3402 return ERROR_INVALID_ARGUMENTS
;
3410 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3413 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3416 mnemonic
= "LDREXB";
3419 mnemonic
= "LDREXH";
3422 return ERROR_INVALID_ARGUMENTS
;
3427 return ERROR_INVALID_ARGUMENTS
;
3432 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3433 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3435 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3436 mnemonic
, rd
, rt
, rn
);
3442 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3443 mnemonic
, rt
, rn
, imm
, imm
);
3445 sprintf(cp
, "%s\tr%u, [r%u]",
3450 /* two indexed modes will write back rn */
3451 if (opcode
& (1 << 21)) {
3452 if (opcode
& (1 << 24)) /* pre-indexed */
3454 else { /* post-indexed */
3461 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3462 mnemonic
, rt
, rd
, rn
, p1
,
3463 (opcode
& (1 << 23)) ? "" : "-",
3468 address
= thumb_alignpc4(address
);
3470 if (opcode
& (1 << 23))
3474 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3475 mnemonic
, rt
, rd
, address
);
3479 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3480 arm_instruction_t
*instruction
, char *cp
)
3482 int op
= (opcode
>> 21) & 0xf;
3483 int rd
= (opcode
>> 8) & 0xf;
3484 int rn
= (opcode
>> 16) & 0xf;
3485 int type
= (opcode
>> 4) & 0x3;
3486 int immed
= (opcode
>> 6) & 0x3;
3490 immed
|= (opcode
>> 10) & 0x1c;
3491 if (opcode
& (1 << 20))
3497 if (!(opcode
& (1 << 20)))
3498 return ERROR_INVALID_ARGUMENTS
;
3499 instruction
->type
= ARM_TST
;
3504 instruction
->type
= ARM_AND
;
3508 instruction
->type
= ARM_BIC
;
3513 instruction
->type
= ARM_MOV
;
3517 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3519 (int) (opcode
& 0xf));
3532 sprintf(cp
, "RRX%s\tr%d, r%d",
3534 (int) (opcode
& 0xf));
3542 instruction
->type
= ARM_ORR
;
3548 instruction
->type
= ARM_MVN
;
3553 // instruction->type = ARM_ORN;
3559 if (!(opcode
& (1 << 20)))
3560 return ERROR_INVALID_ARGUMENTS
;
3561 instruction
->type
= ARM_TEQ
;
3566 instruction
->type
= ARM_EOR
;
3571 if (!(opcode
& (1 << 20)))
3572 return ERROR_INVALID_ARGUMENTS
;
3573 instruction
->type
= ARM_CMN
;
3578 instruction
->type
= ARM_ADD
;
3582 instruction
->type
= ARM_ADC
;
3586 instruction
->type
= ARM_SBC
;
3591 if (!(opcode
& (1 << 21)))
3592 return ERROR_INVALID_ARGUMENTS
;
3593 instruction
->type
= ARM_CMP
;
3598 instruction
->type
= ARM_SUB
;
3602 instruction
->type
= ARM_RSB
;
3606 return ERROR_INVALID_ARGUMENTS
;
3609 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3610 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3633 strcpy(cp
, ", RRX");
3639 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3643 sprintf(cp
, "%s%s.W\tr%d, r%d",
3644 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3648 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3649 mnemonic
, suffix
, rd
,
3650 (int) (opcode
& 0xf), immed
? immed
: 32);
3654 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3655 arm_instruction_t
*instruction
, char *cp
)
3660 if (((opcode
>> 4) & 0xf) == 0) {
3661 switch ((opcode
>> 21) & 0x7) {
3675 return ERROR_INVALID_ARGUMENTS
;
3678 instruction
->type
= ARM_MOV
;
3679 if (opcode
& (1 << 20))
3681 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3683 (int) (opcode
>> 8) & 0xf,
3684 (int) (opcode
>> 16) & 0xf,
3685 (int) (opcode
>> 0) & 0xf);
3687 } else if (opcode
& (1 << 7)) {
3688 switch ((opcode
>> 20) & 0xf) {
3693 switch ((opcode
>> 4) & 0x3) {
3695 suffix
= ", ROR #8";
3698 suffix
= ", ROR #16";
3701 suffix
= ", ROR #24";
3704 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3705 (opcode
& (1 << 24)) ? 'U' : 'S',
3706 (opcode
& (1 << 26)) ? 'B' : 'H',
3707 (int) (opcode
>> 8) & 0xf,
3708 (int) (opcode
>> 0) & 0xf,
3715 if (opcode
& (1 << 6))
3716 return ERROR_INVALID_ARGUMENTS
;
3717 if (((opcode
>> 12) & 0xf) != 0xf)
3718 return ERROR_INVALID_ARGUMENTS
;
3719 if (!(opcode
& (1 << 20)))
3720 return ERROR_INVALID_ARGUMENTS
;
3722 switch (((opcode
>> 19) & 0x04)
3723 | ((opcode
>> 4) & 0x3)) {
3728 mnemonic
= "REV16.W";
3734 mnemonic
= "REVSH.W";
3740 return ERROR_INVALID_ARGUMENTS
;
3742 sprintf(cp
, "%s\tr%d, r%d",
3744 (int) (opcode
>> 8) & 0xf,
3745 (int) (opcode
>> 0) & 0xf);
3748 return ERROR_INVALID_ARGUMENTS
;
3755 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3756 arm_instruction_t
*instruction
, char *cp
)
3758 int rn
= (opcode
>> 16) & 0xf;
3761 instruction
->type
= ARM_LDR
;
3764 immed
= opcode
& 0x0fff;
3765 if ((opcode
& (1 << 23)) == 0)
3767 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3768 (int) (opcode
>> 12) & 0xf,
3769 thumb_alignpc4(address
) + immed
);
3773 if (opcode
& (1 << 23)) {
3774 immed
= opcode
& 0x0fff;
3775 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3776 (int) (opcode
>> 12) & 0xf,
3781 if (!(opcode
& (0x3f << 6))) {
3782 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3783 (int) (opcode
>> 12) & 0xf,
3785 (int) (opcode
>> 0) & 0xf,
3786 (int) (opcode
>> 4) & 0x3);
3791 if (((opcode
>> 8) & 0xf) == 0xe) {
3792 immed
= opcode
& 0x00ff;
3794 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3795 (int) (opcode
>> 12) & 0xf,
3800 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3801 char *p1
= "]", *p2
= "";
3803 if (!(opcode
& 0x0500))
3804 return ERROR_INVALID_ARGUMENTS
;
3806 immed
= opcode
& 0x00ff;
3808 /* two indexed modes will write back rn */
3809 if (opcode
& 0x100) {
3810 if (opcode
& 0x400) /* pre-indexed */
3812 else { /* post-indexed */
3818 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3819 (int) (opcode
>> 12) & 0xf,
3821 (opcode
& 0x200) ? "" : "-",
3826 return ERROR_INVALID_ARGUMENTS
;
3829 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3830 arm_instruction_t
*instruction
, char *cp
)
3832 int rn
= (opcode
>> 16) & 0xf;
3833 int rt
= (opcode
>> 12) & 0xf;
3834 int op2
= (opcode
>> 6) & 0x3f;
3836 char *p1
= "", *p2
= "]";
3839 switch ((opcode
>> 23) & 0x3) {
3841 if ((rn
& rt
) == 0xf) {
3843 immed
= opcode
& 0xfff;
3844 address
= thumb_alignpc4(address
);
3845 if (opcode
& (1 << 23))
3849 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
3853 if (rn
== 0x0f && rt
!= 0x0f) {
3855 immed
= opcode
& 0xfff;
3856 address
= thumb_alignpc4(address
);
3857 if (opcode
& (1 << 23))
3861 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
3867 if ((op2
& 0x3c) == 0x38) {
3868 immed
= opcode
& 0xff;
3869 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3870 rt
, rn
, immed
, immed
);
3873 if ((op2
& 0x3c) == 0x30) {
3875 immed
= opcode
& 0xff;
3878 p1
= (opcode
& (1 << 21)) ? "W" : "";
3879 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3880 p1
, rn
, immed
, immed
);
3885 immed
= opcode
& 0xff;
3886 if (!(opcode
& 0x200))
3889 /* two indexed modes will write back rn */
3890 if (opcode
& 0x100) {
3891 if (opcode
& 0x400) /* pre-indexed */
3893 else { /* post-indexed */
3899 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3900 mnemonic
, rt
, rn
, p1
,
3904 if ((op2
& 0x24) == 0x24) {
3906 goto ldrxb_immediate_t3
;
3909 int rm
= opcode
& 0xf;
3912 sprintf(cp
, "PLD\t");
3914 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
3915 immed
= (opcode
>> 4) & 0x3;
3917 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3922 if ((rn
& rt
) == 0xf)
3925 immed
= opcode
& 0xfff;
3926 goto preload_immediate
;
3930 mnemonic
= "LDRB.W";
3931 immed
= opcode
& 0xfff;
3932 goto ldrxb_immediate_t2
;
3934 if ((rn
& rt
) == 0xf) {
3935 immed
= opcode
& 0xfff;
3936 address
= thumb_alignpc4(address
);
3937 if (opcode
& (1 << 23))
3941 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
3944 if (rn
== 0xf && rt
!= 0xf) {
3946 immed
= opcode
& 0xfff;
3947 address
= thumb_alignpc4(address
);
3948 if (opcode
& (1 << 23))
3952 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
3957 if ((op2
& 0x3c) == 0x38) {
3958 immed
= opcode
& 0xff;
3959 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
3960 rt
, rn
, immed
, immed
);
3963 if ((op2
& 0x3c) == 0x30) {
3965 immed
= opcode
& 0xff;
3966 immed
= -immed
; // pli
3967 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
3972 goto ldrxb_immediate_t3
;
3974 if ((op2
& 0x24) == 0x24) {
3976 goto ldrxb_immediate_t3
;
3979 int rm
= opcode
& 0xf;
3982 sprintf(cp
, "PLI\t");
3984 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
3985 immed
= (opcode
>> 4) & 0x3;
3987 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3993 immed
= opcode
& 0xfff;
3994 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4000 immed
= opcode
& 0xfff;
4002 goto ldrxb_immediate_t2
;
4005 return ERROR_INVALID_ARGUMENTS
;
4008 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4009 arm_instruction_t
*instruction
, char *cp
)
4011 int rn
= (opcode
>> 16) & 0xf;
4012 int rt
= (opcode
>> 12) & 0xf;
4013 int op2
= (opcode
>> 6) & 0x3f;
4018 sprintf(cp
, "HINT (UNALLOCATED)");
4022 if (opcode
& (1 << 24))
4025 if ((opcode
& (1 << 23)) == 0) {
4028 immed
= opcode
& 0xfff;
4029 address
= thumb_alignpc4(address
);
4030 if (opcode
& (1 << 23))
4034 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4039 int rm
= opcode
& 0xf;
4041 immed
= (opcode
>> 4) & 0x3;
4042 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4043 sign
, rt
, rn
, rm
, immed
);
4046 if ((op2
& 0x3c) == 0x38) {
4047 immed
= opcode
& 0xff;
4048 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4049 sign
, rt
, rn
, immed
, immed
);
4052 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4053 char *p1
= "", *p2
= "]";
4055 immed
= opcode
& 0xff;
4056 if (!(opcode
& 0x200))
4059 /* two indexed modes will write back rn */
4060 if (opcode
& 0x100) {
4061 if (opcode
& 0x400) /* pre-indexed */
4063 else { /* post-indexed */
4068 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4069 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4076 immed
= opcode
& 0xfff;
4077 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4078 sign
, *sign
? "" : ".W",
4079 rt
, rn
, immed
, immed
);
4083 return ERROR_INVALID_ARGUMENTS
;
4087 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4088 * always set. That means eventual arm_simulate_step() support for Thumb2
4089 * will need work in this area.
4091 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
4098 /* clear low bit ... it's set on function pointers */
4101 /* clear fields, to avoid confusion */
4102 memset(instruction
, 0, sizeof(arm_instruction_t
));
4104 /* read first halfword, see if this is the only one */
4105 retval
= target_read_u16(target
, address
, &op
);
4106 if (retval
!= ERROR_OK
)
4109 switch (op
& 0xf800) {
4113 /* 32-bit instructions */
4114 instruction
->instruction_size
= 4;
4116 retval
= target_read_u16(target
, address
+ 2, &op
);
4117 if (retval
!= ERROR_OK
)
4120 instruction
->opcode
= opcode
;
4123 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4124 return thumb_evaluate_opcode(op
, address
, instruction
);
4127 snprintf(instruction
->text
, 128,
4128 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4130 cp
= strchr(instruction
->text
, 0);
4131 retval
= ERROR_FAIL
;
4133 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4134 if ((opcode
& 0x1a008000) == 0x10000000)
4135 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4137 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4138 else if ((opcode
& 0x1a008000) == 0x12000000)
4139 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4141 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4142 else if ((opcode
& 0x18008000) == 0x10008000)
4143 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4145 /* ARMv7-M: A5.3.5 Load/store multiple */
4146 else if ((opcode
& 0x1e400000) == 0x08000000)
4147 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4149 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4150 else if ((opcode
& 0x1e400000) == 0x08400000)
4151 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4153 /* ARMv7-M: A5.3.7 Load word */
4154 else if ((opcode
& 0x1f700000) == 0x18500000)
4155 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4157 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4158 else if ((opcode
& 0x1e700000) == 0x18300000)
4159 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4161 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4162 else if ((opcode
& 0x1e700000) == 0x18100000)
4163 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4165 /* ARMv7-M: A5.3.10 Store single data item */
4166 else if ((opcode
& 0x1f100000) == 0x18000000)
4167 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4169 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4170 else if ((opcode
& 0x1e000000) == 0x0a000000)
4171 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4173 /* ARMv7-M: A5.3.12 Data processing (register)
4174 * and A5.3.13 Miscellaneous operations
4176 else if ((opcode
& 0x1f000000) == 0x1a000000)
4177 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4179 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4180 else if ((opcode
& 0x1f800000) == 0x1b000000)
4181 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4183 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4184 else if ((opcode
& 0x1f800000) == 0x1b800000)
4185 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4187 if (retval
== ERROR_OK
)
4191 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4192 * instructions; not yet handled here.
4195 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4196 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4197 strcpy(cp
, "UNDEFINED OPCODE");
4201 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4204 strcpy(cp
, "(32-bit Thumb2 ...)");
4208 int arm_access_size(arm_instruction_t
*instruction
)
4210 if ((instruction
->type
== ARM_LDRB
)
4211 || (instruction
->type
== ARM_LDRBT
)
4212 || (instruction
->type
== ARM_LDRSB
)
4213 || (instruction
->type
== ARM_STRB
)
4214 || (instruction
->type
== ARM_STRBT
))
4218 else if ((instruction
->type
== ARM_LDRH
)
4219 || (instruction
->type
== ARM_LDRSH
)
4220 || (instruction
->type
== ARM_STRH
))
4224 else if ((instruction
->type
== ARM_LDR
)
4225 || (instruction
->type
== ARM_LDRT
)
4226 || (instruction
->type
== ARM_STR
)
4227 || (instruction
->type
== ARM_STRT
))
4231 else if ((instruction
->type
== ARM_LDRD
)
4232 || (instruction
->type
== ARM_STRD
))
4238 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)