1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
25 #include "arm_disassembler.h"
29 /* textual represenation of the condition field */
30 /* ALways (default) is ommitted (empty string) */
31 char *arm_condition_strings
[] =
33 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
36 /* make up for C's missing ROR */
37 uint32_t ror(uint32_t value
, int places
)
39 return (value
>> places
) | (value
<< (32 - places
));
42 int evaluate_pld(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
45 if ((opcode
& 0x0d70f0000) == 0x0550f000)
47 instruction
->type
= ARM_PLD
;
49 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
55 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
59 LOG_ERROR("should never reach this point");
63 int evaluate_swi(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
65 instruction
->type
= ARM_SWI
;
67 snprintf(instruction
->text
, 128,
68 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
69 address
, opcode
, (opcode
& 0xffffff));
74 int evaluate_blx_imm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
78 uint32_t target_address
;
80 instruction
->type
= ARM_BLX
;
81 immediate
= opcode
& 0x00ffffff;
83 /* sign extend 24-bit immediate */
84 if (immediate
& 0x00800000)
85 offset
= 0xff000000 | immediate
;
89 /* shift two bits left */
92 /* odd/event halfword */
93 if (opcode
& 0x01000000)
96 target_address
= address
+ 8 + offset
;
98 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
100 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
101 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
106 int evaluate_b_bl(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
111 uint32_t target_address
;
113 immediate
= opcode
& 0x00ffffff;
114 L
= (opcode
& 0x01000000) >> 24;
116 /* sign extend 24-bit immediate */
117 if (immediate
& 0x00800000)
118 offset
= 0xff000000 | immediate
;
122 /* shift two bits left */
125 target_address
= address
+ 8 + offset
;
128 instruction
->type
= ARM_BL
;
130 instruction
->type
= ARM_B
;
132 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
133 (L
) ? "L" : "", COND(opcode
), target_address
);
135 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
136 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
141 /* Coprocessor load/store and double register transfers */
142 /* both normal and extended instruction space (condition field b1111) */
143 int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
145 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
148 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
150 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
153 cp_opcode
= (opcode
& 0xf0) >> 4;
154 Rd
= (opcode
& 0xf000) >> 12;
155 Rn
= (opcode
& 0xf0000) >> 16;
156 CRm
= (opcode
& 0xf);
159 if ((opcode
& 0x0ff00000) == 0x0c400000)
161 instruction
->type
= ARM_MCRR
;
166 if ((opcode
& 0x0ff00000) == 0x0c500000)
168 instruction
->type
= ARM_MRRC
;
172 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
173 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
175 else /* LDC or STC */
177 uint8_t CRd
, Rn
, offset
;
180 char addressing_mode
[32];
182 CRd
= (opcode
& 0xf000) >> 12;
183 Rn
= (opcode
& 0xf0000) >> 16;
184 offset
= (opcode
& 0xff);
187 if (opcode
& 0x00100000)
189 instruction
->type
= ARM_LDC
;
194 instruction
->type
= ARM_STC
;
198 U
= (opcode
& 0x00800000) >> 23;
199 N
= (opcode
& 0x00400000) >> 22;
201 /* addressing modes */
202 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
203 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
204 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
205 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
206 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
207 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
208 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
209 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
211 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
212 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
214 cp_num
, CRd
, addressing_mode
);
220 /* Coprocessor data processing instructions */
221 /* Coprocessor register transfer instructions */
222 /* both normal and extended instruction space (condition field b1111) */
223 int evaluate_cdp_mcr_mrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
227 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
229 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
230 cp_num
= (opcode
& 0xf00) >> 8;
231 CRd_Rd
= (opcode
& 0xf000) >> 12;
232 CRn
= (opcode
& 0xf0000) >> 16;
233 CRm
= (opcode
& 0xf);
234 opcode_2
= (opcode
& 0xe0) >> 5;
237 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
239 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
241 instruction
->type
= ARM_MRC
;
244 else /* bit 20 not set -> MCR */
246 instruction
->type
= ARM_MCR
;
250 opcode_1
= (opcode
& 0x00e00000) >> 21;
252 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",
253 address
, opcode
, mnemonic
, cond
,
254 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
256 else /* bit 4 not set -> CDP */
258 instruction
->type
= ARM_CDP
;
261 opcode_1
= (opcode
& 0x00f00000) >> 20;
263 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",
264 address
, opcode
, mnemonic
, cond
,
265 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
271 /* Load/store instructions */
272 int evaluate_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
274 uint8_t I
, P
, U
, B
, W
, L
;
276 char *operation
; /* "LDR" or "STR" */
277 char *suffix
; /* "", "B", "T", "BT" */
281 I
= (opcode
& 0x02000000) >> 25;
282 P
= (opcode
& 0x01000000) >> 24;
283 U
= (opcode
& 0x00800000) >> 23;
284 B
= (opcode
& 0x00400000) >> 22;
285 W
= (opcode
& 0x00200000) >> 21;
286 L
= (opcode
& 0x00100000) >> 20;
288 /* target register */
289 Rd
= (opcode
& 0xf000) >> 12;
292 Rn
= (opcode
& 0xf0000) >> 16;
294 instruction
->info
.load_store
.Rd
= Rd
;
295 instruction
->info
.load_store
.Rn
= Rn
;
296 instruction
->info
.load_store
.U
= U
;
298 /* determine operation */
304 /* determine instruction type and suffix */
307 if ((P
== 0) && (W
== 1))
310 instruction
->type
= ARM_LDRBT
;
312 instruction
->type
= ARM_STRBT
;
318 instruction
->type
= ARM_LDRB
;
320 instruction
->type
= ARM_STRB
;
326 if ((P
== 0) && (W
== 1))
329 instruction
->type
= ARM_LDRT
;
331 instruction
->type
= ARM_STRT
;
337 instruction
->type
= ARM_LDR
;
339 instruction
->type
= ARM_STR
;
344 if (!I
) /* #+-<offset_12> */
346 uint32_t offset_12
= (opcode
& 0xfff);
348 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
350 snprintf(offset
, 32, "%s", "");
352 instruction
->info
.load_store
.offset_mode
= 0;
353 instruction
->info
.load_store
.offset
.offset
= offset_12
;
355 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
357 uint8_t shift_imm
, shift
;
360 shift_imm
= (opcode
& 0xf80) >> 7;
361 shift
= (opcode
& 0x60) >> 5;
364 /* LSR encodes a shift by 32 bit as 0x0 */
365 if ((shift
== 0x1) && (shift_imm
== 0x0))
368 /* ASR encodes a shift by 32 bit as 0x0 */
369 if ((shift
== 0x2) && (shift_imm
== 0x0))
372 /* ROR by 32 bit is actually a RRX */
373 if ((shift
== 0x3) && (shift_imm
== 0x0))
376 instruction
->info
.load_store
.offset_mode
= 1;
377 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
378 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
379 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
381 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
383 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
385 else /* +-<Rm>, <Shift>, #<shift_imm> */
390 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
393 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
396 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
399 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
402 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
410 if (W
== 0) /* offset */
412 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
413 address
, opcode
, operation
, COND(opcode
), suffix
,
416 instruction
->info
.load_store
.index_mode
= 0;
418 else /* pre-indexed */
420 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
421 address
, opcode
, operation
, COND(opcode
), suffix
,
424 instruction
->info
.load_store
.index_mode
= 1;
427 else /* post-indexed */
429 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
430 address
, opcode
, operation
, COND(opcode
), suffix
,
433 instruction
->info
.load_store
.index_mode
= 2;
439 /* Miscellaneous load/store instructions */
440 int evaluate_misc_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
442 uint8_t P
, U
, I
, W
, L
, S
, H
;
444 char *operation
; /* "LDR" or "STR" */
445 char *suffix
; /* "H", "SB", "SH", "D" */
449 P
= (opcode
& 0x01000000) >> 24;
450 U
= (opcode
& 0x00800000) >> 23;
451 I
= (opcode
& 0x00400000) >> 22;
452 W
= (opcode
& 0x00200000) >> 21;
453 L
= (opcode
& 0x00100000) >> 20;
454 S
= (opcode
& 0x00000040) >> 6;
455 H
= (opcode
& 0x00000020) >> 5;
457 /* target register */
458 Rd
= (opcode
& 0xf000) >> 12;
461 Rn
= (opcode
& 0xf0000) >> 16;
463 instruction
->info
.load_store
.Rd
= Rd
;
464 instruction
->info
.load_store
.Rn
= Rn
;
465 instruction
->info
.load_store
.U
= U
;
467 /* determine instruction type and suffix */
475 instruction
->type
= ARM_LDRSH
;
481 instruction
->type
= ARM_LDRSB
;
485 else /* there are no signed stores, so this is used to encode double-register load/stores */
491 instruction
->type
= ARM_STRD
;
496 instruction
->type
= ARM_LDRD
;
506 instruction
->type
= ARM_LDRH
;
511 instruction
->type
= ARM_STRH
;
515 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
517 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
518 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
520 instruction
->info
.load_store
.offset_mode
= 0;
521 instruction
->info
.load_store
.offset
.offset
= offset_8
;
523 else /* Register offset/index (+-<Rm>) */
527 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
529 instruction
->info
.load_store
.offset_mode
= 1;
530 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
531 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
532 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
537 if (W
== 0) /* offset */
539 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
540 address
, opcode
, operation
, COND(opcode
), suffix
,
543 instruction
->info
.load_store
.index_mode
= 0;
545 else /* pre-indexed */
547 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
548 address
, opcode
, operation
, COND(opcode
), suffix
,
551 instruction
->info
.load_store
.index_mode
= 1;
554 else /* post-indexed */
556 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
557 address
, opcode
, operation
, COND(opcode
), suffix
,
560 instruction
->info
.load_store
.index_mode
= 2;
566 /* Load/store multiples instructions */
567 int evaluate_ldm_stm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
569 uint8_t P
, U
, S
, W
, L
, Rn
;
570 uint32_t register_list
;
571 char *addressing_mode
;
578 P
= (opcode
& 0x01000000) >> 24;
579 U
= (opcode
& 0x00800000) >> 23;
580 S
= (opcode
& 0x00400000) >> 22;
581 W
= (opcode
& 0x00200000) >> 21;
582 L
= (opcode
& 0x00100000) >> 20;
583 register_list
= (opcode
& 0xffff);
584 Rn
= (opcode
& 0xf0000) >> 16;
586 instruction
->info
.load_store_multiple
.Rn
= Rn
;
587 instruction
->info
.load_store_multiple
.register_list
= register_list
;
588 instruction
->info
.load_store_multiple
.S
= S
;
589 instruction
->info
.load_store_multiple
.W
= W
;
593 instruction
->type
= ARM_LDM
;
598 instruction
->type
= ARM_STM
;
606 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
607 addressing_mode
= "IB";
611 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
612 addressing_mode
= "DB";
619 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
620 /* "IA" is the default in UAL syntax */
621 addressing_mode
= "";
625 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
626 addressing_mode
= "DA";
630 reg_list_p
= reg_list
;
631 for (i
= 0; i
<= 15; i
++)
633 if ((register_list
>> i
) & 1)
638 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
642 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
647 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
648 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
649 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
654 /* Multiplies, extra load/stores */
655 int evaluate_mul_and_extra_ld_st(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
657 /* Multiply (accumulate) (long) and Swap/swap byte */
658 if ((opcode
& 0x000000f0) == 0x00000090)
660 /* Multiply (accumulate) */
661 if ((opcode
& 0x0f800000) == 0x00000000)
663 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
665 Rs
= (opcode
& 0xf00) >> 8;
666 Rn
= (opcode
& 0xf000) >> 12;
667 Rd
= (opcode
& 0xf0000) >> 16;
668 S
= (opcode
& 0x00100000) >> 20;
670 /* examine A bit (accumulate) */
671 if (opcode
& 0x00200000)
673 instruction
->type
= ARM_MLA
;
674 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
675 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
679 instruction
->type
= ARM_MUL
;
680 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
681 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
687 /* Multiply (accumulate) long */
688 if ((opcode
& 0x0f800000) == 0x00800000)
690 char* mnemonic
= NULL
;
691 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
693 Rs
= (opcode
& 0xf00) >> 8;
694 RdHi
= (opcode
& 0xf000) >> 12;
695 RdLow
= (opcode
& 0xf0000) >> 16;
696 S
= (opcode
& 0x00100000) >> 20;
698 switch ((opcode
& 0x00600000) >> 21)
701 instruction
->type
= ARM_UMULL
;
705 instruction
->type
= ARM_UMLAL
;
709 instruction
->type
= ARM_SMULL
;
713 instruction
->type
= ARM_SMLAL
;
718 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
719 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
720 RdLow
, RdHi
, Rm
, Rs
);
726 if ((opcode
& 0x0f800000) == 0x01000000)
730 Rd
= (opcode
& 0xf000) >> 12;
731 Rn
= (opcode
& 0xf0000) >> 16;
734 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
736 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
737 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
743 return evaluate_misc_load_store(opcode
, address
, instruction
);
746 int evaluate_mrs_msr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
748 int R
= (opcode
& 0x00400000) >> 22;
749 char *PSR
= (R
) ? "SPSR" : "CPSR";
751 /* Move register to status register (MSR) */
752 if (opcode
& 0x00200000)
754 instruction
->type
= ARM_MSR
;
756 /* immediate variant */
757 if (opcode
& 0x02000000)
759 uint8_t immediate
= (opcode
& 0xff);
760 uint8_t rotate
= (opcode
& 0xf00);
762 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
763 address
, opcode
, COND(opcode
), PSR
,
764 (opcode
& 0x10000) ? "c" : "",
765 (opcode
& 0x20000) ? "x" : "",
766 (opcode
& 0x40000) ? "s" : "",
767 (opcode
& 0x80000) ? "f" : "",
768 ror(immediate
, (rotate
* 2))
771 else /* register variant */
773 uint8_t Rm
= opcode
& 0xf;
774 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
775 address
, opcode
, COND(opcode
), PSR
,
776 (opcode
& 0x10000) ? "c" : "",
777 (opcode
& 0x20000) ? "x" : "",
778 (opcode
& 0x40000) ? "s" : "",
779 (opcode
& 0x80000) ? "f" : "",
785 else /* Move status register to register (MRS) */
789 instruction
->type
= ARM_MRS
;
790 Rd
= (opcode
& 0x0000f000) >> 12;
792 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
793 address
, opcode
, COND(opcode
), Rd
, PSR
);
799 /* Miscellaneous instructions */
800 int evaluate_misc_instr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
803 if ((opcode
& 0x000000f0) == 0x00000000)
805 evaluate_mrs_msr(opcode
, address
, instruction
);
809 if ((opcode
& 0x006000f0) == 0x00200010)
812 instruction
->type
= ARM_BX
;
815 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
816 address
, opcode
, COND(opcode
), Rm
);
818 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
819 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
823 if ((opcode
& 0x006000f0) == 0x00600010)
826 instruction
->type
= ARM_CLZ
;
828 Rd
= (opcode
& 0xf000) >> 12;
830 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
831 address
, opcode
, COND(opcode
), Rd
, Rm
);
835 if ((opcode
& 0x006000f0) == 0x00200030)
838 instruction
->type
= ARM_BLX
;
841 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
842 address
, opcode
, COND(opcode
), Rm
);
844 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
845 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
848 /* Enhanced DSP add/subtracts */
849 if ((opcode
& 0x0000000f0) == 0x00000050)
852 char *mnemonic
= NULL
;
854 Rd
= (opcode
& 0xf000) >> 12;
855 Rn
= (opcode
& 0xf0000) >> 16;
857 switch ((opcode
& 0x00600000) >> 21)
860 instruction
->type
= ARM_QADD
;
864 instruction
->type
= ARM_QSUB
;
868 instruction
->type
= ARM_QDADD
;
872 instruction
->type
= ARM_QDSUB
;
877 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
878 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
881 /* Software breakpoints */
882 if ((opcode
& 0x0000000f0) == 0x00000070)
885 instruction
->type
= ARM_BKPT
;
886 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
888 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
889 address
, opcode
, immediate
);
892 /* Enhanced DSP multiplies */
893 if ((opcode
& 0x000000090) == 0x00000080)
895 int x
= (opcode
& 0x20) >> 5;
896 int y
= (opcode
& 0x40) >> 6;
899 if ((opcode
& 0x00600000) == 0x00000000)
901 uint8_t Rd
, Rm
, Rs
, Rn
;
902 instruction
->type
= ARM_SMLAxy
;
903 Rd
= (opcode
& 0xf0000) >> 16;
905 Rs
= (opcode
& 0xf00) >> 8;
906 Rn
= (opcode
& 0xf000) >> 12;
908 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
909 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
914 if ((opcode
& 0x00600000) == 0x00400000)
916 uint8_t RdLow
, RdHi
, Rm
, Rs
;
917 instruction
->type
= ARM_SMLAxy
;
918 RdHi
= (opcode
& 0xf0000) >> 16;
919 RdLow
= (opcode
& 0xf000) >> 12;
921 Rs
= (opcode
& 0xf00) >> 8;
923 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
924 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
925 RdLow
, RdHi
, Rm
, Rs
);
929 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
931 uint8_t Rd
, Rm
, Rs
, Rn
;
932 instruction
->type
= ARM_SMLAWy
;
933 Rd
= (opcode
& 0xf0000) >> 16;
935 Rs
= (opcode
& 0xf00) >> 8;
936 Rn
= (opcode
& 0xf000) >> 12;
938 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
939 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
944 if ((opcode
& 0x00600000) == 0x00300000)
947 instruction
->type
= ARM_SMULxy
;
948 Rd
= (opcode
& 0xf0000) >> 16;
950 Rs
= (opcode
& 0xf00) >> 8;
952 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
953 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
958 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
961 instruction
->type
= ARM_SMULWy
;
962 Rd
= (opcode
& 0xf0000) >> 16;
964 Rs
= (opcode
& 0xf00) >> 8;
966 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
967 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
975 int evaluate_data_proc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
977 uint8_t I
, op
, S
, Rn
, Rd
;
978 char *mnemonic
= NULL
;
979 char shifter_operand
[32];
981 I
= (opcode
& 0x02000000) >> 25;
982 op
= (opcode
& 0x01e00000) >> 21;
983 S
= (opcode
& 0x00100000) >> 20;
985 Rd
= (opcode
& 0xf000) >> 12;
986 Rn
= (opcode
& 0xf0000) >> 16;
988 instruction
->info
.data_proc
.Rd
= Rd
;
989 instruction
->info
.data_proc
.Rn
= Rn
;
990 instruction
->info
.data_proc
.S
= S
;
995 instruction
->type
= ARM_AND
;
999 instruction
->type
= ARM_EOR
;
1003 instruction
->type
= ARM_SUB
;
1007 instruction
->type
= ARM_RSB
;
1011 instruction
->type
= ARM_ADD
;
1015 instruction
->type
= ARM_ADC
;
1019 instruction
->type
= ARM_SBC
;
1023 instruction
->type
= ARM_RSC
;
1027 instruction
->type
= ARM_TST
;
1031 instruction
->type
= ARM_TEQ
;
1035 instruction
->type
= ARM_CMP
;
1039 instruction
->type
= ARM_CMN
;
1043 instruction
->type
= ARM_ORR
;
1047 instruction
->type
= ARM_MOV
;
1051 instruction
->type
= ARM_BIC
;
1055 instruction
->type
= ARM_MVN
;
1060 if (I
) /* immediate shifter operand (#<immediate>)*/
1062 uint8_t immed_8
= opcode
& 0xff;
1063 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1066 immediate
= ror(immed_8
, rotate_imm
* 2);
1068 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1070 instruction
->info
.data_proc
.variant
= 0;
1071 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1073 else /* register-based shifter operand */
1076 shift
= (opcode
& 0x60) >> 5;
1077 Rm
= (opcode
& 0xf);
1079 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1082 shift_imm
= (opcode
& 0xf80) >> 7;
1084 instruction
->info
.data_proc
.variant
= 1;
1085 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1086 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1087 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1089 /* LSR encodes a shift by 32 bit as 0x0 */
1090 if ((shift
== 0x1) && (shift_imm
== 0x0))
1093 /* ASR encodes a shift by 32 bit as 0x0 */
1094 if ((shift
== 0x2) && (shift_imm
== 0x0))
1097 /* ROR by 32 bit is actually a RRX */
1098 if ((shift
== 0x3) && (shift_imm
== 0x0))
1101 if ((shift_imm
== 0x0) && (shift
== 0x0))
1103 snprintf(shifter_operand
, 32, "r%i", Rm
);
1107 if (shift
== 0x0) /* LSL */
1109 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1111 else if (shift
== 0x1) /* LSR */
1113 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1115 else if (shift
== 0x2) /* ASR */
1117 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1119 else if (shift
== 0x3) /* ROR */
1121 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1123 else if (shift
== 0x4) /* RRX */
1125 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1129 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1131 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1133 instruction
->info
.data_proc
.variant
= 2;
1134 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1135 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1136 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1138 if (shift
== 0x0) /* LSL */
1140 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1142 else if (shift
== 0x1) /* LSR */
1144 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1146 else if (shift
== 0x2) /* ASR */
1148 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1150 else if (shift
== 0x3) /* ROR */
1152 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1157 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1159 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1160 address
, opcode
, mnemonic
, COND(opcode
),
1161 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1163 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1165 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1166 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1168 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1169 address
, opcode
, mnemonic
, COND(opcode
),
1170 (S
) ? "S" : "", Rd
, shifter_operand
);
1172 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1174 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1175 address
, opcode
, mnemonic
, COND(opcode
),
1176 Rn
, shifter_operand
);
1182 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1184 /* clear fields, to avoid confusion */
1185 memset(instruction
, 0, sizeof(arm_instruction_t
));
1186 instruction
->opcode
= opcode
;
1187 instruction
->instruction_size
= 4;
1189 /* catch opcodes with condition field [31:28] = b1111 */
1190 if ((opcode
& 0xf0000000) == 0xf0000000)
1192 /* Undefined instruction (or ARMv5E cache preload PLD) */
1193 if ((opcode
& 0x08000000) == 0x00000000)
1194 return evaluate_pld(opcode
, address
, instruction
);
1196 /* Undefined instruction */
1197 if ((opcode
& 0x0e000000) == 0x08000000)
1199 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1200 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1204 /* Branch and branch with link and change to Thumb */
1205 if ((opcode
& 0x0e000000) == 0x0a000000)
1206 return evaluate_blx_imm(opcode
, address
, instruction
);
1208 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1209 /* Coprocessor load/store and double register transfers */
1210 if ((opcode
& 0x0e000000) == 0x0c000000)
1211 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1213 /* Coprocessor data processing */
1214 if ((opcode
& 0x0f000100) == 0x0c000000)
1215 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1217 /* Coprocessor register transfers */
1218 if ((opcode
& 0x0f000010) == 0x0c000010)
1219 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1221 /* Undefined instruction */
1222 if ((opcode
& 0x0f000000) == 0x0f000000)
1224 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1225 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1230 /* catch opcodes with [27:25] = b000 */
1231 if ((opcode
& 0x0e000000) == 0x00000000)
1233 /* Multiplies, extra load/stores */
1234 if ((opcode
& 0x00000090) == 0x00000090)
1235 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1237 /* Miscellaneous instructions */
1238 if ((opcode
& 0x0f900000) == 0x01000000)
1239 return evaluate_misc_instr(opcode
, address
, instruction
);
1241 return evaluate_data_proc(opcode
, address
, instruction
);
1244 /* catch opcodes with [27:25] = b001 */
1245 if ((opcode
& 0x0e000000) == 0x02000000)
1247 /* Undefined instruction */
1248 if ((opcode
& 0x0fb00000) == 0x03000000)
1250 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1251 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1255 /* Move immediate to status register */
1256 if ((opcode
& 0x0fb00000) == 0x03200000)
1257 return evaluate_mrs_msr(opcode
, address
, instruction
);
1259 return evaluate_data_proc(opcode
, address
, instruction
);
1263 /* catch opcodes with [27:25] = b010 */
1264 if ((opcode
& 0x0e000000) == 0x04000000)
1266 /* Load/store immediate offset */
1267 return evaluate_load_store(opcode
, address
, instruction
);
1270 /* catch opcodes with [27:25] = b011 */
1271 if ((opcode
& 0x0e000000) == 0x06000000)
1273 /* Undefined instruction */
1274 if ((opcode
& 0x00000010) == 0x00000010)
1276 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1277 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1281 /* Load/store register offset */
1282 return evaluate_load_store(opcode
, address
, instruction
);
1286 /* catch opcodes with [27:25] = b100 */
1287 if ((opcode
& 0x0e000000) == 0x08000000)
1289 /* Load/store multiple */
1290 return evaluate_ldm_stm(opcode
, address
, instruction
);
1293 /* catch opcodes with [27:25] = b101 */
1294 if ((opcode
& 0x0e000000) == 0x0a000000)
1296 /* Branch and branch with link */
1297 return evaluate_b_bl(opcode
, address
, instruction
);
1300 /* catch opcodes with [27:25] = b110 */
1301 if ((opcode
& 0x0e000000) == 0x0a000000)
1303 /* Coprocessor load/store and double register transfers */
1304 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1307 /* catch opcodes with [27:25] = b111 */
1308 if ((opcode
& 0x0e000000) == 0x0e000000)
1310 /* Software interrupt */
1311 if ((opcode
& 0x0f000000) == 0x0f000000)
1312 return evaluate_swi(opcode
, address
, instruction
);
1314 /* Coprocessor data processing */
1315 if ((opcode
& 0x0f000010) == 0x0e000000)
1316 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1318 /* Coprocessor register transfers */
1319 if ((opcode
& 0x0f000010) == 0x0e000010)
1320 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1323 LOG_ERROR("should never reach this point");
1327 int evaluate_b_bl_blx_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1329 uint32_t offset
= opcode
& 0x7ff;
1330 uint32_t opc
= (opcode
>> 11) & 0x3;
1331 uint32_t target_address
;
1332 char *mnemonic
= NULL
;
1334 /* sign extend 11-bit offset */
1335 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1336 offset
= 0xfffff800 | offset
;
1338 target_address
= address
+ 4 + (offset
<< 1);
1342 /* unconditional branch */
1344 instruction
->type
= ARM_B
;
1349 instruction
->type
= ARM_BLX
;
1354 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1355 mnemonic
= "prefix";
1356 target_address
= offset
<< 12;
1360 instruction
->type
= ARM_BL
;
1365 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1366 * these are effectively 32-bit instructions even in Thumb1.
1367 * Might be simplest to always use the Thumb2 decoder.
1370 snprintf(instruction
->text
, 128,
1371 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1372 address
, opcode
, mnemonic
, target_address
);
1374 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1375 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1380 int evaluate_add_sub_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1382 uint8_t Rd
= (opcode
>> 0) & 0x7;
1383 uint8_t Rn
= (opcode
>> 3) & 0x7;
1384 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1385 uint32_t opc
= opcode
& (1 << 9);
1386 uint32_t reg_imm
= opcode
& (1 << 10);
1391 instruction
->type
= ARM_SUB
;
1396 instruction
->type
= ARM_ADD
;
1400 instruction
->info
.data_proc
.Rd
= Rd
;
1401 instruction
->info
.data_proc
.Rn
= Rn
;
1402 instruction
->info
.data_proc
.S
= 1;
1406 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1407 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1408 snprintf(instruction
->text
, 128,
1409 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1410 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1414 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1415 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1416 snprintf(instruction
->text
, 128,
1417 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1418 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1424 int evaluate_shift_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1426 uint8_t Rd
= (opcode
>> 0) & 0x7;
1427 uint8_t Rm
= (opcode
>> 3) & 0x7;
1428 uint8_t imm
= (opcode
>> 6) & 0x1f;
1429 uint8_t opc
= (opcode
>> 11) & 0x3;
1430 char *mnemonic
= NULL
;
1435 instruction
->type
= ARM_MOV
;
1437 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1440 instruction
->type
= ARM_MOV
;
1442 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1445 instruction
->type
= ARM_MOV
;
1447 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1451 if ((imm
== 0) && (opc
!= 0))
1454 instruction
->info
.data_proc
.Rd
= Rd
;
1455 instruction
->info
.data_proc
.Rn
= -1;
1456 instruction
->info
.data_proc
.S
= 1;
1458 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1459 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1460 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1462 snprintf(instruction
->text
, 128,
1463 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1464 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1469 int evaluate_data_proc_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1471 uint8_t imm
= opcode
& 0xff;
1472 uint8_t Rd
= (opcode
>> 8) & 0x7;
1473 uint32_t opc
= (opcode
>> 11) & 0x3;
1474 char *mnemonic
= NULL
;
1476 instruction
->info
.data_proc
.Rd
= Rd
;
1477 instruction
->info
.data_proc
.Rn
= Rd
;
1478 instruction
->info
.data_proc
.S
= 1;
1479 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1480 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1485 instruction
->type
= ARM_MOV
;
1487 instruction
->info
.data_proc
.Rn
= -1;
1490 instruction
->type
= ARM_CMP
;
1492 instruction
->info
.data_proc
.Rd
= -1;
1495 instruction
->type
= ARM_ADD
;
1499 instruction
->type
= ARM_SUB
;
1504 snprintf(instruction
->text
, 128,
1505 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1506 address
, opcode
, mnemonic
, Rd
, imm
);
1511 int evaluate_data_proc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1513 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1514 char *mnemonic
= NULL
;
1517 high_reg
= (opcode
& 0x0400) >> 10;
1518 op
= (opcode
& 0x03C0) >> 6;
1520 Rd
= (opcode
& 0x0007);
1521 Rm
= (opcode
& 0x0038) >> 3;
1522 H1
= (opcode
& 0x0080) >> 7;
1523 H2
= (opcode
& 0x0040) >> 6;
1525 instruction
->info
.data_proc
.Rd
= Rd
;
1526 instruction
->info
.data_proc
.Rn
= Rd
;
1527 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1528 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1529 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1540 instruction
->type
= ARM_ADD
;
1544 instruction
->type
= ARM_CMP
;
1548 instruction
->type
= ARM_MOV
;
1554 if ((opcode
& 0x7) == 0x0)
1556 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1559 instruction
->type
= ARM_BLX
;
1560 snprintf(instruction
->text
, 128,
1562 " 0x%4.4x \tBLX\tr%i",
1563 address
, opcode
, Rm
);
1567 instruction
->type
= ARM_BX
;
1568 snprintf(instruction
->text
, 128,
1570 " 0x%4.4x \tBX\tr%i",
1571 address
, opcode
, Rm
);
1576 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1577 snprintf(instruction
->text
, 128,
1580 "UNDEFINED INSTRUCTION",
1592 instruction
->type
= ARM_AND
;
1596 instruction
->type
= ARM_EOR
;
1600 instruction
->type
= ARM_MOV
;
1602 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1603 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1604 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1605 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1608 instruction
->type
= ARM_MOV
;
1610 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1611 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1612 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1613 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1616 instruction
->type
= ARM_MOV
;
1618 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1619 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1620 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1621 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1624 instruction
->type
= ARM_ADC
;
1628 instruction
->type
= ARM_SBC
;
1632 instruction
->type
= ARM_MOV
;
1634 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1635 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1636 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1637 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1640 instruction
->type
= ARM_TST
;
1644 instruction
->type
= ARM_RSB
;
1646 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1647 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1648 instruction
->info
.data_proc
.Rn
= Rm
;
1651 instruction
->type
= ARM_CMP
;
1655 instruction
->type
= ARM_CMN
;
1659 instruction
->type
= ARM_ORR
;
1663 instruction
->type
= ARM_MUL
;
1667 instruction
->type
= ARM_BIC
;
1671 instruction
->type
= ARM_MVN
;
1678 snprintf(instruction
->text
, 128,
1679 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
1681 address
, opcode
, mnemonic
, Rd
, Rm
);
1683 snprintf(instruction
->text
, 128,
1684 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
1685 address
, opcode
, mnemonic
, Rd
, Rm
);
1690 /* PC-relative data addressing is word-aligned even with Thumb */
1691 static inline uint32_t thumb_alignpc4(uint32_t addr
)
1693 return (addr
+ 4) & ~3;
1696 int evaluate_load_literal_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1699 uint8_t Rd
= (opcode
>> 8) & 0x7;
1701 instruction
->type
= ARM_LDR
;
1702 immediate
= opcode
& 0x000000ff;
1705 instruction
->info
.load_store
.Rd
= Rd
;
1706 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
1707 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1708 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1709 instruction
->info
.load_store
.offset
.offset
= immediate
;
1711 snprintf(instruction
->text
, 128,
1712 "0x%8.8" PRIx32
" 0x%4.4x \t"
1713 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8x",
1714 address
, opcode
, Rd
, immediate
,
1715 thumb_alignpc4(address
) + immediate
);
1720 int evaluate_load_store_reg_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1722 uint8_t Rd
= (opcode
>> 0) & 0x7;
1723 uint8_t Rn
= (opcode
>> 3) & 0x7;
1724 uint8_t Rm
= (opcode
>> 6) & 0x7;
1725 uint8_t opc
= (opcode
>> 9) & 0x7;
1726 char *mnemonic
= NULL
;
1731 instruction
->type
= ARM_STR
;
1735 instruction
->type
= ARM_STRH
;
1739 instruction
->type
= ARM_STRB
;
1743 instruction
->type
= ARM_LDRSB
;
1747 instruction
->type
= ARM_LDR
;
1751 instruction
->type
= ARM_LDRH
;
1755 instruction
->type
= ARM_LDRB
;
1759 instruction
->type
= ARM_LDRSH
;
1764 snprintf(instruction
->text
, 128,
1765 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
1766 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
1768 instruction
->info
.load_store
.Rd
= Rd
;
1769 instruction
->info
.load_store
.Rn
= Rn
;
1770 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1771 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
1772 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1777 int evaluate_load_store_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1779 uint32_t offset
= (opcode
>> 6) & 0x1f;
1780 uint8_t Rd
= (opcode
>> 0) & 0x7;
1781 uint8_t Rn
= (opcode
>> 3) & 0x7;
1782 uint32_t L
= opcode
& (1 << 11);
1783 uint32_t B
= opcode
& (1 << 12);
1790 instruction
->type
= ARM_LDR
;
1795 instruction
->type
= ARM_STR
;
1799 if ((opcode
&0xF000) == 0x8000)
1810 snprintf(instruction
->text
, 128,
1811 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
1812 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
1814 instruction
->info
.load_store
.Rd
= Rd
;
1815 instruction
->info
.load_store
.Rn
= Rn
;
1816 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1817 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1818 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
1823 int evaluate_load_store_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1825 uint32_t offset
= opcode
& 0xff;
1826 uint8_t Rd
= (opcode
>> 8) & 0x7;
1827 uint32_t L
= opcode
& (1 << 11);
1832 instruction
->type
= ARM_LDR
;
1837 instruction
->type
= ARM_STR
;
1841 snprintf(instruction
->text
, 128,
1842 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
1843 address
, opcode
, mnemonic
, Rd
, offset
*4);
1845 instruction
->info
.load_store
.Rd
= Rd
;
1846 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
1847 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1848 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1849 instruction
->info
.load_store
.offset
.offset
= offset
*4;
1854 int evaluate_add_sp_pc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1856 uint32_t imm
= opcode
& 0xff;
1857 uint8_t Rd
= (opcode
>> 8) & 0x7;
1859 uint32_t SP
= opcode
& (1 << 11);
1862 instruction
->type
= ARM_ADD
;
1875 snprintf(instruction
->text
, 128,
1876 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
1877 address
, opcode
, Rd
, reg_name
, imm
* 4);
1879 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1880 instruction
->info
.data_proc
.Rd
= Rd
;
1881 instruction
->info
.data_proc
.Rn
= Rn
;
1882 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1887 int evaluate_adjust_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1889 uint32_t imm
= opcode
& 0x7f;
1890 uint8_t opc
= opcode
& (1 << 7);
1896 instruction
->type
= ARM_SUB
;
1901 instruction
->type
= ARM_ADD
;
1905 snprintf(instruction
->text
, 128,
1906 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
1907 address
, opcode
, mnemonic
, imm
*4);
1909 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1910 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
1911 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
1912 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1917 int evaluate_breakpoint_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1919 uint32_t imm
= opcode
& 0xff;
1921 instruction
->type
= ARM_BKPT
;
1923 snprintf(instruction
->text
, 128,
1924 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
1925 address
, opcode
, imm
);
1930 int evaluate_load_store_multiple_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1932 uint32_t reg_list
= opcode
& 0xff;
1933 uint32_t L
= opcode
& (1 << 11);
1934 uint32_t R
= opcode
& (1 << 8);
1935 uint8_t Rn
= (opcode
>> 8) & 7;
1936 uint8_t addr_mode
= 0 /* IA */;
1940 char ptr_name
[7] = "";
1943 if ((opcode
& 0xf000) == 0xc000)
1944 { /* generic load/store multiple */
1947 instruction
->type
= ARM_LDM
;
1952 instruction
->type
= ARM_STM
;
1955 snprintf(ptr_name
,7,"r%i!, ",Rn
);
1962 instruction
->type
= ARM_LDM
;
1965 reg_list
|= (1 << 15) /*PC*/;
1969 instruction
->type
= ARM_STM
;
1971 addr_mode
= 3; /*DB*/
1973 reg_list
|= (1 << 14) /*LR*/;
1977 reg_names_p
= reg_names
;
1978 for (i
= 0; i
<= 15; i
++)
1980 if (reg_list
& (1 << i
))
1981 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
1983 if (reg_names_p
> reg_names
)
1984 reg_names_p
[-2] = '\0';
1985 else /* invalid op : no registers */
1986 reg_names
[0] = '\0';
1988 snprintf(instruction
->text
, 128,
1989 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
1990 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
1992 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
1993 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1994 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
1999 int evaluate_cond_branch_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2001 uint32_t offset
= opcode
& 0xff;
2002 uint8_t cond
= (opcode
>> 8) & 0xf;
2003 uint32_t target_address
;
2007 instruction
->type
= ARM_SWI
;
2008 snprintf(instruction
->text
, 128,
2009 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2010 address
, opcode
, offset
);
2013 else if (cond
== 0xe)
2015 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2016 snprintf(instruction
->text
, 128,
2017 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2022 /* sign extend 8-bit offset */
2023 if (offset
& 0x00000080)
2024 offset
= 0xffffff00 | offset
;
2026 target_address
= address
+ 4 + (offset
<< 1);
2028 snprintf(instruction
->text
, 128,
2029 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2031 arm_condition_strings
[cond
], target_address
);
2033 instruction
->type
= ARM_B
;
2034 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2035 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2040 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2041 arm_instruction_t
*instruction
)
2045 /* added in Thumb2 */
2046 offset
= (opcode
>> 3) & 0x1f;
2047 offset
|= (opcode
& 0x0200) >> 4;
2049 snprintf(instruction
->text
, 128,
2050 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2052 (opcode
& 0x0800) ? "N" : "",
2053 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2058 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2059 arm_instruction_t
*instruction
)
2061 /* added in ARMv6 */
2062 snprintf(instruction
->text
, 128,
2063 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2065 (opcode
& 0x0080) ? 'U' : 'S',
2066 (opcode
& 0x0040) ? 'B' : 'H',
2067 opcode
& 0x7, (opcode
>> 3) & 0x7);
2072 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2073 arm_instruction_t
*instruction
)
2075 /* added in ARMv6 */
2076 if ((opcode
& 0x0ff0) == 0x0650)
2077 snprintf(instruction
->text
, 128,
2078 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2080 (opcode
& 0x80) ? "BE" : "LE");
2081 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2082 snprintf(instruction
->text
, 128,
2083 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c %s%s%s",
2085 (opcode
& 0x0010) ? 'D' : 'E',
2086 (opcode
& 0x0004) ? "A" : "",
2087 (opcode
& 0x0002) ? "I" : "",
2088 (opcode
& 0x0001) ? "F" : "");
2093 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2094 arm_instruction_t
*instruction
)
2098 /* added in ARMv6 */
2099 switch (opcode
& 0x00c0) {
2110 snprintf(instruction
->text
, 128,
2111 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2112 address
, opcode
, suffix
,
2113 opcode
& 0x7, (opcode
>> 3) & 0x7);
2118 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2119 arm_instruction_t
*instruction
)
2123 switch ((opcode
>> 4) & 0x0f) {
2140 hint
= "HINT (UNRECOGNIZED)";
2144 snprintf(instruction
->text
, 128,
2145 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2146 address
, opcode
, hint
);
2151 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2152 arm_instruction_t
*instruction
)
2154 unsigned cond
= (opcode
>> 4) & 0x0f;
2155 char *x
= "", *y
= "", *z
= "";
2158 z
= (opcode
& 0x02) ? "T" : "E";
2160 y
= (opcode
& 0x04) ? "T" : "E";
2162 x
= (opcode
& 0x08) ? "T" : "E";
2164 snprintf(instruction
->text
, 128,
2165 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2167 x
, y
, z
, arm_condition_strings
[cond
]);
2169 /* NOTE: strictly speaking, the next 1-4 instructions should
2170 * now be displayed with the relevant conditional suffix...
2176 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2178 /* clear fields, to avoid confusion */
2179 memset(instruction
, 0, sizeof(arm_instruction_t
));
2180 instruction
->opcode
= opcode
;
2181 instruction
->instruction_size
= 2;
2183 if ((opcode
& 0xe000) == 0x0000)
2185 /* add/substract register or immediate */
2186 if ((opcode
& 0x1800) == 0x1800)
2187 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2188 /* shift by immediate */
2190 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2193 /* Add/substract/compare/move immediate */
2194 if ((opcode
& 0xe000) == 0x2000)
2196 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2199 /* Data processing instructions */
2200 if ((opcode
& 0xf800) == 0x4000)
2202 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2205 /* Load from literal pool */
2206 if ((opcode
& 0xf800) == 0x4800)
2208 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2211 /* Load/Store register offset */
2212 if ((opcode
& 0xf000) == 0x5000)
2214 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2217 /* Load/Store immediate offset */
2218 if (((opcode
& 0xe000) == 0x6000)
2219 ||((opcode
& 0xf000) == 0x8000))
2221 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2224 /* Load/Store from/to stack */
2225 if ((opcode
& 0xf000) == 0x9000)
2227 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2231 if ((opcode
& 0xf000) == 0xa000)
2233 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2237 if ((opcode
& 0xf000) == 0xb000)
2239 switch ((opcode
>> 8) & 0x0f) {
2241 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2246 return evaluate_cb_thumb(opcode
, address
, instruction
);
2248 return evaluate_extend_thumb(opcode
, address
, instruction
);
2253 return evaluate_load_store_multiple_thumb(opcode
, address
,
2256 return evaluate_cps_thumb(opcode
, address
, instruction
);
2258 if ((opcode
& 0x00c0) == 0x0080)
2260 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2262 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2264 if (opcode
& 0x000f)
2265 return evaluate_ifthen_thumb(opcode
, address
,
2268 return evaluate_hint_thumb(opcode
, address
,
2272 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2273 snprintf(instruction
->text
, 128,
2274 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2279 /* Load/Store multiple */
2280 if ((opcode
& 0xf000) == 0xc000)
2282 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2285 /* Conditional branch + SWI */
2286 if ((opcode
& 0xf000) == 0xd000)
2288 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2291 if ((opcode
& 0xe000) == 0xe000)
2293 /* Undefined instructions */
2294 if ((opcode
& 0xf801) == 0xe801)
2296 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2297 snprintf(instruction
->text
, 128,
2298 "0x%8.8" PRIx32
" 0x%8.8x\t"
2299 "UNDEFINED INSTRUCTION",
2304 { /* Branch to offset */
2305 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2309 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2313 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2314 arm_instruction_t
*instruction
, char *cp
)
2317 unsigned b21
= 1 << 21;
2318 unsigned b22
= 1 << 22;
2320 /* instead of combining two smaller 16-bit branch instructions,
2321 * Thumb2 uses only one larger 32-bit instruction.
2323 offset
= opcode
& 0x7ff;
2324 offset
|= (opcode
& 0x03ff0000) >> 5;
2325 if (opcode
& (1 << 26)) {
2326 offset
|= 0xff << 23;
2327 if ((opcode
& (1 << 11)) == 0)
2329 if ((opcode
& (1 << 13)) == 0)
2332 if (opcode
& (1 << 11))
2334 if (opcode
& (1 << 13))
2342 address
+= offset
<< 1;
2344 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2345 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2346 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2347 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2348 (opcode
& (1 << 14)) ? "BL" : "B.W",
2354 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2355 arm_instruction_t
*instruction
, char *cp
)
2358 unsigned b17
= 1 << 17;
2359 unsigned b18
= 1 << 18;
2360 unsigned cond
= (opcode
>> 22) & 0x0f;
2362 offset
= opcode
& 0x7ff;
2363 offset
|= (opcode
& 0x003f0000) >> 5;
2364 if (opcode
& (1 << 26)) {
2365 offset
|= 0xffff << 19;
2366 if ((opcode
& (1 << 11)) == 0)
2368 if ((opcode
& (1 << 13)) == 0)
2371 if (opcode
& (1 << 11))
2373 if (opcode
& (1 << 13))
2380 address
+= offset
<< 1;
2382 instruction
->type
= ARM_B
;
2383 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2384 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2385 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2386 arm_condition_strings
[cond
],
2392 static const char *special_name(int number
)
2394 char *special
= "(RESERVED)";
2425 special
= "primask";
2428 special
= "basepri";
2431 special
= "basepri_max";
2434 special
= "faultmask";
2437 special
= "control";
2443 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2444 arm_instruction_t
*instruction
, char *cp
)
2446 const char *mnemonic
;
2448 if (opcode
& 0x0700) {
2449 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2450 strcpy(cp
, "UNDEFINED");
2454 if (opcode
& 0x00f0) {
2455 sprintf(cp
, "DBG\t#%d", opcode
& 0xf);
2459 switch (opcode
& 0x0f) {
2464 mnemonic
= "YIELD.W";
2476 mnemonic
= "HINT.W (UNRECOGNIZED)";
2479 strcpy(cp
, mnemonic
);
2483 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2484 arm_instruction_t
*instruction
, char *cp
)
2486 const char *mnemonic
;
2488 switch ((opcode
>> 4) & 0x0f) {
2502 return ERROR_INVALID_ARGUMENTS
;
2504 strcpy(cp
, mnemonic
);
2508 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2509 arm_instruction_t
*instruction
, char *cp
)
2511 /* permanently undefined */
2512 if ((opcode
& 0x07f07000) == 0x07f02000) {
2513 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2514 strcpy(cp
, "UNDEFINED");
2518 switch ((opcode
>> 12) & 0x5) {
2521 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2525 if (((opcode
>> 23) & 0x07) == 0x07)
2526 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2527 if (opcode
& (1 << 26))
2532 switch ((opcode
>> 20) & 0x7f) {
2535 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2536 (opcode
>> 16) & 0x0f);
2539 return t2ev_hint(opcode
, address
, instruction
, cp
);
2541 return t2ev_misc(opcode
, address
, instruction
, cp
);
2544 sprintf(cp
, "MRS\tr%d, %s", (opcode
>> 16) & 0x0f,
2545 special_name(opcode
& 0xff));
2550 return ERROR_INVALID_ARGUMENTS
;
2553 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
2554 arm_instruction_t
*instruction
, char *cp
)
2556 char *mnemonic
= NULL
;
2557 int rn
= (opcode
>> 16) & 0xf;
2558 int rd
= (opcode
>> 8) & 0xf;
2559 unsigned immed
= opcode
& 0xff;
2564 /* ARMv7-M: A5.3.2 Modified immediate constants */
2565 func
= (opcode
>> 11) & 0x0e;
2568 if (opcode
& (1 << 26))
2571 /* "Modified" immediates */
2572 switch (func
>> 1) {
2579 immed
+= immed
<< 16;
2582 immed
+= immed
<< 8;
2583 immed
+= immed
<< 16;
2587 immed
= ror(immed
, func
);
2590 if (opcode
& (1 << 20))
2593 switch ((opcode
>> 21) & 0xf) {
2596 instruction
->type
= ARM_TST
;
2602 instruction
->type
= ARM_AND
;
2607 instruction
->type
= ARM_BIC
;
2612 instruction
->type
= ARM_MOV
;
2616 instruction
->type
= ARM_ORR
;
2622 instruction
->type
= ARM_MVN
;
2626 // instruction->type = ARM_ORN;
2632 instruction
->type
= ARM_TEQ
;
2638 instruction
->type
= ARM_EOR
;
2644 instruction
->type
= ARM_CMN
;
2650 instruction
->type
= ARM_ADD
;
2655 instruction
->type
= ARM_ADC
;
2659 instruction
->type
= ARM_SBC
;
2664 instruction
->type
= ARM_CMP
;
2670 instruction
->type
= ARM_SUB
;
2675 instruction
->type
= ARM_RSB
;
2679 return ERROR_INVALID_ARGUMENTS
;
2683 sprintf(cp
, "%s\tr%d, #%d\t; %#8.8x",
2684 mnemonic
, rd
, immed
, immed
);
2686 sprintf(cp
, "%s%s\tr%d, r%d, #%d\t; %#8.8x",
2687 mnemonic
, suffix
, rd
, rn
, immed
, immed
);
2692 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
2693 arm_instruction_t
*instruction
, char *cp
)
2695 char *mnemonic
= NULL
;
2696 int rn
= (opcode
>> 16) & 0xf;
2697 int rd
= (opcode
>> 8) & 0xf;
2700 bool is_signed
= false;
2702 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 12);
2703 if (opcode
& (1 << 27))
2706 switch ((opcode
>> 20) & 0x1f) {
2723 /* move constant to top 16 bits of register */
2724 immed
|= (opcode
>> 4) & 0xf000;
2725 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
2732 /* signed/unsigned saturated add */
2733 immed
= (opcode
>> 6) & 0x03;
2734 immed
|= (opcode
>> 10) & 0x1c;
2735 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
2736 is_signed
? "S" : "U",
2737 rd
, (opcode
& 0x1f) + 1, rn
,
2738 (opcode
& (1 << 21)) ? "ASR" : "LSL",
2739 immed
? immed
: 32);
2745 /* signed/unsigned bitfield extract */
2746 immed
= (opcode
>> 6) & 0x03;
2747 immed
|= (opcode
>> 10) & 0x1c;
2748 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
2749 is_signed
? "S" : "U",
2751 (opcode
& 0x1f) + 1);
2754 immed
= (opcode
>> 6) & 0x03;
2755 immed
|= (opcode
>> 10) & 0x1c;
2756 if (rn
== 0xf) /* bitfield clear */
2757 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
2759 (opcode
& 0x1f) + 1 - immed
);
2760 else /* bitfield insert */
2761 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
2763 (opcode
& 0x1f) + 1 - immed
);
2766 return ERROR_INVALID_ARGUMENTS
;
2769 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
2770 rd
, rn
, immed
, immed
);
2774 address
= thumb_alignpc4(address
);
2779 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
2780 * not hiding the pc-relative stuff will sometimes be useful.
2782 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
2786 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
2787 arm_instruction_t
*instruction
, char *cp
)
2789 unsigned op
= (opcode
>> 20) & 0xf;
2795 unsigned rn
= (opcode
>> 16) & 0x0f;
2796 unsigned rt
= (opcode
>> 12) & 0x0f;
2799 return ERROR_INVALID_ARGUMENTS
;
2801 if (opcode
& 0x0800)
2836 return ERROR_INVALID_ARGUMENTS
;
2839 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
2840 size
, rt
, rn
, opcode
& 0x0f,
2841 (opcode
>> 4) & 0x03);
2844 immed
= opcode
& 0x0fff;
2845 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
2846 size
, rt
, rn
, immed
, immed
);
2850 immed
= opcode
& 0x00ff;
2852 switch (opcode
& 0x700) {
2858 return ERROR_INVALID_ARGUMENTS
;
2861 /* two indexed modes will write back rn */
2862 if (opcode
& 0x100) {
2863 if (opcode
& 0x400) /* pre-indexed */
2865 else { /* post-indexed */
2871 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
2872 size
, suffix
, rt
, rn
, p1
,
2873 (opcode
& 0x200) ? "" : "-",
2878 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
2879 arm_instruction_t
*instruction
, char *cp
)
2881 int ra
= (opcode
>> 12) & 0xf;
2884 switch (opcode
& 0x007000f0) {
2887 sprintf(cp
, "MUL\tr%d, r%d, r%d",
2888 (opcode
>> 8) & 0xf, (opcode
>> 16) & 0xf,
2889 (opcode
>> 0) & 0xf);
2891 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
2892 (opcode
>> 8) & 0xf, (opcode
>> 16) & 0xf,
2893 (opcode
>> 0) & 0xf, ra
);
2896 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
2897 (opcode
>> 8) & 0xf, (opcode
>> 16) & 0xf,
2898 (opcode
>> 0) & 0xf, ra
);
2901 return ERROR_INVALID_ARGUMENTS
;
2906 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
2907 arm_instruction_t
*instruction
, char *cp
)
2909 int op
= (opcode
>> 4) & 0xf;
2910 char *infix
= "MUL";
2912 op
+= (opcode
>> 16) & 0x70;
2920 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
2921 (op
& 0x20) ? 'U' : 'S',
2923 (opcode
>> 12) & 0xf,
2924 (opcode
>> 8) & 0xf,
2925 (opcode
>> 16) & 0xf,
2926 (opcode
>> 0) & 0xf);
2930 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
2931 (op
& 0x20) ? 'U' : 'S',
2932 (opcode
>> 8) & 0xf,
2933 (opcode
>> 16) & 0xf,
2934 (opcode
>> 0) & 0xf);
2937 return ERROR_INVALID_ARGUMENTS
;
2943 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
2944 arm_instruction_t
*instruction
, char *cp
)
2946 int rn
= (opcode
>> 16) & 0xf;
2947 int op
= (opcode
>> 22) & 0x6;
2948 int t
= (opcode
>> 21) & 1;
2949 unsigned registers
= opcode
& 0xffff;
2951 if (opcode
& (1 << 20))
2956 sprintf(cp
, "STMB\tr%d%s, ", rn
, t
? "!" : "");
2960 sprintf(cp
, "POP\t");
2962 sprintf(cp
, "LDM\tr%d%s, ", rn
, t
? "!" : "");
2966 sprintf(cp
, "PUSH\t");
2968 sprintf(cp
, "STM\tr%d%s, ", rn
, t
? "!" : "");
2971 sprintf(cp
, "LDMB\tr%d%s, ", rn
, t
? "!" : "");
2974 return ERROR_INVALID_ARGUMENTS
;
2979 for (t
= 0; registers
; t
++, registers
>>= 1) {
2980 if ((registers
& 1) == 0)
2983 sprintf(cp
, "r%d%s", t
, registers
? "," : "");
2992 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
2993 arm_instruction_t
*instruction
, char *cp
)
2995 int op
= (opcode
>> 21) & 0xf;
2996 int rd
= (opcode
>> 8) & 0xf;
2997 int rn
= (opcode
>> 16) & 0xf;
2998 int type
= (opcode
>> 4) & 0x3;
2999 int immed
= (opcode
>> 6) & 0x3;
3003 immed
|= (opcode
>> 10) & 0x7;
3004 if (opcode
& (1 << 21))
3010 if (!(opcode
& (1 << 21)))
3011 return ERROR_INVALID_ARGUMENTS
;
3012 instruction
->type
= ARM_TST
;
3016 instruction
->type
= ARM_AND
;
3020 instruction
->type
= ARM_BIC
;
3025 instruction
->type
= ARM_MOV
;
3029 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3030 suffix
, rd
, (opcode
& 0xf));
3043 sprintf(cp
, "RRX%s.W\tr%d, r%d",
3044 suffix
, rd
, (opcode
& 0xf));
3052 instruction
->type
= ARM_ORR
;
3058 instruction
->type
= ARM_MVN
;
3063 // instruction->type = ARM_ORN;
3069 if (!(opcode
& (1 << 21)))
3070 return ERROR_INVALID_ARGUMENTS
;
3071 instruction
->type
= ARM_TEQ
;
3075 instruction
->type
= ARM_EOR
;
3080 if (!(opcode
& (1 << 21)))
3081 return ERROR_INVALID_ARGUMENTS
;
3082 instruction
->type
= ARM_CMN
;
3086 instruction
->type
= ARM_ADD
;
3090 instruction
->type
= ARM_ADC
;
3094 instruction
->type
= ARM_SBC
;
3099 if (!(opcode
& (1 << 21)))
3100 return ERROR_INVALID_ARGUMENTS
;
3101 instruction
->type
= ARM_CMP
;
3105 instruction
->type
= ARM_SUB
;
3109 instruction
->type
= ARM_RSB
;
3113 return ERROR_INVALID_ARGUMENTS
;
3116 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3117 mnemonic
, suffix
, rd
, rn
, (opcode
& 0xf));
3142 sprintf(cp
, " %s #%d", suffix
, immed
? immed
: 32);
3146 sprintf(cp
, "%s%s.W\tr%d, r%d",
3147 mnemonic
, suffix
, rn
, (opcode
& 0xf));
3151 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3152 mnemonic
, suffix
, rd
, (opcode
& 0xf), immed
? immed
: 32);
3156 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3157 arm_instruction_t
*instruction
, char *cp
)
3162 if (((opcode
>> 4) & 0xf) == 0) {
3163 switch ((opcode
>> 21) & 0x7) {
3177 return ERROR_INVALID_ARGUMENTS
;
3180 instruction
->type
= ARM_MOV
;
3181 if (opcode
& (1 << 20))
3183 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3185 (opcode
>> 8) & 0xf,
3186 (opcode
>> 16) & 0xf,
3187 (opcode
>> 0) & 0xf);
3189 } else if (opcode
& (1 << 7)) {
3190 switch ((opcode
>> 24) & 0xf) {
3195 switch ((opcode
>> 4) & 0x3) {
3197 suffix
= ", ROR #8";
3200 suffix
= ", ROR #16";
3203 suffix
= ", ROR #24";
3206 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3207 (opcode
& (1 << 24)) ? 'U' : 'S',
3208 (opcode
& (1 << 26)) ? 'B' : 'H',
3209 (opcode
>> 8) & 0xf,
3210 (opcode
>> 16) & 0xf,
3217 if (opcode
& (1 << 6))
3218 return ERROR_INVALID_ARGUMENTS
;
3219 if (~opcode
& (0xff << 12))
3220 return ERROR_INVALID_ARGUMENTS
;
3221 if (!(opcode
& (1 << 20)))
3222 return ERROR_INVALID_ARGUMENTS
;
3224 switch (((opcode
>> 19) & 0x04)
3225 | ((opcode
>> 4) & 0x3)) {
3230 mnemonic
= "REV16.W";
3236 mnemonic
= "REVSH.W";
3242 return ERROR_INVALID_ARGUMENTS
;
3244 sprintf(cp
, "%s\tr%d, r%d",
3246 (opcode
>> 8) & 0xf,
3247 (opcode
>> 0) & 0xf);
3250 return ERROR_INVALID_ARGUMENTS
;
3258 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
3259 * always set. That means eventual arm_simulate_step() support for Thumb2
3260 * will need work in this area.
3262 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
3269 /* clear low bit ... it's set on function pointers */
3272 /* clear fields, to avoid confusion */
3273 memset(instruction
, 0, sizeof(arm_instruction_t
));
3275 /* read first halfword, see if this is the only one */
3276 retval
= target_read_u16(target
, address
, &op
);
3277 if (retval
!= ERROR_OK
)
3280 switch (op
& 0xf800) {
3284 /* 32-bit instructions */
3285 instruction
->instruction_size
= 4;
3287 retval
= target_read_u16(target
, address
+ 2, &op
);
3288 if (retval
!= ERROR_OK
)
3291 instruction
->opcode
= opcode
;
3294 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
3295 return thumb_evaluate_opcode(op
, address
, instruction
);
3298 snprintf(instruction
->text
, 128,
3299 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
3301 cp
= strchr(instruction
->text
, 0);
3302 retval
= ERROR_FAIL
;
3304 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
3305 if ((opcode
& 0x1a008000) == 0x10000000)
3306 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
3308 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
3309 else if ((opcode
& 0x1a008000) == 0x12000000)
3310 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
3312 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
3313 else if ((opcode
& 0x18008000) == 0x10008000)
3314 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
3316 /* ARMv7-M: A5.3.5 Load/store multiple */
3317 else if ((opcode
& 0x1e400000) == 0x08000000)
3318 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
3320 /* ARMv7-M: A5.3.10 Store single data item */
3321 else if ((opcode
& 0x1f100000) == 0x18000000)
3322 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
3324 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
3325 else if ((opcode
& 0x1e000000) == 0x0a000000)
3326 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
3328 /* ARMv7-M: A5.3.12 Data processing (register) */
3329 else if ((opcode
& 0x1f000000) == 0x1a000000)
3330 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
3332 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
3333 else if ((opcode
& 0x1f800000) == 0x1b000000)
3334 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
3336 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
3337 else if ((opcode
& 0x1f800000) == 0x1b800000)
3338 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
3340 /* FIXME decode more 32-bit instructions */
3342 if (retval
== ERROR_OK
)
3345 if (retval
== ERROR_INVALID_ARGUMENTS
) {
3346 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3347 strcpy(cp
, "UNDEFINED OPCODE");
3351 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08x)", opcode
);
3353 strcpy(cp
, "(32-bit Thumb2 ...)");
3357 int arm_access_size(arm_instruction_t
*instruction
)
3359 if ((instruction
->type
== ARM_LDRB
)
3360 || (instruction
->type
== ARM_LDRBT
)
3361 || (instruction
->type
== ARM_LDRSB
)
3362 || (instruction
->type
== ARM_STRB
)
3363 || (instruction
->type
== ARM_STRBT
))
3367 else if ((instruction
->type
== ARM_LDRH
)
3368 || (instruction
->type
== ARM_LDRSH
)
3369 || (instruction
->type
== ARM_STRH
))
3373 else if ((instruction
->type
== ARM_LDR
)
3374 || (instruction
->type
== ARM_LDRT
)
3375 || (instruction
->type
== ARM_STR
)
3376 || (instruction
->type
== ARM_STRT
))
3380 else if ((instruction
->type
== ARM_LDRD
)
3381 || (instruction
->type
== ARM_STRD
))
3387 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)