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 switch ((opcode
>> 24) & 0x3) {
453 sprintf(cp
, "UNDEFINED");
454 return ARM_UNDEFINED_INSTRUCTION
;
463 switch ((opcode
>> 10) & 0x3) {
479 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
480 (opcode
& (1 << 22)) ? 'U' : 'S',
485 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
486 (opcode
& (1 << 22)) ? 'U' : 'S',
493 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
499 switch ((opcode
>> 20) & 0x7) {
522 switch ((opcode
>> 5) & 0x7) {
551 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
552 (int) (opcode
>> 12) & 0xf,
553 (int) (opcode
>> 16) & 0xf,
554 (int) (opcode
>> 0) & 0xf);
558 /* these opcodes might be used someday */
559 sprintf(cp
, "UNDEFINED");
560 return ARM_UNDEFINED_INSTRUCTION
;
563 /* ARMv6 and later support "media" instructions (includes SIMD) */
564 static int evaluate_media(uint32_t opcode
, uint32_t address
,
565 arm_instruction_t
*instruction
)
567 char *cp
= instruction
->text
;
568 char *mnemonic
= NULL
;
571 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
575 /* parallel add/subtract */
576 if ((opcode
& 0x01800000) == 0x00000000) {
577 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
582 if ((opcode
& 0x01f00020) == 0x00800000) {
584 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
586 if (opcode
& (1 << 6)) {
595 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
597 (int) (opcode
>> 12) & 0xf,
598 (int) (opcode
>> 16) & 0xf,
599 (int) (opcode
>> 0) & 0xf,
605 if ((opcode
& 0x01a00020) == 0x00a00000) {
607 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
609 if (opcode
& (1 << 6)) {
617 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
618 (opcode
& (1 << 22)) ? 'U' : 'S',
620 (int) (opcode
>> 12) & 0xf,
621 (int) (opcode
>> 16) & 0x1f,
622 (int) (opcode
>> 0) & 0xf,
628 if ((opcode
& 0x018000f0) == 0x00800070) {
629 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
634 if ((opcode
& 0x01f00080) == 0x01000000) {
635 unsigned rn
= (opcode
>> 12) & 0xf;
638 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
639 (opcode
& (1 << 6)) ? 'S' : 'A',
640 (opcode
& (1 << 5)) ? "X" : "",
642 (int) (opcode
>> 16) & 0xf,
643 (int) (opcode
>> 0) & 0xf,
644 (int) (opcode
>> 8) & 0xf,
647 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
648 (opcode
& (1 << 6)) ? 'S' : 'A',
649 (opcode
& (1 << 5)) ? "X" : "",
651 (int) (opcode
>> 16) & 0xf,
652 (int) (opcode
>> 0) & 0xf,
653 (int) (opcode
>> 8) & 0xf);
656 if ((opcode
& 0x01f00000) == 0x01400000) {
657 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
658 (opcode
& (1 << 6)) ? 'S' : 'A',
659 (opcode
& (1 << 5)) ? "X" : "",
661 (int) (opcode
>> 12) & 0xf,
662 (int) (opcode
>> 16) & 0xf,
663 (int) (opcode
>> 0) & 0xf,
664 (int) (opcode
>> 8) & 0xf);
667 if ((opcode
& 0x01f00000) == 0x01500000) {
668 unsigned rn
= (opcode
>> 12) & 0xf;
670 switch (opcode
& 0xc0) {
682 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
683 (opcode
& (1 << 6)) ? 'S' : 'A',
684 (opcode
& (1 << 5)) ? "R" : "",
686 (int) (opcode
>> 16) & 0xf,
687 (int) (opcode
>> 0) & 0xf,
688 (int) (opcode
>> 8) & 0xf,
691 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
692 (opcode
& (1 << 5)) ? "R" : "",
694 (int) (opcode
>> 16) & 0xf,
695 (int) (opcode
>> 0) & 0xf,
696 (int) (opcode
>> 8) & 0xf);
701 /* simple matches against the remaining decode bits */
702 switch (opcode
& 0x01f000f0) {
705 /* parallel halfword saturate */
706 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
707 (opcode
& (1 << 22)) ? 'U' : 'S',
709 (int) (opcode
>> 12) & 0xf,
710 (int) (opcode
>> 16) & 0xf,
711 (int) (opcode
>> 0) & 0xf);
724 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
725 (int) (opcode
>> 12) & 0xf,
726 (int) (opcode
>> 16) & 0xf,
727 (int) (opcode
>> 0) & 0xf);
730 /* unsigned sum of absolute differences */
731 if (((opcode
>> 12) & 0xf) == 0xf)
732 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
733 (int) (opcode
>> 16) & 0xf,
734 (int) (opcode
>> 0) & 0xf,
735 (int) (opcode
>> 8) & 0xf);
737 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
738 (int) (opcode
>> 16) & 0xf,
739 (int) (opcode
>> 0) & 0xf,
740 (int) (opcode
>> 8) & 0xf,
741 (int) (opcode
>> 12) & 0xf);
745 unsigned rm
= (opcode
>> 0) & 0xf;
746 unsigned rd
= (opcode
>> 12) & 0xf;
748 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
753 /* these opcodes might be used someday */
754 sprintf(cp
, "UNDEFINED");
758 /* Miscellaneous load/store instructions */
759 int evaluate_misc_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
761 uint8_t P
, U
, I
, W
, L
, S
, H
;
763 char *operation
; /* "LDR" or "STR" */
764 char *suffix
; /* "H", "SB", "SH", "D" */
768 P
= (opcode
& 0x01000000) >> 24;
769 U
= (opcode
& 0x00800000) >> 23;
770 I
= (opcode
& 0x00400000) >> 22;
771 W
= (opcode
& 0x00200000) >> 21;
772 L
= (opcode
& 0x00100000) >> 20;
773 S
= (opcode
& 0x00000040) >> 6;
774 H
= (opcode
& 0x00000020) >> 5;
776 /* target register */
777 Rd
= (opcode
& 0xf000) >> 12;
780 Rn
= (opcode
& 0xf0000) >> 16;
782 instruction
->info
.load_store
.Rd
= Rd
;
783 instruction
->info
.load_store
.Rn
= Rn
;
784 instruction
->info
.load_store
.U
= U
;
786 /* determine instruction type and suffix */
794 instruction
->type
= ARM_LDRSH
;
800 instruction
->type
= ARM_LDRSB
;
804 else /* there are no signed stores, so this is used to encode double-register load/stores */
810 instruction
->type
= ARM_STRD
;
815 instruction
->type
= ARM_LDRD
;
825 instruction
->type
= ARM_LDRH
;
830 instruction
->type
= ARM_STRH
;
834 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
836 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
837 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
839 instruction
->info
.load_store
.offset_mode
= 0;
840 instruction
->info
.load_store
.offset
.offset
= offset_8
;
842 else /* Register offset/index (+-<Rm>) */
846 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
848 instruction
->info
.load_store
.offset_mode
= 1;
849 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
850 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
851 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
856 if (W
== 0) /* offset */
858 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
859 address
, opcode
, operation
, COND(opcode
), suffix
,
862 instruction
->info
.load_store
.index_mode
= 0;
864 else /* pre-indexed */
866 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
867 address
, opcode
, operation
, COND(opcode
), suffix
,
870 instruction
->info
.load_store
.index_mode
= 1;
873 else /* post-indexed */
875 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
876 address
, opcode
, operation
, COND(opcode
), suffix
,
879 instruction
->info
.load_store
.index_mode
= 2;
885 /* Load/store multiples instructions */
886 int evaluate_ldm_stm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
888 uint8_t P
, U
, S
, W
, L
, Rn
;
889 uint32_t register_list
;
890 char *addressing_mode
;
897 P
= (opcode
& 0x01000000) >> 24;
898 U
= (opcode
& 0x00800000) >> 23;
899 S
= (opcode
& 0x00400000) >> 22;
900 W
= (opcode
& 0x00200000) >> 21;
901 L
= (opcode
& 0x00100000) >> 20;
902 register_list
= (opcode
& 0xffff);
903 Rn
= (opcode
& 0xf0000) >> 16;
905 instruction
->info
.load_store_multiple
.Rn
= Rn
;
906 instruction
->info
.load_store_multiple
.register_list
= register_list
;
907 instruction
->info
.load_store_multiple
.S
= S
;
908 instruction
->info
.load_store_multiple
.W
= W
;
912 instruction
->type
= ARM_LDM
;
917 instruction
->type
= ARM_STM
;
925 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
926 addressing_mode
= "IB";
930 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
931 addressing_mode
= "DB";
938 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
939 /* "IA" is the default in UAL syntax */
940 addressing_mode
= "";
944 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
945 addressing_mode
= "DA";
949 reg_list_p
= reg_list
;
950 for (i
= 0; i
<= 15; i
++)
952 if ((register_list
>> i
) & 1)
957 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
961 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
966 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
967 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
968 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
973 /* Multiplies, extra load/stores */
974 int evaluate_mul_and_extra_ld_st(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
976 /* Multiply (accumulate) (long) and Swap/swap byte */
977 if ((opcode
& 0x000000f0) == 0x00000090)
979 /* Multiply (accumulate) */
980 if ((opcode
& 0x0f800000) == 0x00000000)
982 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
984 Rs
= (opcode
& 0xf00) >> 8;
985 Rn
= (opcode
& 0xf000) >> 12;
986 Rd
= (opcode
& 0xf0000) >> 16;
987 S
= (opcode
& 0x00100000) >> 20;
989 /* examine A bit (accumulate) */
990 if (opcode
& 0x00200000)
992 instruction
->type
= ARM_MLA
;
993 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
994 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
998 instruction
->type
= ARM_MUL
;
999 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1000 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1006 /* Multiply (accumulate) long */
1007 if ((opcode
& 0x0f800000) == 0x00800000)
1009 char* mnemonic
= NULL
;
1010 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1012 Rs
= (opcode
& 0xf00) >> 8;
1013 RdHi
= (opcode
& 0xf000) >> 12;
1014 RdLow
= (opcode
& 0xf0000) >> 16;
1015 S
= (opcode
& 0x00100000) >> 20;
1017 switch ((opcode
& 0x00600000) >> 21)
1020 instruction
->type
= ARM_UMULL
;
1024 instruction
->type
= ARM_UMLAL
;
1028 instruction
->type
= ARM_SMULL
;
1032 instruction
->type
= ARM_SMLAL
;
1037 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1038 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1039 RdLow
, RdHi
, Rm
, Rs
);
1044 /* Swap/swap byte */
1045 if ((opcode
& 0x0f800000) == 0x01000000)
1049 Rd
= (opcode
& 0xf000) >> 12;
1050 Rn
= (opcode
& 0xf0000) >> 16;
1052 /* examine B flag */
1053 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1055 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1056 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1062 return evaluate_misc_load_store(opcode
, address
, instruction
);
1065 int evaluate_mrs_msr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1067 int R
= (opcode
& 0x00400000) >> 22;
1068 char *PSR
= (R
) ? "SPSR" : "CPSR";
1070 /* Move register to status register (MSR) */
1071 if (opcode
& 0x00200000)
1073 instruction
->type
= ARM_MSR
;
1075 /* immediate variant */
1076 if (opcode
& 0x02000000)
1078 uint8_t immediate
= (opcode
& 0xff);
1079 uint8_t rotate
= (opcode
& 0xf00);
1081 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1082 address
, opcode
, COND(opcode
), PSR
,
1083 (opcode
& 0x10000) ? "c" : "",
1084 (opcode
& 0x20000) ? "x" : "",
1085 (opcode
& 0x40000) ? "s" : "",
1086 (opcode
& 0x80000) ? "f" : "",
1087 ror(immediate
, (rotate
* 2))
1090 else /* register variant */
1092 uint8_t Rm
= opcode
& 0xf;
1093 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1094 address
, opcode
, COND(opcode
), PSR
,
1095 (opcode
& 0x10000) ? "c" : "",
1096 (opcode
& 0x20000) ? "x" : "",
1097 (opcode
& 0x40000) ? "s" : "",
1098 (opcode
& 0x80000) ? "f" : "",
1104 else /* Move status register to register (MRS) */
1108 instruction
->type
= ARM_MRS
;
1109 Rd
= (opcode
& 0x0000f000) >> 12;
1111 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1112 address
, opcode
, COND(opcode
), Rd
, PSR
);
1118 /* Miscellaneous instructions */
1119 int evaluate_misc_instr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1122 if ((opcode
& 0x000000f0) == 0x00000000)
1124 evaluate_mrs_msr(opcode
, address
, instruction
);
1128 if ((opcode
& 0x006000f0) == 0x00200010)
1131 instruction
->type
= ARM_BX
;
1134 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1135 address
, opcode
, COND(opcode
), Rm
);
1137 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1138 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1141 /* BXJ - "Jazelle" support (ARMv5-J) */
1142 if ((opcode
& 0x006000f0) == 0x00200020)
1145 instruction
->type
= ARM_BX
;
1148 snprintf(instruction
->text
, 128,
1149 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1150 address
, opcode
, COND(opcode
), Rm
);
1152 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1153 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1157 if ((opcode
& 0x006000f0) == 0x00600010)
1160 instruction
->type
= ARM_CLZ
;
1162 Rd
= (opcode
& 0xf000) >> 12;
1164 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1165 address
, opcode
, COND(opcode
), Rd
, Rm
);
1169 if ((opcode
& 0x006000f0) == 0x00200030)
1172 instruction
->type
= ARM_BLX
;
1175 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1176 address
, opcode
, COND(opcode
), Rm
);
1178 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1179 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1182 /* Enhanced DSP add/subtracts */
1183 if ((opcode
& 0x0000000f0) == 0x00000050)
1186 char *mnemonic
= NULL
;
1188 Rd
= (opcode
& 0xf000) >> 12;
1189 Rn
= (opcode
& 0xf0000) >> 16;
1191 switch ((opcode
& 0x00600000) >> 21)
1194 instruction
->type
= ARM_QADD
;
1198 instruction
->type
= ARM_QSUB
;
1202 instruction
->type
= ARM_QDADD
;
1206 instruction
->type
= ARM_QDSUB
;
1211 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1212 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1215 /* Software breakpoints */
1216 if ((opcode
& 0x0000000f0) == 0x00000070)
1219 instruction
->type
= ARM_BKPT
;
1220 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1222 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1223 address
, opcode
, immediate
);
1226 /* Enhanced DSP multiplies */
1227 if ((opcode
& 0x000000090) == 0x00000080)
1229 int x
= (opcode
& 0x20) >> 5;
1230 int y
= (opcode
& 0x40) >> 6;
1233 if ((opcode
& 0x00600000) == 0x00000000)
1235 uint8_t Rd
, Rm
, Rs
, Rn
;
1236 instruction
->type
= ARM_SMLAxy
;
1237 Rd
= (opcode
& 0xf0000) >> 16;
1238 Rm
= (opcode
& 0xf);
1239 Rs
= (opcode
& 0xf00) >> 8;
1240 Rn
= (opcode
& 0xf000) >> 12;
1242 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1243 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1248 if ((opcode
& 0x00600000) == 0x00400000)
1250 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1251 instruction
->type
= ARM_SMLAxy
;
1252 RdHi
= (opcode
& 0xf0000) >> 16;
1253 RdLow
= (opcode
& 0xf000) >> 12;
1254 Rm
= (opcode
& 0xf);
1255 Rs
= (opcode
& 0xf00) >> 8;
1257 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1258 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1259 RdLow
, RdHi
, Rm
, Rs
);
1263 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1265 uint8_t Rd
, Rm
, Rs
, Rn
;
1266 instruction
->type
= ARM_SMLAWy
;
1267 Rd
= (opcode
& 0xf0000) >> 16;
1268 Rm
= (opcode
& 0xf);
1269 Rs
= (opcode
& 0xf00) >> 8;
1270 Rn
= (opcode
& 0xf000) >> 12;
1272 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1273 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1278 if ((opcode
& 0x00600000) == 0x00300000)
1281 instruction
->type
= ARM_SMULxy
;
1282 Rd
= (opcode
& 0xf0000) >> 16;
1283 Rm
= (opcode
& 0xf);
1284 Rs
= (opcode
& 0xf00) >> 8;
1286 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1287 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1292 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1295 instruction
->type
= ARM_SMULWy
;
1296 Rd
= (opcode
& 0xf0000) >> 16;
1297 Rm
= (opcode
& 0xf);
1298 Rs
= (opcode
& 0xf00) >> 8;
1300 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1301 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1309 int evaluate_data_proc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1311 uint8_t I
, op
, S
, Rn
, Rd
;
1312 char *mnemonic
= NULL
;
1313 char shifter_operand
[32];
1315 I
= (opcode
& 0x02000000) >> 25;
1316 op
= (opcode
& 0x01e00000) >> 21;
1317 S
= (opcode
& 0x00100000) >> 20;
1319 Rd
= (opcode
& 0xf000) >> 12;
1320 Rn
= (opcode
& 0xf0000) >> 16;
1322 instruction
->info
.data_proc
.Rd
= Rd
;
1323 instruction
->info
.data_proc
.Rn
= Rn
;
1324 instruction
->info
.data_proc
.S
= S
;
1329 instruction
->type
= ARM_AND
;
1333 instruction
->type
= ARM_EOR
;
1337 instruction
->type
= ARM_SUB
;
1341 instruction
->type
= ARM_RSB
;
1345 instruction
->type
= ARM_ADD
;
1349 instruction
->type
= ARM_ADC
;
1353 instruction
->type
= ARM_SBC
;
1357 instruction
->type
= ARM_RSC
;
1361 instruction
->type
= ARM_TST
;
1365 instruction
->type
= ARM_TEQ
;
1369 instruction
->type
= ARM_CMP
;
1373 instruction
->type
= ARM_CMN
;
1377 instruction
->type
= ARM_ORR
;
1381 instruction
->type
= ARM_MOV
;
1385 instruction
->type
= ARM_BIC
;
1389 instruction
->type
= ARM_MVN
;
1394 if (I
) /* immediate shifter operand (#<immediate>)*/
1396 uint8_t immed_8
= opcode
& 0xff;
1397 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1400 immediate
= ror(immed_8
, rotate_imm
* 2);
1402 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1404 instruction
->info
.data_proc
.variant
= 0;
1405 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1407 else /* register-based shifter operand */
1410 shift
= (opcode
& 0x60) >> 5;
1411 Rm
= (opcode
& 0xf);
1413 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1416 shift_imm
= (opcode
& 0xf80) >> 7;
1418 instruction
->info
.data_proc
.variant
= 1;
1419 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1420 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1421 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1423 /* LSR encodes a shift by 32 bit as 0x0 */
1424 if ((shift
== 0x1) && (shift_imm
== 0x0))
1427 /* ASR encodes a shift by 32 bit as 0x0 */
1428 if ((shift
== 0x2) && (shift_imm
== 0x0))
1431 /* ROR by 32 bit is actually a RRX */
1432 if ((shift
== 0x3) && (shift_imm
== 0x0))
1435 if ((shift_imm
== 0x0) && (shift
== 0x0))
1437 snprintf(shifter_operand
, 32, "r%i", Rm
);
1441 if (shift
== 0x0) /* LSL */
1443 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1445 else if (shift
== 0x1) /* LSR */
1447 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1449 else if (shift
== 0x2) /* ASR */
1451 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1453 else if (shift
== 0x3) /* ROR */
1455 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1457 else if (shift
== 0x4) /* RRX */
1459 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1463 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1465 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1467 instruction
->info
.data_proc
.variant
= 2;
1468 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1469 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1470 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1472 if (shift
== 0x0) /* LSL */
1474 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1476 else if (shift
== 0x1) /* LSR */
1478 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1480 else if (shift
== 0x2) /* ASR */
1482 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1484 else if (shift
== 0x3) /* ROR */
1486 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1491 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1493 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1494 address
, opcode
, mnemonic
, COND(opcode
),
1495 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1497 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1499 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1500 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1502 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1503 address
, opcode
, mnemonic
, COND(opcode
),
1504 (S
) ? "S" : "", Rd
, shifter_operand
);
1506 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1508 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1509 address
, opcode
, mnemonic
, COND(opcode
),
1510 Rn
, shifter_operand
);
1516 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1518 /* clear fields, to avoid confusion */
1519 memset(instruction
, 0, sizeof(arm_instruction_t
));
1520 instruction
->opcode
= opcode
;
1521 instruction
->instruction_size
= 4;
1523 /* catch opcodes with condition field [31:28] = b1111 */
1524 if ((opcode
& 0xf0000000) == 0xf0000000)
1526 /* Undefined instruction (or ARMv5E cache preload PLD) */
1527 if ((opcode
& 0x08000000) == 0x00000000)
1528 return evaluate_pld(opcode
, address
, instruction
);
1530 /* Undefined instruction */
1531 if ((opcode
& 0x0e000000) == 0x08000000)
1533 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1534 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1538 /* Branch and branch with link and change to Thumb */
1539 if ((opcode
& 0x0e000000) == 0x0a000000)
1540 return evaluate_blx_imm(opcode
, address
, instruction
);
1542 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1543 /* Coprocessor load/store and double register transfers */
1544 if ((opcode
& 0x0e000000) == 0x0c000000)
1545 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1547 /* Coprocessor data processing */
1548 if ((opcode
& 0x0f000100) == 0x0c000000)
1549 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1551 /* Coprocessor register transfers */
1552 if ((opcode
& 0x0f000010) == 0x0c000010)
1553 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1555 /* Undefined instruction */
1556 if ((opcode
& 0x0f000000) == 0x0f000000)
1558 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1559 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1564 /* catch opcodes with [27:25] = b000 */
1565 if ((opcode
& 0x0e000000) == 0x00000000)
1567 /* Multiplies, extra load/stores */
1568 if ((opcode
& 0x00000090) == 0x00000090)
1569 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1571 /* Miscellaneous instructions */
1572 if ((opcode
& 0x0f900000) == 0x01000000)
1573 return evaluate_misc_instr(opcode
, address
, instruction
);
1575 return evaluate_data_proc(opcode
, address
, instruction
);
1578 /* catch opcodes with [27:25] = b001 */
1579 if ((opcode
& 0x0e000000) == 0x02000000)
1581 /* Undefined instruction */
1582 if ((opcode
& 0x0fb00000) == 0x03000000)
1584 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1585 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1589 /* Move immediate to status register */
1590 if ((opcode
& 0x0fb00000) == 0x03200000)
1591 return evaluate_mrs_msr(opcode
, address
, instruction
);
1593 return evaluate_data_proc(opcode
, address
, instruction
);
1597 /* catch opcodes with [27:25] = b010 */
1598 if ((opcode
& 0x0e000000) == 0x04000000)
1600 /* Load/store immediate offset */
1601 return evaluate_load_store(opcode
, address
, instruction
);
1604 /* catch opcodes with [27:25] = b011 */
1605 if ((opcode
& 0x0e000000) == 0x06000000)
1607 /* Load/store register offset */
1608 if ((opcode
& 0x00000010) == 0x00000000)
1609 return evaluate_load_store(opcode
, address
, instruction
);
1611 /* Architecturally Undefined instruction
1612 * ... don't expect these to ever be used
1614 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1616 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1617 snprintf(instruction
->text
, 128,
1618 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1623 /* "media" instructions */
1624 return evaluate_media(opcode
, address
, instruction
);
1627 /* catch opcodes with [27:25] = b100 */
1628 if ((opcode
& 0x0e000000) == 0x08000000)
1630 /* Load/store multiple */
1631 return evaluate_ldm_stm(opcode
, address
, instruction
);
1634 /* catch opcodes with [27:25] = b101 */
1635 if ((opcode
& 0x0e000000) == 0x0a000000)
1637 /* Branch and branch with link */
1638 return evaluate_b_bl(opcode
, address
, instruction
);
1641 /* catch opcodes with [27:25] = b110 */
1642 if ((opcode
& 0x0e000000) == 0x0a000000)
1644 /* Coprocessor load/store and double register transfers */
1645 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1648 /* catch opcodes with [27:25] = b111 */
1649 if ((opcode
& 0x0e000000) == 0x0e000000)
1651 /* Software interrupt */
1652 if ((opcode
& 0x0f000000) == 0x0f000000)
1653 return evaluate_swi(opcode
, address
, instruction
);
1655 /* Coprocessor data processing */
1656 if ((opcode
& 0x0f000010) == 0x0e000000)
1657 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1659 /* Coprocessor register transfers */
1660 if ((opcode
& 0x0f000010) == 0x0e000010)
1661 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1664 LOG_ERROR("should never reach this point");
1668 int evaluate_b_bl_blx_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1670 uint32_t offset
= opcode
& 0x7ff;
1671 uint32_t opc
= (opcode
>> 11) & 0x3;
1672 uint32_t target_address
;
1673 char *mnemonic
= NULL
;
1675 /* sign extend 11-bit offset */
1676 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1677 offset
= 0xfffff800 | offset
;
1679 target_address
= address
+ 4 + (offset
<< 1);
1683 /* unconditional branch */
1685 instruction
->type
= ARM_B
;
1690 instruction
->type
= ARM_BLX
;
1695 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1696 mnemonic
= "prefix";
1697 target_address
= offset
<< 12;
1701 instruction
->type
= ARM_BL
;
1706 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1707 * these are effectively 32-bit instructions even in Thumb1.
1708 * Might be simplest to always use the Thumb2 decoder.
1711 snprintf(instruction
->text
, 128,
1712 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1713 address
, opcode
, mnemonic
, target_address
);
1715 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1716 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1721 int evaluate_add_sub_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1723 uint8_t Rd
= (opcode
>> 0) & 0x7;
1724 uint8_t Rn
= (opcode
>> 3) & 0x7;
1725 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1726 uint32_t opc
= opcode
& (1 << 9);
1727 uint32_t reg_imm
= opcode
& (1 << 10);
1732 instruction
->type
= ARM_SUB
;
1737 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1738 instruction
->type
= ARM_ADD
;
1742 instruction
->info
.data_proc
.Rd
= Rd
;
1743 instruction
->info
.data_proc
.Rn
= Rn
;
1744 instruction
->info
.data_proc
.S
= 1;
1748 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1749 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1750 snprintf(instruction
->text
, 128,
1751 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1752 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1756 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1757 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1758 snprintf(instruction
->text
, 128,
1759 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1760 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1766 int evaluate_shift_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1768 uint8_t Rd
= (opcode
>> 0) & 0x7;
1769 uint8_t Rm
= (opcode
>> 3) & 0x7;
1770 uint8_t imm
= (opcode
>> 6) & 0x1f;
1771 uint8_t opc
= (opcode
>> 11) & 0x3;
1772 char *mnemonic
= NULL
;
1777 instruction
->type
= ARM_MOV
;
1779 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1782 instruction
->type
= ARM_MOV
;
1784 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1787 instruction
->type
= ARM_MOV
;
1789 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1793 if ((imm
== 0) && (opc
!= 0))
1796 instruction
->info
.data_proc
.Rd
= Rd
;
1797 instruction
->info
.data_proc
.Rn
= -1;
1798 instruction
->info
.data_proc
.S
= 1;
1800 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1801 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1802 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1804 snprintf(instruction
->text
, 128,
1805 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1806 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1811 int evaluate_data_proc_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1813 uint8_t imm
= opcode
& 0xff;
1814 uint8_t Rd
= (opcode
>> 8) & 0x7;
1815 uint32_t opc
= (opcode
>> 11) & 0x3;
1816 char *mnemonic
= NULL
;
1818 instruction
->info
.data_proc
.Rd
= Rd
;
1819 instruction
->info
.data_proc
.Rn
= Rd
;
1820 instruction
->info
.data_proc
.S
= 1;
1821 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1822 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1827 instruction
->type
= ARM_MOV
;
1829 instruction
->info
.data_proc
.Rn
= -1;
1832 instruction
->type
= ARM_CMP
;
1834 instruction
->info
.data_proc
.Rd
= -1;
1837 instruction
->type
= ARM_ADD
;
1841 instruction
->type
= ARM_SUB
;
1846 snprintf(instruction
->text
, 128,
1847 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1848 address
, opcode
, mnemonic
, Rd
, imm
);
1853 int evaluate_data_proc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1855 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1856 char *mnemonic
= NULL
;
1859 high_reg
= (opcode
& 0x0400) >> 10;
1860 op
= (opcode
& 0x03C0) >> 6;
1862 Rd
= (opcode
& 0x0007);
1863 Rm
= (opcode
& 0x0038) >> 3;
1864 H1
= (opcode
& 0x0080) >> 7;
1865 H2
= (opcode
& 0x0040) >> 6;
1867 instruction
->info
.data_proc
.Rd
= Rd
;
1868 instruction
->info
.data_proc
.Rn
= Rd
;
1869 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1870 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1871 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1882 instruction
->type
= ARM_ADD
;
1886 instruction
->type
= ARM_CMP
;
1890 instruction
->type
= ARM_MOV
;
1896 if ((opcode
& 0x7) == 0x0)
1898 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1901 instruction
->type
= ARM_BLX
;
1902 snprintf(instruction
->text
, 128,
1904 " 0x%4.4x \tBLX\tr%i",
1905 address
, opcode
, Rm
);
1909 instruction
->type
= ARM_BX
;
1910 snprintf(instruction
->text
, 128,
1912 " 0x%4.4x \tBX\tr%i",
1913 address
, opcode
, Rm
);
1918 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1919 snprintf(instruction
->text
, 128,
1922 "UNDEFINED INSTRUCTION",
1934 instruction
->type
= ARM_AND
;
1938 instruction
->type
= ARM_EOR
;
1942 instruction
->type
= ARM_MOV
;
1944 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1945 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1946 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1947 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1950 instruction
->type
= ARM_MOV
;
1952 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1953 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1954 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1955 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1958 instruction
->type
= ARM_MOV
;
1960 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1961 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1962 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1963 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1966 instruction
->type
= ARM_ADC
;
1970 instruction
->type
= ARM_SBC
;
1974 instruction
->type
= ARM_MOV
;
1976 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1977 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1978 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1979 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1982 instruction
->type
= ARM_TST
;
1986 instruction
->type
= ARM_RSB
;
1988 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1989 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1990 instruction
->info
.data_proc
.Rn
= Rm
;
1993 instruction
->type
= ARM_CMP
;
1997 instruction
->type
= ARM_CMN
;
2001 instruction
->type
= ARM_ORR
;
2005 instruction
->type
= ARM_MUL
;
2009 instruction
->type
= ARM_BIC
;
2013 instruction
->type
= ARM_MVN
;
2020 snprintf(instruction
->text
, 128,
2021 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2023 address
, opcode
, mnemonic
, Rd
, Rm
);
2025 snprintf(instruction
->text
, 128,
2026 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2027 address
, opcode
, mnemonic
, Rd
, Rm
);
2032 /* PC-relative data addressing is word-aligned even with Thumb */
2033 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2035 return (addr
+ 4) & ~3;
2038 int evaluate_load_literal_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2041 uint8_t Rd
= (opcode
>> 8) & 0x7;
2043 instruction
->type
= ARM_LDR
;
2044 immediate
= opcode
& 0x000000ff;
2047 instruction
->info
.load_store
.Rd
= Rd
;
2048 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2049 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2050 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2051 instruction
->info
.load_store
.offset
.offset
= immediate
;
2053 snprintf(instruction
->text
, 128,
2054 "0x%8.8" PRIx32
" 0x%4.4x \t"
2055 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2056 address
, opcode
, Rd
, immediate
,
2057 thumb_alignpc4(address
) + immediate
);
2062 int evaluate_load_store_reg_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2064 uint8_t Rd
= (opcode
>> 0) & 0x7;
2065 uint8_t Rn
= (opcode
>> 3) & 0x7;
2066 uint8_t Rm
= (opcode
>> 6) & 0x7;
2067 uint8_t opc
= (opcode
>> 9) & 0x7;
2068 char *mnemonic
= NULL
;
2073 instruction
->type
= ARM_STR
;
2077 instruction
->type
= ARM_STRH
;
2081 instruction
->type
= ARM_STRB
;
2085 instruction
->type
= ARM_LDRSB
;
2089 instruction
->type
= ARM_LDR
;
2093 instruction
->type
= ARM_LDRH
;
2097 instruction
->type
= ARM_LDRB
;
2101 instruction
->type
= ARM_LDRSH
;
2106 snprintf(instruction
->text
, 128,
2107 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2108 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2110 instruction
->info
.load_store
.Rd
= Rd
;
2111 instruction
->info
.load_store
.Rn
= Rn
;
2112 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2113 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2114 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2119 int evaluate_load_store_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2121 uint32_t offset
= (opcode
>> 6) & 0x1f;
2122 uint8_t Rd
= (opcode
>> 0) & 0x7;
2123 uint8_t Rn
= (opcode
>> 3) & 0x7;
2124 uint32_t L
= opcode
& (1 << 11);
2125 uint32_t B
= opcode
& (1 << 12);
2132 instruction
->type
= ARM_LDR
;
2137 instruction
->type
= ARM_STR
;
2141 if ((opcode
&0xF000) == 0x8000)
2152 snprintf(instruction
->text
, 128,
2153 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2154 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2156 instruction
->info
.load_store
.Rd
= Rd
;
2157 instruction
->info
.load_store
.Rn
= Rn
;
2158 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2159 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2160 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2165 int evaluate_load_store_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2167 uint32_t offset
= opcode
& 0xff;
2168 uint8_t Rd
= (opcode
>> 8) & 0x7;
2169 uint32_t L
= opcode
& (1 << 11);
2174 instruction
->type
= ARM_LDR
;
2179 instruction
->type
= ARM_STR
;
2183 snprintf(instruction
->text
, 128,
2184 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2185 address
, opcode
, mnemonic
, Rd
, offset
*4);
2187 instruction
->info
.load_store
.Rd
= Rd
;
2188 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2189 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2190 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2191 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2196 int evaluate_add_sp_pc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2198 uint32_t imm
= opcode
& 0xff;
2199 uint8_t Rd
= (opcode
>> 8) & 0x7;
2201 uint32_t SP
= opcode
& (1 << 11);
2204 instruction
->type
= ARM_ADD
;
2217 snprintf(instruction
->text
, 128,
2218 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2219 address
, opcode
, Rd
, reg_name
, imm
* 4);
2221 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2222 instruction
->info
.data_proc
.Rd
= Rd
;
2223 instruction
->info
.data_proc
.Rn
= Rn
;
2224 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2229 int evaluate_adjust_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2231 uint32_t imm
= opcode
& 0x7f;
2232 uint8_t opc
= opcode
& (1 << 7);
2238 instruction
->type
= ARM_SUB
;
2243 instruction
->type
= ARM_ADD
;
2247 snprintf(instruction
->text
, 128,
2248 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2249 address
, opcode
, mnemonic
, imm
*4);
2251 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2252 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2253 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2254 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2259 int evaluate_breakpoint_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2261 uint32_t imm
= opcode
& 0xff;
2263 instruction
->type
= ARM_BKPT
;
2265 snprintf(instruction
->text
, 128,
2266 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2267 address
, opcode
, imm
);
2272 int evaluate_load_store_multiple_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2274 uint32_t reg_list
= opcode
& 0xff;
2275 uint32_t L
= opcode
& (1 << 11);
2276 uint32_t R
= opcode
& (1 << 8);
2277 uint8_t Rn
= (opcode
>> 8) & 7;
2278 uint8_t addr_mode
= 0 /* IA */;
2282 char ptr_name
[7] = "";
2285 if ((opcode
& 0xf000) == 0xc000)
2286 { /* generic load/store multiple */
2291 instruction
->type
= ARM_LDM
;
2293 if (opcode
& (1 << Rn
))
2298 instruction
->type
= ARM_STM
;
2301 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2308 instruction
->type
= ARM_LDM
;
2311 reg_list
|= (1 << 15) /*PC*/;
2315 instruction
->type
= ARM_STM
;
2317 addr_mode
= 3; /*DB*/
2319 reg_list
|= (1 << 14) /*LR*/;
2323 reg_names_p
= reg_names
;
2324 for (i
= 0; i
<= 15; i
++)
2326 if (reg_list
& (1 << i
))
2327 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2329 if (reg_names_p
> reg_names
)
2330 reg_names_p
[-2] = '\0';
2331 else /* invalid op : no registers */
2332 reg_names
[0] = '\0';
2334 snprintf(instruction
->text
, 128,
2335 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2336 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2338 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2339 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2340 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2345 int evaluate_cond_branch_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2347 uint32_t offset
= opcode
& 0xff;
2348 uint8_t cond
= (opcode
>> 8) & 0xf;
2349 uint32_t target_address
;
2353 instruction
->type
= ARM_SWI
;
2354 snprintf(instruction
->text
, 128,
2355 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2356 address
, opcode
, offset
);
2359 else if (cond
== 0xe)
2361 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2362 snprintf(instruction
->text
, 128,
2363 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2368 /* sign extend 8-bit offset */
2369 if (offset
& 0x00000080)
2370 offset
= 0xffffff00 | offset
;
2372 target_address
= address
+ 4 + (offset
<< 1);
2374 snprintf(instruction
->text
, 128,
2375 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2377 arm_condition_strings
[cond
], target_address
);
2379 instruction
->type
= ARM_B
;
2380 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2381 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2386 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2387 arm_instruction_t
*instruction
)
2391 /* added in Thumb2 */
2392 offset
= (opcode
>> 3) & 0x1f;
2393 offset
|= (opcode
& 0x0200) >> 4;
2395 snprintf(instruction
->text
, 128,
2396 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2398 (opcode
& 0x0800) ? "N" : "",
2399 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2404 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2405 arm_instruction_t
*instruction
)
2407 /* added in ARMv6 */
2408 snprintf(instruction
->text
, 128,
2409 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2411 (opcode
& 0x0080) ? 'U' : 'S',
2412 (opcode
& 0x0040) ? 'B' : 'H',
2413 opcode
& 0x7, (opcode
>> 3) & 0x7);
2418 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2419 arm_instruction_t
*instruction
)
2421 /* added in ARMv6 */
2422 if ((opcode
& 0x0ff0) == 0x0650)
2423 snprintf(instruction
->text
, 128,
2424 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2426 (opcode
& 0x80) ? "BE" : "LE");
2427 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2428 snprintf(instruction
->text
, 128,
2429 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2431 (opcode
& 0x0010) ? 'D' : 'E',
2432 (opcode
& 0x0004) ? "A" : "",
2433 (opcode
& 0x0002) ? "I" : "",
2434 (opcode
& 0x0001) ? "F" : "");
2439 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2440 arm_instruction_t
*instruction
)
2444 /* added in ARMv6 */
2445 switch ((opcode
>> 6) & 3) {
2456 snprintf(instruction
->text
, 128,
2457 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2458 address
, opcode
, suffix
,
2459 opcode
& 0x7, (opcode
>> 3) & 0x7);
2464 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2465 arm_instruction_t
*instruction
)
2469 switch ((opcode
>> 4) & 0x0f) {
2486 hint
= "HINT (UNRECOGNIZED)";
2490 snprintf(instruction
->text
, 128,
2491 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2492 address
, opcode
, hint
);
2497 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2498 arm_instruction_t
*instruction
)
2500 unsigned cond
= (opcode
>> 4) & 0x0f;
2501 char *x
= "", *y
= "", *z
= "";
2504 z
= (opcode
& 0x02) ? "T" : "E";
2506 y
= (opcode
& 0x04) ? "T" : "E";
2508 x
= (opcode
& 0x08) ? "T" : "E";
2510 snprintf(instruction
->text
, 128,
2511 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2513 x
, y
, z
, arm_condition_strings
[cond
]);
2515 /* NOTE: strictly speaking, the next 1-4 instructions should
2516 * now be displayed with the relevant conditional suffix...
2522 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2524 /* clear fields, to avoid confusion */
2525 memset(instruction
, 0, sizeof(arm_instruction_t
));
2526 instruction
->opcode
= opcode
;
2527 instruction
->instruction_size
= 2;
2529 if ((opcode
& 0xe000) == 0x0000)
2531 /* add/substract register or immediate */
2532 if ((opcode
& 0x1800) == 0x1800)
2533 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2534 /* shift by immediate */
2536 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2539 /* Add/substract/compare/move immediate */
2540 if ((opcode
& 0xe000) == 0x2000)
2542 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2545 /* Data processing instructions */
2546 if ((opcode
& 0xf800) == 0x4000)
2548 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2551 /* Load from literal pool */
2552 if ((opcode
& 0xf800) == 0x4800)
2554 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2557 /* Load/Store register offset */
2558 if ((opcode
& 0xf000) == 0x5000)
2560 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2563 /* Load/Store immediate offset */
2564 if (((opcode
& 0xe000) == 0x6000)
2565 ||((opcode
& 0xf000) == 0x8000))
2567 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2570 /* Load/Store from/to stack */
2571 if ((opcode
& 0xf000) == 0x9000)
2573 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2577 if ((opcode
& 0xf000) == 0xa000)
2579 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2583 if ((opcode
& 0xf000) == 0xb000)
2585 switch ((opcode
>> 8) & 0x0f) {
2587 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2592 return evaluate_cb_thumb(opcode
, address
, instruction
);
2594 return evaluate_extend_thumb(opcode
, address
, instruction
);
2599 return evaluate_load_store_multiple_thumb(opcode
, address
,
2602 return evaluate_cps_thumb(opcode
, address
, instruction
);
2604 if ((opcode
& 0x00c0) == 0x0080)
2606 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2608 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2610 if (opcode
& 0x000f)
2611 return evaluate_ifthen_thumb(opcode
, address
,
2614 return evaluate_hint_thumb(opcode
, address
,
2618 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2619 snprintf(instruction
->text
, 128,
2620 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2625 /* Load/Store multiple */
2626 if ((opcode
& 0xf000) == 0xc000)
2628 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2631 /* Conditional branch + SWI */
2632 if ((opcode
& 0xf000) == 0xd000)
2634 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2637 if ((opcode
& 0xe000) == 0xe000)
2639 /* Undefined instructions */
2640 if ((opcode
& 0xf801) == 0xe801)
2642 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2643 snprintf(instruction
->text
, 128,
2644 "0x%8.8" PRIx32
" 0x%8.8x\t"
2645 "UNDEFINED INSTRUCTION",
2650 { /* Branch to offset */
2651 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2655 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2659 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2660 arm_instruction_t
*instruction
, char *cp
)
2663 unsigned b21
= 1 << 21;
2664 unsigned b22
= 1 << 22;
2666 /* instead of combining two smaller 16-bit branch instructions,
2667 * Thumb2 uses only one larger 32-bit instruction.
2669 offset
= opcode
& 0x7ff;
2670 offset
|= (opcode
& 0x03ff0000) >> 5;
2671 if (opcode
& (1 << 26)) {
2672 offset
|= 0xff << 23;
2673 if ((opcode
& (1 << 11)) == 0)
2675 if ((opcode
& (1 << 13)) == 0)
2678 if (opcode
& (1 << 11))
2680 if (opcode
& (1 << 13))
2688 address
+= offset
<< 1;
2690 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2691 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2692 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2693 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2694 (opcode
& (1 << 14)) ? "BL" : "B.W",
2700 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2701 arm_instruction_t
*instruction
, char *cp
)
2704 unsigned b17
= 1 << 17;
2705 unsigned b18
= 1 << 18;
2706 unsigned cond
= (opcode
>> 22) & 0x0f;
2708 offset
= opcode
& 0x7ff;
2709 offset
|= (opcode
& 0x003f0000) >> 5;
2710 if (opcode
& (1 << 26)) {
2711 offset
|= 0xffff << 19;
2712 if ((opcode
& (1 << 11)) == 0)
2714 if ((opcode
& (1 << 13)) == 0)
2717 if (opcode
& (1 << 11))
2719 if (opcode
& (1 << 13))
2726 address
+= offset
<< 1;
2728 instruction
->type
= ARM_B
;
2729 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2730 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2731 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2732 arm_condition_strings
[cond
],
2738 static const char *special_name(int number
)
2740 char *special
= "(RESERVED)";
2771 special
= "primask";
2774 special
= "basepri";
2777 special
= "basepri_max";
2780 special
= "faultmask";
2783 special
= "control";
2789 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2790 arm_instruction_t
*instruction
, char *cp
)
2792 const char *mnemonic
;
2794 if (opcode
& 0x0700) {
2795 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2796 strcpy(cp
, "UNDEFINED");
2800 if (opcode
& 0x00f0) {
2801 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2805 switch (opcode
& 0x0f) {
2810 mnemonic
= "YIELD.W";
2822 mnemonic
= "HINT.W (UNRECOGNIZED)";
2825 strcpy(cp
, mnemonic
);
2829 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2830 arm_instruction_t
*instruction
, char *cp
)
2832 const char *mnemonic
;
2834 switch ((opcode
>> 4) & 0x0f) {
2848 return ERROR_INVALID_ARGUMENTS
;
2850 strcpy(cp
, mnemonic
);
2854 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2855 arm_instruction_t
*instruction
, char *cp
)
2857 /* permanently undefined */
2858 if ((opcode
& 0x07f07000) == 0x07f02000) {
2859 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2860 strcpy(cp
, "UNDEFINED");
2864 switch ((opcode
>> 12) & 0x5) {
2867 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2871 if (((opcode
>> 23) & 0x07) != 0x07)
2872 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2873 if (opcode
& (1 << 26))
2878 switch ((opcode
>> 20) & 0x7f) {
2881 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2882 (int) (opcode
>> 16) & 0x0f);
2885 return t2ev_hint(opcode
, address
, instruction
, cp
);
2887 return t2ev_misc(opcode
, address
, instruction
, cp
);
2890 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
2891 special_name(opcode
& 0xff));
2896 return ERROR_INVALID_ARGUMENTS
;
2899 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
2900 arm_instruction_t
*instruction
, char *cp
)
2902 char *mnemonic
= NULL
;
2903 int rn
= (opcode
>> 16) & 0xf;
2904 int rd
= (opcode
>> 8) & 0xf;
2905 unsigned immed
= opcode
& 0xff;
2911 /* ARMv7-M: A5.3.2 Modified immediate constants */
2912 func
= (opcode
>> 11) & 0x0e;
2915 if (opcode
& (1 << 26))
2918 /* "Modified" immediates */
2919 switch (func
>> 1) {
2926 immed
+= immed
<< 16;
2929 immed
+= immed
<< 8;
2930 immed
+= immed
<< 16;
2934 immed
= ror(immed
, func
);
2937 if (opcode
& (1 << 20))
2940 switch ((opcode
>> 21) & 0xf) {
2943 instruction
->type
= ARM_TST
;
2949 instruction
->type
= ARM_AND
;
2954 instruction
->type
= ARM_BIC
;
2959 instruction
->type
= ARM_MOV
;
2964 instruction
->type
= ARM_ORR
;
2970 instruction
->type
= ARM_MVN
;
2974 // instruction->type = ARM_ORN;
2980 instruction
->type
= ARM_TEQ
;
2986 instruction
->type
= ARM_EOR
;
2992 instruction
->type
= ARM_CMN
;
2998 instruction
->type
= ARM_ADD
;
3004 instruction
->type
= ARM_ADC
;
3009 instruction
->type
= ARM_SBC
;
3014 instruction
->type
= ARM_CMP
;
3020 instruction
->type
= ARM_SUB
;
3026 instruction
->type
= ARM_RSB
;
3031 return ERROR_INVALID_ARGUMENTS
;
3035 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3036 mnemonic
, suffix2
,rd
, immed
, immed
);
3038 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3039 mnemonic
, suffix
, suffix2
,
3040 rd
, rn
, immed
, immed
);
3045 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3046 arm_instruction_t
*instruction
, char *cp
)
3048 char *mnemonic
= NULL
;
3049 int rn
= (opcode
>> 16) & 0xf;
3050 int rd
= (opcode
>> 8) & 0xf;
3053 bool is_signed
= false;
3055 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3056 if (opcode
& (1 << 26))
3059 switch ((opcode
>> 20) & 0x1f) {
3068 immed
|= (opcode
>> 4) & 0xf000;
3069 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3077 /* move constant to top 16 bits of register */
3078 immed
|= (opcode
>> 4) & 0xf000;
3079 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3086 /* signed/unsigned saturated add */
3087 immed
= (opcode
>> 6) & 0x03;
3088 immed
|= (opcode
>> 10) & 0x1c;
3089 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3090 is_signed
? "S" : "U",
3091 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3092 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3093 immed
? immed
: 32);
3099 /* signed/unsigned bitfield extract */
3100 immed
= (opcode
>> 6) & 0x03;
3101 immed
|= (opcode
>> 10) & 0x1c;
3102 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3103 is_signed
? "S" : "U",
3105 (int) (opcode
& 0x1f) + 1);
3108 immed
= (opcode
>> 6) & 0x03;
3109 immed
|= (opcode
>> 10) & 0x1c;
3110 if (rn
== 0xf) /* bitfield clear */
3111 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3113 (int) (opcode
& 0x1f) + 1 - immed
);
3114 else /* bitfield insert */
3115 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3117 (int) (opcode
& 0x1f) + 1 - immed
);
3120 return ERROR_INVALID_ARGUMENTS
;
3123 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3124 rd
, rn
, immed
, immed
);
3128 address
= thumb_alignpc4(address
);
3133 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3134 * not hiding the pc-relative stuff will sometimes be useful.
3136 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3140 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3141 arm_instruction_t
*instruction
, char *cp
)
3143 unsigned op
= (opcode
>> 20) & 0xf;
3149 unsigned rn
= (opcode
>> 16) & 0x0f;
3150 unsigned rt
= (opcode
>> 12) & 0x0f;
3153 return ERROR_INVALID_ARGUMENTS
;
3155 if (opcode
& 0x0800)
3190 return ERROR_INVALID_ARGUMENTS
;
3193 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3194 size
, rt
, rn
, (int) opcode
& 0x0f,
3195 (int) (opcode
>> 4) & 0x03);
3199 immed
= opcode
& 0x0fff;
3200 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3201 size
, rt
, rn
, immed
, immed
);
3205 immed
= opcode
& 0x00ff;
3207 switch (opcode
& 0x700) {
3213 return ERROR_INVALID_ARGUMENTS
;
3216 /* two indexed modes will write back rn */
3217 if (opcode
& 0x100) {
3218 if (opcode
& 0x400) /* pre-indexed */
3220 else { /* post-indexed */
3226 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3227 size
, suffix
, rt
, rn
, p1
,
3228 (opcode
& 0x200) ? "" : "-",
3233 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3234 arm_instruction_t
*instruction
, char *cp
)
3236 int ra
= (opcode
>> 12) & 0xf;
3238 switch (opcode
& 0x007000f0) {
3241 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3242 (int) (opcode
>> 8) & 0xf,
3243 (int) (opcode
>> 16) & 0xf,
3244 (int) (opcode
>> 0) & 0xf);
3246 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3247 (int) (opcode
>> 8) & 0xf,
3248 (int) (opcode
>> 16) & 0xf,
3249 (int) (opcode
>> 0) & 0xf, ra
);
3252 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3253 (int) (opcode
>> 8) & 0xf,
3254 (int) (opcode
>> 16) & 0xf,
3255 (int) (opcode
>> 0) & 0xf, ra
);
3258 return ERROR_INVALID_ARGUMENTS
;
3263 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3264 arm_instruction_t
*instruction
, char *cp
)
3266 int op
= (opcode
>> 4) & 0xf;
3267 char *infix
= "MUL";
3269 op
+= (opcode
>> 16) & 0x70;
3277 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3278 (op
& 0x20) ? 'U' : 'S',
3280 (int) (opcode
>> 12) & 0xf,
3281 (int) (opcode
>> 8) & 0xf,
3282 (int) (opcode
>> 16) & 0xf,
3283 (int) (opcode
>> 0) & 0xf);
3287 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3288 (op
& 0x20) ? 'U' : 'S',
3289 (int) (opcode
>> 8) & 0xf,
3290 (int) (opcode
>> 16) & 0xf,
3291 (int) (opcode
>> 0) & 0xf);
3294 return ERROR_INVALID_ARGUMENTS
;
3300 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3301 arm_instruction_t
*instruction
, char *cp
)
3303 int rn
= (opcode
>> 16) & 0xf;
3304 int op
= (opcode
>> 22) & 0x6;
3305 int t
= (opcode
>> 21) & 1;
3306 unsigned registers
= opcode
& 0xffff;
3308 if (opcode
& (1 << 20))
3313 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3317 sprintf(cp
, "POP.W\t");
3319 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3323 sprintf(cp
, "PUSH.W\t");
3325 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3328 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3331 return ERROR_INVALID_ARGUMENTS
;
3336 for (t
= 0; registers
; t
++, registers
>>= 1) {
3337 if ((registers
& 1) == 0)
3340 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3349 /* load/store dual or exclusive, table branch */
3350 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3351 arm_instruction_t
*instruction
, char *cp
)
3353 unsigned op1op2
= (opcode
>> 20) & 0x3;
3354 unsigned op3
= (opcode
>> 4) & 0xf;
3356 unsigned rn
= (opcode
>> 16) & 0xf;
3357 unsigned rt
= (opcode
>> 12) & 0xf;
3358 unsigned rd
= (opcode
>> 8) & 0xf;
3359 unsigned imm
= opcode
& 0xff;
3363 op1op2
|= (opcode
>> 21) & 0xc;
3393 mnemonic
= "STREXB";
3396 mnemonic
= "STREXH";
3399 return ERROR_INVALID_ARGUMENTS
;
3407 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3410 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3413 mnemonic
= "LDREXB";
3416 mnemonic
= "LDREXH";
3419 return ERROR_INVALID_ARGUMENTS
;
3424 return ERROR_INVALID_ARGUMENTS
;
3429 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3430 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3432 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3433 mnemonic
, rd
, rt
, rn
);
3439 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3440 mnemonic
, rt
, rn
, imm
, imm
);
3442 sprintf(cp
, "%s\tr%u, [r%u]",
3447 /* two indexed modes will write back rn */
3448 if (opcode
& (1 << 21)) {
3449 if (opcode
& (1 << 24)) /* pre-indexed */
3451 else { /* post-indexed */
3458 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3459 mnemonic
, rt
, rd
, rn
, p1
,
3460 (opcode
& (1 << 23)) ? "" : "-",
3465 address
= thumb_alignpc4(address
);
3467 if (opcode
& (1 << 23))
3471 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3472 mnemonic
, rt
, rd
, address
);
3476 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3477 arm_instruction_t
*instruction
, char *cp
)
3479 int op
= (opcode
>> 21) & 0xf;
3480 int rd
= (opcode
>> 8) & 0xf;
3481 int rn
= (opcode
>> 16) & 0xf;
3482 int type
= (opcode
>> 4) & 0x3;
3483 int immed
= (opcode
>> 6) & 0x3;
3487 immed
|= (opcode
>> 10) & 0x1c;
3488 if (opcode
& (1 << 20))
3494 if (!(opcode
& (1 << 20)))
3495 return ERROR_INVALID_ARGUMENTS
;
3496 instruction
->type
= ARM_TST
;
3501 instruction
->type
= ARM_AND
;
3505 instruction
->type
= ARM_BIC
;
3510 instruction
->type
= ARM_MOV
;
3514 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3516 (int) (opcode
& 0xf));
3529 sprintf(cp
, "RRX%s\tr%d, r%d",
3531 (int) (opcode
& 0xf));
3539 instruction
->type
= ARM_ORR
;
3545 instruction
->type
= ARM_MVN
;
3550 // instruction->type = ARM_ORN;
3556 if (!(opcode
& (1 << 20)))
3557 return ERROR_INVALID_ARGUMENTS
;
3558 instruction
->type
= ARM_TEQ
;
3563 instruction
->type
= ARM_EOR
;
3568 if (!(opcode
& (1 << 20)))
3569 return ERROR_INVALID_ARGUMENTS
;
3570 instruction
->type
= ARM_CMN
;
3575 instruction
->type
= ARM_ADD
;
3579 instruction
->type
= ARM_ADC
;
3583 instruction
->type
= ARM_SBC
;
3588 if (!(opcode
& (1 << 21)))
3589 return ERROR_INVALID_ARGUMENTS
;
3590 instruction
->type
= ARM_CMP
;
3595 instruction
->type
= ARM_SUB
;
3599 instruction
->type
= ARM_RSB
;
3603 return ERROR_INVALID_ARGUMENTS
;
3606 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3607 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3630 strcpy(cp
, ", RRX");
3636 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3640 sprintf(cp
, "%s%s.W\tr%d, r%d",
3641 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3645 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3646 mnemonic
, suffix
, rd
,
3647 (int) (opcode
& 0xf), immed
? immed
: 32);
3651 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3652 arm_instruction_t
*instruction
, char *cp
)
3657 if (((opcode
>> 4) & 0xf) == 0) {
3658 switch ((opcode
>> 21) & 0x7) {
3672 return ERROR_INVALID_ARGUMENTS
;
3675 instruction
->type
= ARM_MOV
;
3676 if (opcode
& (1 << 20))
3678 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3680 (int) (opcode
>> 8) & 0xf,
3681 (int) (opcode
>> 16) & 0xf,
3682 (int) (opcode
>> 0) & 0xf);
3684 } else if (opcode
& (1 << 7)) {
3685 switch ((opcode
>> 20) & 0xf) {
3690 switch ((opcode
>> 4) & 0x3) {
3692 suffix
= ", ROR #8";
3695 suffix
= ", ROR #16";
3698 suffix
= ", ROR #24";
3701 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3702 (opcode
& (1 << 24)) ? 'U' : 'S',
3703 (opcode
& (1 << 26)) ? 'B' : 'H',
3704 (int) (opcode
>> 8) & 0xf,
3705 (int) (opcode
>> 0) & 0xf,
3712 if (opcode
& (1 << 6))
3713 return ERROR_INVALID_ARGUMENTS
;
3714 if (((opcode
>> 12) & 0xf) != 0xf)
3715 return ERROR_INVALID_ARGUMENTS
;
3716 if (!(opcode
& (1 << 20)))
3717 return ERROR_INVALID_ARGUMENTS
;
3719 switch (((opcode
>> 19) & 0x04)
3720 | ((opcode
>> 4) & 0x3)) {
3725 mnemonic
= "REV16.W";
3731 mnemonic
= "REVSH.W";
3737 return ERROR_INVALID_ARGUMENTS
;
3739 sprintf(cp
, "%s\tr%d, r%d",
3741 (int) (opcode
>> 8) & 0xf,
3742 (int) (opcode
>> 0) & 0xf);
3745 return ERROR_INVALID_ARGUMENTS
;
3752 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3753 arm_instruction_t
*instruction
, char *cp
)
3755 int rn
= (opcode
>> 16) & 0xf;
3758 instruction
->type
= ARM_LDR
;
3761 immed
= opcode
& 0x0fff;
3762 if ((opcode
& (1 << 23)) == 0)
3764 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3765 (int) (opcode
>> 12) & 0xf,
3766 thumb_alignpc4(address
) + immed
);
3770 if (opcode
& (1 << 23)) {
3771 immed
= opcode
& 0x0fff;
3772 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3773 (int) (opcode
>> 12) & 0xf,
3778 if (!(opcode
& (0x3f << 6))) {
3779 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3780 (int) (opcode
>> 12) & 0xf,
3782 (int) (opcode
>> 0) & 0xf,
3783 (int) (opcode
>> 4) & 0x3);
3788 if (((opcode
>> 8) & 0xf) == 0xe) {
3789 immed
= opcode
& 0x00ff;
3791 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3792 (int) (opcode
>> 12) & 0xf,
3797 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3798 char *p1
= "]", *p2
= "";
3800 if (!(opcode
& 0x0500))
3801 return ERROR_INVALID_ARGUMENTS
;
3803 immed
= opcode
& 0x00ff;
3805 /* two indexed modes will write back rn */
3806 if (opcode
& 0x100) {
3807 if (opcode
& 0x400) /* pre-indexed */
3809 else { /* post-indexed */
3815 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3816 (int) (opcode
>> 12) & 0xf,
3818 (opcode
& 0x200) ? "" : "-",
3823 return ERROR_INVALID_ARGUMENTS
;
3826 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3827 arm_instruction_t
*instruction
, char *cp
)
3829 int rn
= (opcode
>> 16) & 0xf;
3830 int rt
= (opcode
>> 12) & 0xf;
3831 int op2
= (opcode
>> 6) & 0x3f;
3833 char *p1
= "", *p2
= "]";
3836 switch ((opcode
>> 23) & 0x3) {
3838 if ((rn
& rt
) == 0xf) {
3840 immed
= opcode
& 0xfff;
3841 address
= thumb_alignpc4(address
);
3842 if (opcode
& (1 << 23))
3846 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
3850 if (rn
== 0x0f && rt
!= 0x0f) {
3852 immed
= opcode
& 0xfff;
3853 address
= thumb_alignpc4(address
);
3854 if (opcode
& (1 << 23))
3858 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
3864 if ((op2
& 0x3c) == 0x38) {
3865 immed
= opcode
& 0xff;
3866 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3867 rt
, rn
, immed
, immed
);
3870 if ((op2
& 0x3c) == 0x30) {
3872 immed
= opcode
& 0xff;
3875 p1
= (opcode
& (1 << 21)) ? "W" : "";
3876 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3877 p1
, rn
, immed
, immed
);
3882 immed
= opcode
& 0xff;
3883 if (!(opcode
& 0x200))
3886 /* two indexed modes will write back rn */
3887 if (opcode
& 0x100) {
3888 if (opcode
& 0x400) /* pre-indexed */
3890 else { /* post-indexed */
3896 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3897 mnemonic
, rt
, rn
, p1
,
3901 if ((op2
& 0x24) == 0x24) {
3903 goto ldrxb_immediate_t3
;
3906 int rm
= opcode
& 0xf;
3909 sprintf(cp
, "PLD\t");
3911 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
3912 immed
= (opcode
>> 4) & 0x3;
3914 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3919 if ((rn
& rt
) == 0xf)
3922 immed
= opcode
& 0xfff;
3923 goto preload_immediate
;
3927 mnemonic
= "LDRB.W";
3928 immed
= opcode
& 0xfff;
3929 goto ldrxb_immediate_t2
;
3931 if ((rn
& rt
) == 0xf) {
3932 immed
= opcode
& 0xfff;
3933 address
= thumb_alignpc4(address
);
3934 if (opcode
& (1 << 23))
3938 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
3941 if (rn
== 0xf && rt
!= 0xf) {
3943 immed
= opcode
& 0xfff;
3944 address
= thumb_alignpc4(address
);
3945 if (opcode
& (1 << 23))
3949 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
3954 if ((op2
& 0x3c) == 0x38) {
3955 immed
= opcode
& 0xff;
3956 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
3957 rt
, rn
, immed
, immed
);
3960 if ((op2
& 0x3c) == 0x30) {
3962 immed
= opcode
& 0xff;
3963 immed
= -immed
; // pli
3964 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
3969 goto ldrxb_immediate_t3
;
3971 if ((op2
& 0x24) == 0x24) {
3973 goto ldrxb_immediate_t3
;
3976 int rm
= opcode
& 0xf;
3979 sprintf(cp
, "PLI\t");
3981 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
3982 immed
= (opcode
>> 4) & 0x3;
3984 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
3990 immed
= opcode
& 0xfff;
3991 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
3997 immed
= opcode
& 0xfff;
3999 goto ldrxb_immediate_t2
;
4002 return ERROR_INVALID_ARGUMENTS
;
4005 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4006 arm_instruction_t
*instruction
, char *cp
)
4008 int rn
= (opcode
>> 16) & 0xf;
4009 int rt
= (opcode
>> 12) & 0xf;
4010 int op2
= (opcode
>> 6) & 0x3f;
4015 sprintf(cp
, "HINT (UNALLOCATED)");
4019 if (opcode
& (1 << 24))
4022 if ((opcode
& (1 << 23)) == 0) {
4025 immed
= opcode
& 0xfff;
4026 address
= thumb_alignpc4(address
);
4027 if (opcode
& (1 << 23))
4031 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4036 int rm
= opcode
& 0xf;
4038 immed
= (opcode
>> 4) & 0x3;
4039 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4040 sign
, rt
, rn
, rm
, immed
);
4043 if ((op2
& 0x3c) == 0x38) {
4044 immed
= opcode
& 0xff;
4045 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4046 sign
, rt
, rn
, immed
, immed
);
4049 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4050 char *p1
= "", *p2
= "]";
4052 immed
= opcode
& 0xff;
4053 if (!(opcode
& 0x200))
4056 /* two indexed modes will write back rn */
4057 if (opcode
& 0x100) {
4058 if (opcode
& 0x400) /* pre-indexed */
4060 else { /* post-indexed */
4065 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4066 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4073 immed
= opcode
& 0xfff;
4074 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4075 sign
, *sign
? "" : ".W",
4076 rt
, rn
, immed
, immed
);
4080 return ERROR_INVALID_ARGUMENTS
;
4084 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4085 * always set. That means eventual arm_simulate_step() support for Thumb2
4086 * will need work in this area.
4088 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
4095 /* clear low bit ... it's set on function pointers */
4098 /* clear fields, to avoid confusion */
4099 memset(instruction
, 0, sizeof(arm_instruction_t
));
4101 /* read first halfword, see if this is the only one */
4102 retval
= target_read_u16(target
, address
, &op
);
4103 if (retval
!= ERROR_OK
)
4106 switch (op
& 0xf800) {
4110 /* 32-bit instructions */
4111 instruction
->instruction_size
= 4;
4113 retval
= target_read_u16(target
, address
+ 2, &op
);
4114 if (retval
!= ERROR_OK
)
4117 instruction
->opcode
= opcode
;
4120 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4121 return thumb_evaluate_opcode(op
, address
, instruction
);
4124 snprintf(instruction
->text
, 128,
4125 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4127 cp
= strchr(instruction
->text
, 0);
4128 retval
= ERROR_FAIL
;
4130 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4131 if ((opcode
& 0x1a008000) == 0x10000000)
4132 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4134 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4135 else if ((opcode
& 0x1a008000) == 0x12000000)
4136 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4138 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4139 else if ((opcode
& 0x18008000) == 0x10008000)
4140 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4142 /* ARMv7-M: A5.3.5 Load/store multiple */
4143 else if ((opcode
& 0x1e400000) == 0x08000000)
4144 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4146 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4147 else if ((opcode
& 0x1e400000) == 0x08400000)
4148 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4150 /* ARMv7-M: A5.3.7 Load word */
4151 else if ((opcode
& 0x1f700000) == 0x18500000)
4152 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4154 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4155 else if ((opcode
& 0x1e700000) == 0x18300000)
4156 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4158 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4159 else if ((opcode
& 0x1e700000) == 0x18100000)
4160 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4162 /* ARMv7-M: A5.3.10 Store single data item */
4163 else if ((opcode
& 0x1f100000) == 0x18000000)
4164 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4166 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4167 else if ((opcode
& 0x1e000000) == 0x0a000000)
4168 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4170 /* ARMv7-M: A5.3.12 Data processing (register)
4171 * and A5.3.13 Miscellaneous operations
4173 else if ((opcode
& 0x1f000000) == 0x1a000000)
4174 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4176 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4177 else if ((opcode
& 0x1f800000) == 0x1b000000)
4178 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4180 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4181 else if ((opcode
& 0x1f800000) == 0x1b800000)
4182 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4184 if (retval
== ERROR_OK
)
4188 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4189 * instructions; not yet handled here.
4192 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4193 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4194 strcpy(cp
, "UNDEFINED OPCODE");
4198 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4201 strcpy(cp
, "(32-bit Thumb2 ...)");
4205 int arm_access_size(arm_instruction_t
*instruction
)
4207 if ((instruction
->type
== ARM_LDRB
)
4208 || (instruction
->type
== ARM_LDRBT
)
4209 || (instruction
->type
== ARM_LDRSB
)
4210 || (instruction
->type
== ARM_STRB
)
4211 || (instruction
->type
== ARM_STRBT
))
4215 else if ((instruction
->type
== ARM_LDRH
)
4216 || (instruction
->type
== ARM_LDRSH
)
4217 || (instruction
->type
== ARM_STRH
))
4221 else if ((instruction
->type
== ARM_LDR
)
4222 || (instruction
->type
== ARM_LDRT
)
4223 || (instruction
->type
== ARM_STR
)
4224 || (instruction
->type
== ARM_STRT
))
4228 else if ((instruction
->type
== ARM_LDRD
)
4229 || (instruction
->type
== ARM_STRD
))
4235 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)