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
;
1516 high_reg
= (opcode
& 0x0400) >> 10;
1517 op
= (opcode
& 0x03C0) >> 6;
1519 Rd
= (opcode
& 0x0007);
1520 Rm
= (opcode
& 0x0038) >> 3;
1521 H1
= (opcode
& 0x0080) >> 7;
1522 H2
= (opcode
& 0x0040) >> 6;
1524 instruction
->info
.data_proc
.Rd
= Rd
;
1525 instruction
->info
.data_proc
.Rn
= Rd
;
1526 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1527 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1528 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1539 instruction
->type
= ARM_ADD
;
1543 instruction
->type
= ARM_CMP
;
1547 instruction
->type
= ARM_MOV
;
1551 if ((opcode
& 0x7) == 0x0)
1553 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1556 instruction
->type
= ARM_BLX
;
1557 snprintf(instruction
->text
, 128,
1559 " 0x%4.4x \tBLX\tr%i",
1560 address
, opcode
, Rm
);
1564 instruction
->type
= ARM_BX
;
1565 snprintf(instruction
->text
, 128,
1567 " 0x%4.4x \tBX\tr%i",
1568 address
, opcode
, Rm
);
1573 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1574 snprintf(instruction
->text
, 128,
1577 "UNDEFINED INSTRUCTION",
1589 instruction
->type
= ARM_AND
;
1593 instruction
->type
= ARM_EOR
;
1597 instruction
->type
= ARM_MOV
;
1599 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1600 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1601 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1602 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1605 instruction
->type
= ARM_MOV
;
1607 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1608 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1609 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1610 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1613 instruction
->type
= ARM_MOV
;
1615 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1616 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1617 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1618 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1621 instruction
->type
= ARM_ADC
;
1625 instruction
->type
= ARM_SBC
;
1629 instruction
->type
= ARM_MOV
;
1631 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1632 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1633 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1634 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1637 instruction
->type
= ARM_TST
;
1641 instruction
->type
= ARM_RSB
;
1643 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1644 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1645 instruction
->info
.data_proc
.Rn
= Rm
;
1648 instruction
->type
= ARM_CMP
;
1652 instruction
->type
= ARM_CMN
;
1656 instruction
->type
= ARM_ORR
;
1660 instruction
->type
= ARM_MUL
;
1664 instruction
->type
= ARM_BIC
;
1668 instruction
->type
= ARM_MVN
;
1674 snprintf(instruction
->text
, 128,
1675 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
1676 address
, opcode
, mnemonic
, Rd
, Rm
);
1681 /* PC-relative data addressing is word-aligned even with Thumb */
1682 static inline uint32_t thumb_alignpc4(uint32_t addr
)
1684 return (addr
+ 4) & ~3;
1687 int evaluate_load_literal_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1690 uint8_t Rd
= (opcode
>> 8) & 0x7;
1692 instruction
->type
= ARM_LDR
;
1693 immediate
= opcode
& 0x000000ff;
1696 instruction
->info
.load_store
.Rd
= Rd
;
1697 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
1698 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1699 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1700 instruction
->info
.load_store
.offset
.offset
= immediate
;
1702 snprintf(instruction
->text
, 128,
1703 "0x%8.8" PRIx32
" 0x%4.4x \t"
1704 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8x",
1705 address
, opcode
, Rd
, immediate
,
1706 thumb_alignpc4(address
) + immediate
);
1711 int evaluate_load_store_reg_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1713 uint8_t Rd
= (opcode
>> 0) & 0x7;
1714 uint8_t Rn
= (opcode
>> 3) & 0x7;
1715 uint8_t Rm
= (opcode
>> 6) & 0x7;
1716 uint8_t opc
= (opcode
>> 9) & 0x7;
1717 char *mnemonic
= NULL
;
1722 instruction
->type
= ARM_STR
;
1726 instruction
->type
= ARM_STRH
;
1730 instruction
->type
= ARM_STRB
;
1734 instruction
->type
= ARM_LDRSB
;
1738 instruction
->type
= ARM_LDR
;
1742 instruction
->type
= ARM_LDRH
;
1746 instruction
->type
= ARM_LDRB
;
1750 instruction
->type
= ARM_LDRSH
;
1755 snprintf(instruction
->text
, 128,
1756 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
1757 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
1759 instruction
->info
.load_store
.Rd
= Rd
;
1760 instruction
->info
.load_store
.Rn
= Rn
;
1761 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1762 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
1763 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1768 int evaluate_load_store_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1770 uint32_t offset
= (opcode
>> 6) & 0x1f;
1771 uint8_t Rd
= (opcode
>> 0) & 0x7;
1772 uint8_t Rn
= (opcode
>> 3) & 0x7;
1773 uint32_t L
= opcode
& (1 << 11);
1774 uint32_t B
= opcode
& (1 << 12);
1781 instruction
->type
= ARM_LDR
;
1786 instruction
->type
= ARM_STR
;
1790 if ((opcode
&0xF000) == 0x8000)
1801 snprintf(instruction
->text
, 128,
1802 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
1803 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
1805 instruction
->info
.load_store
.Rd
= Rd
;
1806 instruction
->info
.load_store
.Rn
= Rn
;
1807 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1808 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1809 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
1814 int evaluate_load_store_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1816 uint32_t offset
= opcode
& 0xff;
1817 uint8_t Rd
= (opcode
>> 8) & 0x7;
1818 uint32_t L
= opcode
& (1 << 11);
1823 instruction
->type
= ARM_LDR
;
1828 instruction
->type
= ARM_STR
;
1832 snprintf(instruction
->text
, 128,
1833 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
1834 address
, opcode
, mnemonic
, Rd
, offset
*4);
1836 instruction
->info
.load_store
.Rd
= Rd
;
1837 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
1838 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1839 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1840 instruction
->info
.load_store
.offset
.offset
= offset
*4;
1845 int evaluate_add_sp_pc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1847 uint32_t imm
= opcode
& 0xff;
1848 uint8_t Rd
= (opcode
>> 8) & 0x7;
1850 uint32_t SP
= opcode
& (1 << 11);
1853 instruction
->type
= ARM_ADD
;
1866 snprintf(instruction
->text
, 128,
1867 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
1868 address
, opcode
, Rd
, reg_name
, imm
* 4);
1870 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1871 instruction
->info
.data_proc
.Rd
= Rd
;
1872 instruction
->info
.data_proc
.Rn
= Rn
;
1873 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1878 int evaluate_adjust_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1880 uint32_t imm
= opcode
& 0x7f;
1881 uint8_t opc
= opcode
& (1 << 7);
1887 instruction
->type
= ARM_SUB
;
1892 instruction
->type
= ARM_ADD
;
1896 snprintf(instruction
->text
, 128,
1897 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
1898 address
, opcode
, mnemonic
, imm
*4);
1900 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1901 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
1902 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
1903 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1908 int evaluate_breakpoint_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1910 uint32_t imm
= opcode
& 0xff;
1912 instruction
->type
= ARM_BKPT
;
1914 snprintf(instruction
->text
, 128,
1915 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
1916 address
, opcode
, imm
);
1921 int evaluate_load_store_multiple_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1923 uint32_t reg_list
= opcode
& 0xff;
1924 uint32_t L
= opcode
& (1 << 11);
1925 uint32_t R
= opcode
& (1 << 8);
1926 uint8_t Rn
= (opcode
>> 8) & 7;
1927 uint8_t addr_mode
= 0 /* IA */;
1931 char ptr_name
[7] = "";
1934 if ((opcode
& 0xf000) == 0xc000)
1935 { /* generic load/store multiple */
1938 instruction
->type
= ARM_LDM
;
1943 instruction
->type
= ARM_STM
;
1946 snprintf(ptr_name
,7,"r%i!, ",Rn
);
1953 instruction
->type
= ARM_LDM
;
1956 reg_list
|= (1 << 15) /*PC*/;
1960 instruction
->type
= ARM_STM
;
1962 addr_mode
= 3; /*DB*/
1964 reg_list
|= (1 << 14) /*LR*/;
1968 reg_names_p
= reg_names
;
1969 for (i
= 0; i
<= 15; i
++)
1971 if (reg_list
& (1 << i
))
1972 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
1974 if (reg_names_p
> reg_names
)
1975 reg_names_p
[-2] = '\0';
1976 else /* invalid op : no registers */
1977 reg_names
[0] = '\0';
1979 snprintf(instruction
->text
, 128,
1980 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
1981 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
1983 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
1984 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1985 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
1990 int evaluate_cond_branch_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1992 uint32_t offset
= opcode
& 0xff;
1993 uint8_t cond
= (opcode
>> 8) & 0xf;
1994 uint32_t target_address
;
1998 instruction
->type
= ARM_SWI
;
1999 snprintf(instruction
->text
, 128,
2000 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2001 address
, opcode
, offset
);
2004 else if (cond
== 0xe)
2006 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2007 snprintf(instruction
->text
, 128,
2008 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2013 /* sign extend 8-bit offset */
2014 if (offset
& 0x00000080)
2015 offset
= 0xffffff00 | offset
;
2017 target_address
= address
+ 4 + (offset
<< 1);
2019 snprintf(instruction
->text
, 128,
2020 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2022 arm_condition_strings
[cond
], target_address
);
2024 instruction
->type
= ARM_B
;
2025 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2026 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2031 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2032 arm_instruction_t
*instruction
)
2036 /* added in Thumb2 */
2037 offset
= (opcode
>> 3) & 0x1f;
2038 offset
|= (opcode
& 0x0200) >> 4;
2040 snprintf(instruction
->text
, 128,
2041 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2043 (opcode
& 0x0800) ? "N" : "",
2044 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2049 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2050 arm_instruction_t
*instruction
)
2052 /* added in ARMv6 */
2053 snprintf(instruction
->text
, 128,
2054 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2056 (opcode
& 0x0080) ? 'U' : 'S',
2057 (opcode
& 0x0040) ? 'B' : 'H',
2058 opcode
& 0x7, (opcode
>> 3) & 0x7);
2063 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2064 arm_instruction_t
*instruction
)
2066 /* added in ARMv6 */
2067 if ((opcode
& 0x0ff0) == 0x0650)
2068 snprintf(instruction
->text
, 128,
2069 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2071 (opcode
& 0x80) ? "BE" : "LE");
2072 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2073 snprintf(instruction
->text
, 128,
2074 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c %s%s%s",
2076 (opcode
& 0x0010) ? 'D' : 'E',
2077 (opcode
& 0x0004) ? "A" : "",
2078 (opcode
& 0x0002) ? "I" : "",
2079 (opcode
& 0x0001) ? "F" : "");
2084 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2085 arm_instruction_t
*instruction
)
2089 /* added in ARMv6 */
2090 switch (opcode
& 0x00c0) {
2101 snprintf(instruction
->text
, 128,
2102 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2103 address
, opcode
, suffix
,
2104 opcode
& 0x7, (opcode
>> 3) & 0x7);
2109 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2110 arm_instruction_t
*instruction
)
2114 switch ((opcode
>> 4) & 0x0f) {
2131 hint
= "HINT (UNRECOGNIZED)";
2135 snprintf(instruction
->text
, 128,
2136 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2137 address
, opcode
, hint
);
2142 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2143 arm_instruction_t
*instruction
)
2145 unsigned cond
= (opcode
>> 4) & 0x0f;
2146 char *x
= "", *y
= "", *z
= "";
2149 z
= (opcode
& 0x02) ? "T" : "E";
2151 y
= (opcode
& 0x04) ? "T" : "E";
2153 x
= (opcode
& 0x08) ? "T" : "E";
2155 snprintf(instruction
->text
, 128,
2156 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2158 x
, y
, z
, arm_condition_strings
[cond
]);
2160 /* NOTE: strictly speaking, the next 1-4 instructions should
2161 * now be displayed with the relevant conditional suffix...
2167 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
2169 /* clear fields, to avoid confusion */
2170 memset(instruction
, 0, sizeof(arm_instruction_t
));
2171 instruction
->opcode
= opcode
;
2172 instruction
->instruction_size
= 2;
2174 if ((opcode
& 0xe000) == 0x0000)
2176 /* add/substract register or immediate */
2177 if ((opcode
& 0x1800) == 0x1800)
2178 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2179 /* shift by immediate */
2181 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2184 /* Add/substract/compare/move immediate */
2185 if ((opcode
& 0xe000) == 0x2000)
2187 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2190 /* Data processing instructions */
2191 if ((opcode
& 0xf800) == 0x4000)
2193 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2196 /* Load from literal pool */
2197 if ((opcode
& 0xf800) == 0x4800)
2199 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2202 /* Load/Store register offset */
2203 if ((opcode
& 0xf000) == 0x5000)
2205 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2208 /* Load/Store immediate offset */
2209 if (((opcode
& 0xe000) == 0x6000)
2210 ||((opcode
& 0xf000) == 0x8000))
2212 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2215 /* Load/Store from/to stack */
2216 if ((opcode
& 0xf000) == 0x9000)
2218 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2222 if ((opcode
& 0xf000) == 0xa000)
2224 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2228 if ((opcode
& 0xf000) == 0xb000)
2230 switch ((opcode
>> 8) & 0x0f) {
2232 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2237 return evaluate_cb_thumb(opcode
, address
, instruction
);
2239 return evaluate_extend_thumb(opcode
, address
, instruction
);
2244 return evaluate_load_store_multiple_thumb(opcode
, address
,
2247 return evaluate_cps_thumb(opcode
, address
, instruction
);
2249 if ((opcode
& 0x00c0) == 0x0080)
2251 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2253 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2255 if (opcode
& 0x000f)
2256 return evaluate_ifthen_thumb(opcode
, address
,
2259 return evaluate_hint_thumb(opcode
, address
,
2263 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2264 snprintf(instruction
->text
, 128,
2265 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2270 /* Load/Store multiple */
2271 if ((opcode
& 0xf000) == 0xc000)
2273 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2276 /* Conditional branch + SWI */
2277 if ((opcode
& 0xf000) == 0xd000)
2279 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2282 if ((opcode
& 0xe000) == 0xe000)
2284 /* Undefined instructions */
2285 if ((opcode
& 0xf801) == 0xe801)
2287 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2288 snprintf(instruction
->text
, 128,
2289 "0x%8.8" PRIx32
" 0x%8.8x\t"
2290 "UNDEFINED INSTRUCTION",
2295 { /* Branch to offset */
2296 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2300 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2304 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2305 arm_instruction_t
*instruction
, char *cp
)
2308 unsigned b21
= 1 << 21;
2309 unsigned b22
= 1 << 22;
2311 /* instead of combining two smaller 16-bit branch instructions,
2312 * Thumb2 uses only one larger 32-bit instruction.
2314 offset
= opcode
& 0x7ff;
2315 offset
|= (opcode
& 0x03ff0000) >> 5;
2316 if (opcode
& (1 << 26)) {
2317 offset
|= 0xff << 23;
2318 if ((opcode
& (1 << 11)) == 0)
2320 if ((opcode
& (1 << 13)) == 0)
2323 if (opcode
& (1 << 11))
2325 if (opcode
& (1 << 13))
2333 address
+= offset
<< 1;
2335 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2336 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2337 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2338 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2339 (opcode
& (1 << 14)) ? "BL" : "B.W",
2345 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2346 arm_instruction_t
*instruction
, char *cp
)
2349 unsigned b17
= 1 << 17;
2350 unsigned b18
= 1 << 18;
2351 unsigned cond
= (opcode
>> 22) & 0x0f;
2353 offset
= opcode
& 0x7ff;
2354 offset
|= (opcode
& 0x003f0000) >> 5;
2355 if (opcode
& (1 << 26)) {
2356 offset
|= 0xffff << 19;
2357 if ((opcode
& (1 << 11)) == 0)
2359 if ((opcode
& (1 << 13)) == 0)
2362 if (opcode
& (1 << 11))
2364 if (opcode
& (1 << 13))
2371 address
+= offset
<< 1;
2373 instruction
->type
= ARM_B
;
2374 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2375 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2376 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2377 arm_condition_strings
[cond
],
2383 static const char *special_name(int number
)
2385 char *special
= "(RESERVED)";
2416 special
= "primask";
2419 special
= "basepri";
2422 special
= "basepri_max";
2425 special
= "faultmask";
2428 special
= "control";
2434 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2435 arm_instruction_t
*instruction
, char *cp
)
2437 const char *mnemonic
;
2439 if (opcode
& 0x0700) {
2440 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2441 strcpy(cp
, "UNDEFINED");
2445 if (opcode
& 0x00f0) {
2446 sprintf(cp
, "DBG\t#%d", opcode
& 0xf);
2450 switch (opcode
& 0x0f) {
2455 mnemonic
= "YIELD.W";
2467 mnemonic
= "HINT.W (UNRECOGNIZED)";
2470 strcpy(cp
, mnemonic
);
2474 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2475 arm_instruction_t
*instruction
, char *cp
)
2477 const char *mnemonic
;
2479 switch ((opcode
>> 4) & 0x0f) {
2493 return ERROR_INVALID_ARGUMENTS
;
2495 strcpy(cp
, mnemonic
);
2499 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
2500 arm_instruction_t
*instruction
, char *cp
)
2502 /* permanently undefined */
2503 if ((opcode
& 0x07f07000) == 0x07f02000) {
2504 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2505 strcpy(cp
, "UNDEFINED");
2509 switch ((opcode
>> 12) & 0x5) {
2512 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
2516 if (((opcode
>> 23) & 0x07) == 0x07)
2517 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
2518 if (opcode
& (1 << 26))
2523 switch ((opcode
>> 20) & 0x7f) {
2526 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
2527 (opcode
>> 16) & 0x0f);
2530 return t2ev_hint(opcode
, address
, instruction
, cp
);
2532 return t2ev_misc(opcode
, address
, instruction
, cp
);
2535 sprintf(cp
, "MRS\tr%d, %s", (opcode
>> 16) & 0x0f,
2536 special_name(opcode
& 0xff));
2541 return ERROR_INVALID_ARGUMENTS
;
2544 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
2545 arm_instruction_t
*instruction
, char *cp
)
2547 char *mnemonic
= NULL
;
2548 int rn
= (opcode
>> 16) & 0xf;
2549 int rd
= (opcode
>> 8) & 0xf;
2550 unsigned immed
= opcode
& 0xff;
2555 /* ARMv7-M: A5.3.2 Modified immediate constants */
2556 func
= (opcode
>> 11) & 0x0e;
2559 if (opcode
& (1 << 26))
2562 /* "Modified" immediates */
2563 switch (func
>> 1) {
2570 immed
+= immed
<< 16;
2573 immed
+= immed
<< 8;
2574 immed
+= immed
<< 16;
2578 immed
= ror(immed
, func
);
2581 if (opcode
& (1 << 20))
2584 switch ((opcode
>> 21) & 0xf) {
2587 instruction
->type
= ARM_TST
;
2593 instruction
->type
= ARM_AND
;
2598 instruction
->type
= ARM_BIC
;
2603 instruction
->type
= ARM_MOV
;
2607 instruction
->type
= ARM_ORR
;
2613 instruction
->type
= ARM_MVN
;
2617 // instruction->type = ARM_ORN;
2623 instruction
->type
= ARM_TEQ
;
2629 instruction
->type
= ARM_EOR
;
2635 instruction
->type
= ARM_CMN
;
2641 instruction
->type
= ARM_ADD
;
2646 instruction
->type
= ARM_ADC
;
2650 instruction
->type
= ARM_SBC
;
2655 instruction
->type
= ARM_CMP
;
2661 instruction
->type
= ARM_SUB
;
2666 instruction
->type
= ARM_RSB
;
2670 return ERROR_INVALID_ARGUMENTS
;
2674 sprintf(cp
, "%s\tr%d, #%d\t; %#8.8x",
2675 mnemonic
, rd
, immed
, immed
);
2677 sprintf(cp
, "%s%s\tr%d, r%d, #%d\t; %#8.8x",
2678 mnemonic
, suffix
, rd
, rn
, immed
, immed
);
2683 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
2684 arm_instruction_t
*instruction
, char *cp
)
2686 char *mnemonic
= NULL
;
2687 int rn
= (opcode
>> 16) & 0xf;
2688 int rd
= (opcode
>> 8) & 0xf;
2691 bool is_signed
= false;
2693 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 12);
2694 if (opcode
& (1 << 27))
2697 switch ((opcode
>> 20) & 0x1f) {
2714 /* move constant to top 16 bits of register */
2715 immed
|= (opcode
>> 4) & 0xf000;
2716 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
2723 /* signed/unsigned saturated add */
2724 immed
= (opcode
>> 6) & 0x03;
2725 immed
|= (opcode
>> 10) & 0x1c;
2726 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
2727 is_signed
? "S" : "U",
2728 rd
, (opcode
& 0x1f) + 1, rn
,
2729 (opcode
& (1 << 21)) ? "ASR" : "LSL",
2730 immed
? immed
: 32);
2736 /* signed/unsigned bitfield extract */
2737 immed
= (opcode
>> 6) & 0x03;
2738 immed
|= (opcode
>> 10) & 0x1c;
2739 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
2740 is_signed
? "S" : "U",
2742 (opcode
& 0x1f) + 1);
2745 immed
= (opcode
>> 6) & 0x03;
2746 immed
|= (opcode
>> 10) & 0x1c;
2747 if (rn
== 0xf) /* bitfield clear */
2748 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
2750 (opcode
& 0x1f) + 1 - immed
);
2751 else /* bitfield insert */
2752 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
2754 (opcode
& 0x1f) + 1 - immed
);
2757 return ERROR_INVALID_ARGUMENTS
;
2760 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
2761 rd
, rn
, immed
, immed
);
2765 address
= thumb_alignpc4(address
);
2770 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
2771 * not hiding the pc-relative stuff will sometimes be useful.
2773 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
2778 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
2779 * always set. That means eventual arm_simulate_step() support for Thumb2
2780 * will need work in this area.
2782 int thumb2_opcode(target_t
*target
, uint32_t address
, arm_instruction_t
*instruction
)
2789 /* clear low bit ... it's set on function pointers */
2792 /* clear fields, to avoid confusion */
2793 memset(instruction
, 0, sizeof(arm_instruction_t
));
2795 /* read first halfword, see if this is the only one */
2796 retval
= target_read_u16(target
, address
, &op
);
2797 if (retval
!= ERROR_OK
)
2800 switch (op
& 0xf800) {
2804 /* 32-bit instructions */
2805 instruction
->instruction_size
= 4;
2807 retval
= target_read_u16(target
, address
+ 2, &op
);
2808 if (retval
!= ERROR_OK
)
2811 instruction
->opcode
= opcode
;
2814 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
2815 return thumb_evaluate_opcode(op
, address
, instruction
);
2818 snprintf(instruction
->text
, 128,
2819 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
2821 cp
= strchr(instruction
->text
, 0);
2822 retval
= ERROR_FAIL
;
2824 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
2825 if ((opcode
& 0x1a008000) == 0x10000000)
2826 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
2828 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
2829 else if ((opcode
& 0x1a008000) == 0x12000000)
2830 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
2832 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
2833 else if ((opcode
& 0x18008000) == 0x10008000)
2834 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
2836 /* FIXME decode more 32-bit instructions */
2838 if (retval
== ERROR_OK
)
2841 if (retval
== ERROR_INVALID_ARGUMENTS
) {
2842 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2843 strcpy(cp
, "UNDEFINED OPCODE");
2847 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08x)", opcode
);
2849 strcpy(cp
, "(32-bit Thumb2 ...)");
2853 int arm_access_size(arm_instruction_t
*instruction
)
2855 if ((instruction
->type
== ARM_LDRB
)
2856 || (instruction
->type
== ARM_LDRBT
)
2857 || (instruction
->type
== ARM_LDRSB
)
2858 || (instruction
->type
== ARM_STRB
)
2859 || (instruction
->type
== ARM_STRBT
))
2863 else if ((instruction
->type
== ARM_LDRH
)
2864 || (instruction
->type
== ARM_LDRSH
)
2865 || (instruction
->type
== ARM_STRH
))
2869 else if ((instruction
->type
== ARM_LDR
)
2870 || (instruction
->type
== ARM_LDRT
)
2871 || (instruction
->type
== ARM_STR
)
2872 || (instruction
->type
== ARM_STRT
))
2876 else if ((instruction
->type
== ARM_LDRD
)
2877 || (instruction
->type
== ARM_STRD
))
2883 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)