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 ***************************************************************************/
24 #include "arm_disassembler.h"
28 /* textual represenation of the condition field */
29 /* ALways (default) is ommitted (empty string) */
30 char *arm_condition_strings
[] =
32 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
35 /* make up for C's missing ROR */
36 u32
ror(u32 value
, int places
)
38 return (value
>> places
) | (value
<< (32 - places
));
41 int evaluate_pld(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
44 if ((opcode
& 0x0d70f0000) == 0x0550f000)
46 instruction
->type
= ARM_PLD
;
48 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tPLD ...TODO...", address
, opcode
);
54 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
58 LOG_ERROR("should never reach this point");
62 int evaluate_swi(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
64 instruction
->type
= ARM_SWI
;
66 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSWI 0x%6.6x", address
, opcode
, (opcode
& 0xffffff));
71 int evaluate_blx_imm(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
77 instruction
->type
= ARM_BLX
;
78 immediate
= opcode
& 0x00ffffff;
80 /* sign extend 24-bit immediate */
81 if (immediate
& 0x00800000)
82 offset
= 0xff000000 | immediate
;
86 /* shift two bits left */
89 /* odd/event halfword */
90 if (opcode
& 0x01000000)
93 target_address
= address
+ 8 + offset
;
95 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBLX 0x%8.8x", address
, opcode
, target_address
);
97 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
98 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
103 int evaluate_b_bl(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
110 immediate
= opcode
& 0x00ffffff;
111 L
= (opcode
& 0x01000000) >> 24;
113 /* sign extend 24-bit immediate */
114 if (immediate
& 0x00800000)
115 offset
= 0xff000000 | immediate
;
119 /* shift two bits left */
122 target_address
= address
+ 8 + offset
;
125 instruction
->type
= ARM_BL
;
127 instruction
->type
= ARM_B
;
129 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tB%s%s 0x%8.8x", address
, opcode
,
130 (L
) ? "L" : "", COND(opcode
), target_address
);
132 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
133 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
138 /* Coprocessor load/store and double register transfers */
139 /* both normal and extended instruction space (condition field b1111) */
140 int evaluate_ldc_stc_mcrr_mrrc(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
142 u8 cp_num
= (opcode
& 0xf00) >> 8;
145 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
147 u8 cp_opcode
, Rd
, Rn
, CRm
;
150 cp_opcode
= (opcode
& 0xf0) >> 4;
151 Rd
= (opcode
& 0xf000) >> 12;
152 Rn
= (opcode
& 0xf0000) >> 16;
153 CRm
= (opcode
& 0xf);
156 if ((opcode
& 0x0ff00000) == 0x0c400000)
158 instruction
->type
= ARM_MCRR
;
163 if ((opcode
& 0x0ff00000) == 0x0c500000)
165 instruction
->type
= ARM_MRRC
;
169 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, %x, r%i, r%i, c%i",
170 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
172 else /* LDC or STC */
177 char addressing_mode
[32];
179 CRd
= (opcode
& 0xf000) >> 12;
180 Rn
= (opcode
& 0xf0000) >> 16;
181 offset
= (opcode
& 0xff);
184 if (opcode
& 0x00100000)
186 instruction
->type
= ARM_LDC
;
191 instruction
->type
= ARM_STC
;
195 U
= (opcode
& 0x00800000) >> 23;
196 N
= (opcode
& 0x00400000) >> 22;
198 /* addressing modes */
199 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
200 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
201 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
202 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
203 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
204 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
205 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
206 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
208 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s p%i, c%i, %s",
209 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
211 cp_num
, CRd
, addressing_mode
);
217 /* Coprocessor data processing instructions */
218 /* Coprocessor register transfer instructions */
219 /* both normal and extended instruction space (condition field b1111) */
220 int evaluate_cdp_mcr_mrc(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
224 u8 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
226 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
227 cp_num
= (opcode
& 0xf00) >> 8;
228 CRd_Rd
= (opcode
& 0xf000) >> 12;
229 CRn
= (opcode
& 0xf0000) >> 16;
230 CRm
= (opcode
& 0xf);
231 opcode_2
= (opcode
& 0xe0) >> 5;
234 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
236 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
238 instruction
->type
= ARM_MRC
;
241 else /* bit 20 not set -> MCR */
243 instruction
->type
= ARM_MCR
;
247 opcode_1
= (opcode
& 0x00e00000) >> 21;
249 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
250 address
, opcode
, mnemonic
, cond
,
251 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
253 else /* bit 4 not set -> CDP */
255 instruction
->type
= ARM_CDP
;
258 opcode_1
= (opcode
& 0x00f00000) >> 20;
260 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
261 address
, opcode
, mnemonic
, cond
,
262 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
268 /* Load/store instructions */
269 int evaluate_load_store(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
273 char *operation
; /* "LDR" or "STR" */
274 char *suffix
; /* "", "B", "T", "BT" */
278 I
= (opcode
& 0x02000000) >> 25;
279 P
= (opcode
& 0x01000000) >> 24;
280 U
= (opcode
& 0x00800000) >> 23;
281 B
= (opcode
& 0x00400000) >> 22;
282 W
= (opcode
& 0x00200000) >> 21;
283 L
= (opcode
& 0x00100000) >> 20;
285 /* target register */
286 Rd
= (opcode
& 0xf000) >> 12;
289 Rn
= (opcode
& 0xf0000) >> 16;
291 instruction
->info
.load_store
.Rd
= Rd
;
292 instruction
->info
.load_store
.Rn
= Rn
;
293 instruction
->info
.load_store
.U
= U
;
295 /* determine operation */
301 /* determine instruction type and suffix */
304 if ((P
== 0) && (W
== 1))
307 instruction
->type
= ARM_LDRBT
;
309 instruction
->type
= ARM_STRBT
;
315 instruction
->type
= ARM_LDRB
;
317 instruction
->type
= ARM_STRB
;
323 if ((P
== 0) && (W
== 1))
326 instruction
->type
= ARM_LDRT
;
328 instruction
->type
= ARM_STRT
;
334 instruction
->type
= ARM_LDR
;
336 instruction
->type
= ARM_STR
;
341 if (!I
) /* #+-<offset_12> */
343 u32 offset_12
= (opcode
& 0xfff);
345 snprintf(offset
, 32, ", #%s0x%x", (U
) ? "" : "-", offset_12
);
347 snprintf(offset
, 32, "%s", "");
349 instruction
->info
.load_store
.offset_mode
= 0;
350 instruction
->info
.load_store
.offset
.offset
= offset_12
;
352 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
357 shift_imm
= (opcode
& 0xf80) >> 7;
358 shift
= (opcode
& 0x60) >> 5;
361 /* LSR encodes a shift by 32 bit as 0x0 */
362 if ((shift
== 0x1) && (shift_imm
== 0x0))
365 /* ASR encodes a shift by 32 bit as 0x0 */
366 if ((shift
== 0x2) && (shift_imm
== 0x0))
369 /* ROR by 32 bit is actually a RRX */
370 if ((shift
== 0x3) && (shift_imm
== 0x0))
373 instruction
->info
.load_store
.offset_mode
= 1;
374 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
375 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
376 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
378 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
380 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
382 else /* +-<Rm>, <Shift>, #<shift_imm> */
387 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
390 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
393 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
396 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
399 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
407 if (W
== 0) /* offset */
409 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]",
410 address
, opcode
, operation
, COND(opcode
), suffix
,
413 instruction
->info
.load_store
.index_mode
= 0;
415 else /* pre-indexed */
417 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!",
418 address
, opcode
, operation
, COND(opcode
), suffix
,
421 instruction
->info
.load_store
.index_mode
= 1;
424 else /* post-indexed */
426 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s",
427 address
, opcode
, operation
, COND(opcode
), suffix
,
430 instruction
->info
.load_store
.index_mode
= 2;
436 /* Miscellaneous load/store instructions */
437 int evaluate_misc_load_store(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
439 u8 P
, U
, I
, W
, L
, S
, H
;
441 char *operation
; /* "LDR" or "STR" */
442 char *suffix
; /* "H", "SB", "SH", "D" */
446 P
= (opcode
& 0x01000000) >> 24;
447 U
= (opcode
& 0x00800000) >> 23;
448 I
= (opcode
& 0x00400000) >> 22;
449 W
= (opcode
& 0x00200000) >> 21;
450 L
= (opcode
& 0x00100000) >> 20;
451 S
= (opcode
& 0x00000040) >> 6;
452 H
= (opcode
& 0x00000020) >> 5;
454 /* target register */
455 Rd
= (opcode
& 0xf000) >> 12;
458 Rn
= (opcode
& 0xf0000) >> 16;
460 instruction
->info
.load_store
.Rd
= Rd
;
461 instruction
->info
.load_store
.Rn
= Rn
;
462 instruction
->info
.load_store
.U
= U
;
464 /* determine instruction type and suffix */
472 instruction
->type
= ARM_LDRSH
;
478 instruction
->type
= ARM_LDRSB
;
482 else /* there are no signed stores, so this is used to encode double-register load/stores */
488 instruction
->type
= ARM_STRD
;
493 instruction
->type
= ARM_LDRD
;
503 instruction
->type
= ARM_LDRH
;
508 instruction
->type
= ARM_STRH
;
512 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
514 u32 offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
515 snprintf(offset
, 32, "#%s0x%x", (U
) ? "" : "-", offset_8
);
517 instruction
->info
.load_store
.offset_mode
= 0;
518 instruction
->info
.load_store
.offset
.offset
= offset_8
;
520 else /* Register offset/index (+-<Rm>) */
524 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
526 instruction
->info
.load_store
.offset_mode
= 1;
527 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
528 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
529 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
534 if (W
== 0) /* offset */
536 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
537 address
, opcode
, operation
, COND(opcode
), suffix
,
540 instruction
->info
.load_store
.index_mode
= 0;
542 else /* pre-indexed */
544 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
545 address
, opcode
, operation
, COND(opcode
), suffix
,
548 instruction
->info
.load_store
.index_mode
= 1;
551 else /* post-indexed */
553 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
554 address
, opcode
, operation
, COND(opcode
), suffix
,
557 instruction
->info
.load_store
.index_mode
= 2;
563 /* Load/store multiples instructions */
564 int evaluate_ldm_stm(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
566 u8 P
, U
, S
, W
, L
, Rn
;
568 char *addressing_mode
;
575 P
= (opcode
& 0x01000000) >> 24;
576 U
= (opcode
& 0x00800000) >> 23;
577 S
= (opcode
& 0x00400000) >> 22;
578 W
= (opcode
& 0x00200000) >> 21;
579 L
= (opcode
& 0x00100000) >> 20;
580 register_list
= (opcode
& 0xffff);
581 Rn
= (opcode
& 0xf0000) >> 16;
583 instruction
->info
.load_store_multiple
.Rn
= Rn
;
584 instruction
->info
.load_store_multiple
.register_list
= register_list
;
585 instruction
->info
.load_store_multiple
.S
= S
;
586 instruction
->info
.load_store_multiple
.W
= W
;
590 instruction
->type
= ARM_LDM
;
595 instruction
->type
= ARM_STM
;
603 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
604 addressing_mode
= "IB";
608 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
609 addressing_mode
= "DB";
616 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
617 addressing_mode
= "IA";
621 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
622 addressing_mode
= "DA";
626 reg_list_p
= reg_list
;
627 for (i
= 0; i
<= 15; i
++)
629 if ((register_list
>> i
) & 1)
634 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
638 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
643 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i%s, {%s}%s",
644 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
645 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
650 /* Multiplies, extra load/stores */
651 int evaluate_mul_and_extra_ld_st(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
653 /* Multiply (accumulate) (long) and Swap/swap byte */
654 if ((opcode
& 0x000000f0) == 0x00000090)
656 /* Multiply (accumulate) */
657 if ((opcode
& 0x0f800000) == 0x00000000)
659 u8 Rm
, Rs
, Rn
, Rd
, S
;
661 Rs
= (opcode
& 0xf00) >> 8;
662 Rn
= (opcode
& 0xf000) >> 12;
663 Rd
= (opcode
& 0xf0000) >> 16;
664 S
= (opcode
& 0x00100000) >> 20;
666 /* examine A bit (accumulate) */
667 if (opcode
& 0x00200000)
669 instruction
->type
= ARM_MLA
;
670 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMLA%s%s r%i, r%i, r%i, r%i",
671 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
675 instruction
->type
= ARM_MUL
;
676 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMUL%s%s r%i, r%i, r%i",
677 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
683 /* Multiply (accumulate) long */
684 if ((opcode
& 0x0f800000) == 0x00800000)
686 char* mnemonic
= NULL
;
687 u8 Rm
, Rs
, RdHi
, RdLow
, S
;
689 Rs
= (opcode
& 0xf00) >> 8;
690 RdHi
= (opcode
& 0xf000) >> 12;
691 RdLow
= (opcode
& 0xf0000) >> 16;
692 S
= (opcode
& 0x00100000) >> 20;
694 switch ((opcode
& 0x00600000) >> 21)
697 instruction
->type
= ARM_UMULL
;
701 instruction
->type
= ARM_UMLAL
;
705 instruction
->type
= ARM_SMULL
;
709 instruction
->type
= ARM_SMLAL
;
714 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, r%i, r%i",
715 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
716 RdLow
, RdHi
, Rm
, Rs
);
722 if ((opcode
& 0x0f800000) == 0x01000000)
726 Rd
= (opcode
& 0xf000) >> 12;
727 Rn
= (opcode
& 0xf0000) >> 16;
730 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
732 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, [r%i]",
733 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
739 return evaluate_misc_load_store(opcode
, address
, instruction
);
742 int evaluate_mrs_msr(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
744 int R
= (opcode
& 0x00400000) >> 22;
745 char *PSR
= (R
) ? "SPSR" : "CPSR";
747 /* Move register to status register (MSR) */
748 if (opcode
& 0x00200000)
750 instruction
->type
= ARM_MSR
;
752 /* immediate variant */
753 if (opcode
& 0x02000000)
755 u8 immediate
= (opcode
& 0xff);
756 u8 rotate
= (opcode
& 0xf00);
758 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, 0x%8.8x",
759 address
, opcode
, COND(opcode
), PSR
,
760 (opcode
& 0x10000) ? "c" : "",
761 (opcode
& 0x20000) ? "x" : "",
762 (opcode
& 0x40000) ? "s" : "",
763 (opcode
& 0x80000) ? "f" : "",
764 ror(immediate
, (rotate
* 2))
767 else /* register variant */
769 u8 Rm
= opcode
& 0xf;
770 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, r%i",
771 address
, opcode
, COND(opcode
), PSR
,
772 (opcode
& 0x10000) ? "c" : "",
773 (opcode
& 0x20000) ? "x" : "",
774 (opcode
& 0x40000) ? "s" : "",
775 (opcode
& 0x80000) ? "f" : "",
781 else /* Move status register to register (MRS) */
785 instruction
->type
= ARM_MRS
;
786 Rd
= (opcode
& 0x0000f000) >> 12;
788 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMRS%s r%i, %s",
789 address
, opcode
, COND(opcode
), Rd
, PSR
);
795 /* Miscellaneous instructions */
796 int evaluate_misc_instr(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
799 if ((opcode
& 0x000000f0) == 0x00000000)
801 evaluate_mrs_msr(opcode
, address
, instruction
);
805 if ((opcode
& 0x006000f0) == 0x00200010)
808 instruction
->type
= ARM_BX
;
811 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBX%s r%i",
812 address
, opcode
, COND(opcode
), Rm
);
814 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
815 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
819 if ((opcode
& 0x006000f0) == 0x00600010)
822 instruction
->type
= ARM_CLZ
;
824 Rd
= (opcode
& 0xf000) >> 12;
826 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tCLZ%s r%i, r%i",
827 address
, opcode
, COND(opcode
), Rd
, Rm
);
831 if ((opcode
& 0x006000f0) == 0x00200030)
834 instruction
->type
= ARM_BLX
;
837 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
838 address
, opcode
, COND(opcode
), Rm
);
840 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
841 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
844 /* Enhanced DSP add/subtracts */
845 if ((opcode
& 0x0000000f0) == 0x00000050)
848 char *mnemonic
= NULL
;
850 Rd
= (opcode
& 0xf000) >> 12;
851 Rn
= (opcode
& 0xf0000) >> 16;
853 switch ((opcode
& 0x00600000) >> 21)
856 instruction
->type
= ARM_QADD
;
860 instruction
->type
= ARM_QSUB
;
864 instruction
->type
= ARM_QDADD
;
868 instruction
->type
= ARM_QDSUB
;
873 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, r%i",
874 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
877 /* Software breakpoints */
878 if ((opcode
& 0x0000000f0) == 0x00000070)
881 instruction
->type
= ARM_BKPT
;
882 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
884 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBKPT 0x%4.4x",
885 address
, opcode
, immediate
);
888 /* Enhanced DSP multiplies */
889 if ((opcode
& 0x000000090) == 0x00000080)
891 int x
= (opcode
& 0x20) >> 5;
892 int y
= (opcode
& 0x40) >> 6;
895 if ((opcode
& 0x00600000) == 0x00000000)
898 instruction
->type
= ARM_SMLAxy
;
899 Rd
= (opcode
& 0xf0000) >> 16;
901 Rs
= (opcode
& 0xf00) >> 8;
902 Rn
= (opcode
& 0xf000) >> 12;
904 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
905 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
910 if ((opcode
& 0x00600000) == 0x00400000)
912 u8 RdLow
, RdHi
, Rm
, Rs
;
913 instruction
->type
= ARM_SMLAxy
;
914 RdHi
= (opcode
& 0xf0000) >> 16;
915 RdLow
= (opcode
& 0xf000) >> 12;
917 Rs
= (opcode
& 0xf00) >> 8;
919 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
920 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
921 RdLow
, RdHi
, Rm
, Rs
);
925 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
928 instruction
->type
= ARM_SMLAWy
;
929 Rd
= (opcode
& 0xf0000) >> 16;
931 Rs
= (opcode
& 0xf00) >> 8;
932 Rn
= (opcode
& 0xf000) >> 12;
934 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLAW%s%s r%i, r%i, r%i, r%i",
935 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
940 if ((opcode
& 0x00600000) == 0x00300000)
943 instruction
->type
= ARM_SMULxy
;
944 Rd
= (opcode
& 0xf0000) >> 16;
946 Rs
= (opcode
& 0xf00) >> 8;
948 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s%s r%i, r%i, r%i",
949 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
954 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
957 instruction
->type
= ARM_SMULWy
;
958 Rd
= (opcode
& 0xf0000) >> 16;
960 Rs
= (opcode
& 0xf00) >> 8;
962 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s r%i, r%i, r%i",
963 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
971 int evaluate_data_proc(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
974 char *mnemonic
= NULL
;
975 char shifter_operand
[32];
977 I
= (opcode
& 0x02000000) >> 25;
978 op
= (opcode
& 0x01e00000) >> 21;
979 S
= (opcode
& 0x00100000) >> 20;
981 Rd
= (opcode
& 0xf000) >> 12;
982 Rn
= (opcode
& 0xf0000) >> 16;
984 instruction
->info
.data_proc
.Rd
= Rd
;
985 instruction
->info
.data_proc
.Rn
= Rn
;
986 instruction
->info
.data_proc
.S
= S
;
991 instruction
->type
= ARM_AND
;
995 instruction
->type
= ARM_EOR
;
999 instruction
->type
= ARM_SUB
;
1003 instruction
->type
= ARM_RSB
;
1007 instruction
->type
= ARM_ADD
;
1011 instruction
->type
= ARM_ADC
;
1015 instruction
->type
= ARM_SBC
;
1019 instruction
->type
= ARM_RSC
;
1023 instruction
->type
= ARM_TST
;
1027 instruction
->type
= ARM_TEQ
;
1031 instruction
->type
= ARM_CMP
;
1035 instruction
->type
= ARM_CMN
;
1039 instruction
->type
= ARM_ORR
;
1043 instruction
->type
= ARM_MOV
;
1047 instruction
->type
= ARM_BIC
;
1051 instruction
->type
= ARM_MVN
;
1056 if (I
) /* immediate shifter operand (#<immediate>)*/
1058 u8 immed_8
= opcode
& 0xff;
1059 u8 rotate_imm
= (opcode
& 0xf00) >> 8;
1062 immediate
= ror(immed_8
, rotate_imm
* 2);
1064 snprintf(shifter_operand
, 32, "#0x%x", immediate
);
1066 instruction
->info
.data_proc
.variant
= 0;
1067 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1069 else /* register-based shifter operand */
1072 shift
= (opcode
& 0x60) >> 5;
1073 Rm
= (opcode
& 0xf);
1075 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1078 shift_imm
= (opcode
& 0xf80) >> 7;
1080 instruction
->info
.data_proc
.variant
= 1;
1081 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1082 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1083 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1085 /* LSR encodes a shift by 32 bit as 0x0 */
1086 if ((shift
== 0x1) && (shift_imm
== 0x0))
1089 /* ASR encodes a shift by 32 bit as 0x0 */
1090 if ((shift
== 0x2) && (shift_imm
== 0x0))
1093 /* ROR by 32 bit is actually a RRX */
1094 if ((shift
== 0x3) && (shift_imm
== 0x0))
1097 if ((shift_imm
== 0x0) && (shift
== 0x0))
1099 snprintf(shifter_operand
, 32, "r%i", Rm
);
1103 if (shift
== 0x0) /* LSL */
1105 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1107 else if (shift
== 0x1) /* LSR */
1109 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1111 else if (shift
== 0x2) /* ASR */
1113 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1115 else if (shift
== 0x3) /* ROR */
1117 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1119 else if (shift
== 0x4) /* RRX */
1121 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1125 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1127 u8 Rs
= (opcode
& 0xf00) >> 8;
1129 instruction
->info
.data_proc
.variant
= 2;
1130 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1131 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1132 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1134 if (shift
== 0x0) /* LSL */
1136 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1138 else if (shift
== 0x1) /* LSR */
1140 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1142 else if (shift
== 0x2) /* ASR */
1144 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1146 else if (shift
== 0x3) /* ROR */
1148 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1153 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1155 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, %s",
1156 address
, opcode
, mnemonic
, COND(opcode
),
1157 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1159 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1161 if (opcode
==0xe1a00000) /* print MOV r0,r0 as NOP */
1162 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tNOP",address
, opcode
);
1164 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
1165 address
, opcode
, mnemonic
, COND(opcode
),
1166 (S
) ? "S" : "", Rd
, shifter_operand
);
1168 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1170 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, %s",
1171 address
, opcode
, mnemonic
, COND(opcode
),
1172 Rn
, shifter_operand
);
1178 int arm_evaluate_opcode(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
1180 /* clear fields, to avoid confusion */
1181 memset(instruction
, 0, sizeof(arm_instruction_t
));
1182 instruction
->opcode
= opcode
;
1184 /* catch opcodes with condition field [31:28] = b1111 */
1185 if ((opcode
& 0xf0000000) == 0xf0000000)
1187 /* Undefined instruction (or ARMv5E cache preload PLD) */
1188 if ((opcode
& 0x08000000) == 0x00000000)
1189 return evaluate_pld(opcode
, address
, instruction
);
1191 /* Undefined instruction */
1192 if ((opcode
& 0x0e000000) == 0x08000000)
1194 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1195 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1199 /* Branch and branch with link and change to Thumb */
1200 if ((opcode
& 0x0e000000) == 0x0a000000)
1201 return evaluate_blx_imm(opcode
, address
, instruction
);
1203 /* Extended coprocessor opcode space (ARMv5 and higher )*/
1204 /* Coprocessor load/store and double register transfers */
1205 if ((opcode
& 0x0e000000) == 0x0c000000)
1206 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1208 /* Coprocessor data processing */
1209 if ((opcode
& 0x0f000100) == 0x0c000000)
1210 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1212 /* Coprocessor register transfers */
1213 if ((opcode
& 0x0f000010) == 0x0c000010)
1214 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1216 /* Undefined instruction */
1217 if ((opcode
& 0x0f000000) == 0x0f000000)
1219 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1220 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1225 /* catch opcodes with [27:25] = b000 */
1226 if ((opcode
& 0x0e000000) == 0x00000000)
1228 /* Multiplies, extra load/stores */
1229 if ((opcode
& 0x00000090) == 0x00000090)
1230 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1232 /* Miscellaneous instructions */
1233 if ((opcode
& 0x0f900000) == 0x01000000)
1234 return evaluate_misc_instr(opcode
, address
, instruction
);
1236 return evaluate_data_proc(opcode
, address
, instruction
);
1239 /* catch opcodes with [27:25] = b001 */
1240 if ((opcode
& 0x0e000000) == 0x02000000)
1242 /* Undefined instruction */
1243 if ((opcode
& 0x0fb00000) == 0x03000000)
1245 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1246 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1250 /* Move immediate to status register */
1251 if ((opcode
& 0x0fb00000) == 0x03200000)
1252 return evaluate_mrs_msr(opcode
, address
, instruction
);
1254 return evaluate_data_proc(opcode
, address
, instruction
);
1258 /* catch opcodes with [27:25] = b010 */
1259 if ((opcode
& 0x0e000000) == 0x04000000)
1261 /* Load/store immediate offset */
1262 return evaluate_load_store(opcode
, address
, instruction
);
1265 /* catch opcodes with [27:25] = b011 */
1266 if ((opcode
& 0x0e000000) == 0x06000000)
1268 /* Undefined instruction */
1269 if ((opcode
& 0x00000010) == 0x00000010)
1271 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1272 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1276 /* Load/store register offset */
1277 return evaluate_load_store(opcode
, address
, instruction
);
1281 /* catch opcodes with [27:25] = b100 */
1282 if ((opcode
& 0x0e000000) == 0x08000000)
1284 /* Load/store multiple */
1285 return evaluate_ldm_stm(opcode
, address
, instruction
);
1288 /* catch opcodes with [27:25] = b101 */
1289 if ((opcode
& 0x0e000000) == 0x0a000000)
1291 /* Branch and branch with link */
1292 return evaluate_b_bl(opcode
, address
, instruction
);
1295 /* catch opcodes with [27:25] = b110 */
1296 if ((opcode
& 0x0e000000) == 0x0a000000)
1298 /* Coprocessor load/store and double register transfers */
1299 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1302 /* catch opcodes with [27:25] = b111 */
1303 if ((opcode
& 0x0e000000) == 0x0e000000)
1305 /* Software interrupt */
1306 if ((opcode
& 0x0f000000) == 0x0f000000)
1307 return evaluate_swi(opcode
, address
, instruction
);
1309 /* Coprocessor data processing */
1310 if ((opcode
& 0x0f000010) == 0x0e000000)
1311 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1313 /* Coprocessor register transfers */
1314 if ((opcode
& 0x0f000010) == 0x0e000010)
1315 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1318 LOG_ERROR("should never reach this point");
1322 int evaluate_b_bl_blx_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1324 u32 offset
= opcode
& 0x7ff;
1325 u32 opc
= (opcode
>> 11) & 0x3;
1327 char *mnemonic
= NULL
;
1329 /* sign extend 11-bit offset */
1330 if (((opc
==0) || (opc
==2)) && (offset
& 0x00000400))
1331 offset
= 0xfffff800 | offset
;
1333 target_address
= address
+ 4 + (offset
<<1);
1337 /* unconditional branch */
1339 instruction
->type
= ARM_B
;
1344 instruction
->type
= ARM_BLX
;
1349 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1350 mnemonic
= "prefix";
1351 target_address
= offset
<<12;
1355 instruction
->type
= ARM_BL
;
1359 /* TODO: deals correctly with dual opcodes BL/BLX ... */
1361 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s 0x%8.8x", address
, opcode
,mnemonic
, target_address
);
1363 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1364 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1369 int evaluate_add_sub_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1371 u8 Rd
= (opcode
>> 0) & 0x7;
1372 u8 Rn
= (opcode
>> 3) & 0x7;
1373 u8 Rm_imm
= (opcode
>> 6) & 0x7;
1374 u32 opc
= opcode
& (1<<9);
1375 u32 reg_imm
= opcode
& (1<<10);
1380 instruction
->type
= ARM_SUB
;
1385 instruction
->type
= ARM_ADD
;
1389 instruction
->info
.data_proc
.Rd
= Rd
;
1390 instruction
->info
.data_proc
.Rn
= Rn
;
1391 instruction
->info
.data_proc
.S
= 1;
1395 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1396 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1397 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #%d",
1398 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1402 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1403 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1404 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, r%i",
1405 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1411 int evaluate_shift_imm_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1413 u8 Rd
= (opcode
>> 0) & 0x7;
1414 u8 Rm
= (opcode
>> 3) & 0x7;
1415 u8 imm
= (opcode
>> 6) & 0x1f;
1416 u8 opc
= (opcode
>> 11) & 0x3;
1417 char *mnemonic
= NULL
;
1422 instruction
->type
= ARM_MOV
;
1424 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1427 instruction
->type
= ARM_MOV
;
1429 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1432 instruction
->type
= ARM_MOV
;
1434 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1438 if ((imm
==0) && (opc
!=0))
1441 instruction
->info
.data_proc
.Rd
= Rd
;
1442 instruction
->info
.data_proc
.Rn
= -1;
1443 instruction
->info
.data_proc
.S
= 1;
1445 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1446 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1447 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1449 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #0x%02x",
1450 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1455 int evaluate_data_proc_imm_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1457 u8 imm
= opcode
& 0xff;
1458 u8 Rd
= (opcode
>> 8) & 0x7;
1459 u32 opc
= (opcode
>> 11) & 0x3;
1460 char *mnemonic
= NULL
;
1462 instruction
->info
.data_proc
.Rd
= Rd
;
1463 instruction
->info
.data_proc
.Rn
= Rd
;
1464 instruction
->info
.data_proc
.S
= 1;
1465 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1466 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1471 instruction
->type
= ARM_MOV
;
1473 instruction
->info
.data_proc
.Rn
= -1;
1476 instruction
->type
= ARM_CMP
;
1478 instruction
->info
.data_proc
.Rd
= -1;
1481 instruction
->type
= ARM_ADD
;
1485 instruction
->type
= ARM_SUB
;
1490 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, #0x%02x",
1491 address
, opcode
, mnemonic
, Rd
, imm
);
1496 int evaluate_data_proc_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1498 u8 high_reg
, op
, Rm
, Rd
,H1
,H2
;
1499 char *mnemonic
= NULL
;
1501 high_reg
= (opcode
& 0x0400) >> 10;
1502 op
= (opcode
& 0x03C0) >> 6;
1504 Rd
= (opcode
& 0x0007);
1505 Rm
= (opcode
& 0x0038) >> 3;
1506 H1
= (opcode
& 0x0080) >> 7;
1507 H2
= (opcode
& 0x0040) >> 6;
1509 instruction
->info
.data_proc
.Rd
= Rd
;
1510 instruction
->info
.data_proc
.Rn
= Rd
;
1511 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1512 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1513 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1524 instruction
->type
= ARM_ADD
;
1528 instruction
->type
= ARM_CMP
;
1532 instruction
->type
= ARM_MOV
;
1536 if ((opcode
& 0x7) == 0x0)
1538 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1541 instruction
->type
= ARM_BLX
;
1542 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBLX r%i", address
, opcode
, Rm
);
1546 instruction
->type
= ARM_BX
;
1547 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBX r%i", address
, opcode
, Rm
);
1552 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1553 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
1564 instruction
->type
= ARM_AND
;
1568 instruction
->type
= ARM_EOR
;
1572 instruction
->type
= ARM_MOV
;
1574 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1575 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1576 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1577 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1580 instruction
->type
= ARM_MOV
;
1582 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1583 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1584 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1585 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1588 instruction
->type
= ARM_MOV
;
1590 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1591 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1592 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1593 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1596 instruction
->type
= ARM_ADC
;
1600 instruction
->type
= ARM_SBC
;
1604 instruction
->type
= ARM_MOV
;
1606 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1607 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1608 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1609 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1612 instruction
->type
= ARM_TST
;
1616 instruction
->type
= ARM_RSB
;
1618 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1619 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1620 instruction
->info
.data_proc
.Rn
= Rm
;
1623 instruction
->type
= ARM_CMP
;
1627 instruction
->type
= ARM_CMN
;
1631 instruction
->type
= ARM_ORR
;
1635 instruction
->type
= ARM_MUL
;
1639 instruction
->type
= ARM_BIC
;
1643 instruction
->type
= ARM_MVN
;
1649 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i",
1650 address
, opcode
, mnemonic
, Rd
, Rm
);
1655 int evaluate_load_literal_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1658 u8 Rd
= (opcode
>> 8) & 0x7;
1660 instruction
->type
= ARM_LDR
;
1661 immediate
= opcode
& 0x000000ff;
1663 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tLDR r%i, [PC, #0x%x]", address
, opcode
, Rd
, immediate
*4);
1665 instruction
->info
.load_store
.Rd
= Rd
;
1666 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
1667 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1668 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1669 instruction
->info
.load_store
.offset
.offset
= immediate
*4;
1674 int evaluate_load_store_reg_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1676 u8 Rd
= (opcode
>> 0) & 0x7;
1677 u8 Rn
= (opcode
>> 3) & 0x7;
1678 u8 Rm
= (opcode
>> 6) & 0x7;
1679 u8 opc
= (opcode
>> 9) & 0x7;
1680 char *mnemonic
= NULL
;
1685 instruction
->type
= ARM_STR
;
1689 instruction
->type
= ARM_STRH
;
1693 instruction
->type
= ARM_STRB
;
1697 instruction
->type
= ARM_LDRSB
;
1701 instruction
->type
= ARM_LDR
;
1705 instruction
->type
= ARM_LDRH
;
1709 instruction
->type
= ARM_LDRB
;
1713 instruction
->type
= ARM_LDRSH
;
1718 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [r%i, r%i]", address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
1720 instruction
->info
.load_store
.Rd
= Rd
;
1721 instruction
->info
.load_store
.Rn
= Rn
;
1722 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1723 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
1724 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1729 int evaluate_load_store_imm_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1731 u32 offset
= (opcode
>> 6) & 0x1f;
1732 u8 Rd
= (opcode
>> 0) & 0x7;
1733 u8 Rn
= (opcode
>> 3) & 0x7;
1734 u32 L
= opcode
& (1<<11);
1735 u32 B
= opcode
& (1<<12);
1742 instruction
->type
= ARM_LDR
;
1747 instruction
->type
= ARM_STR
;
1751 if ((opcode
&0xF000)==0x8000)
1762 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s%c r%i, [r%i, #0x%x]", address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<<shift
);
1764 instruction
->info
.load_store
.Rd
= Rd
;
1765 instruction
->info
.load_store
.Rn
= Rn
;
1766 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1767 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1768 instruction
->info
.load_store
.offset
.offset
= offset
<<shift
;
1773 int evaluate_load_store_stack_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1775 u32 offset
= opcode
& 0xff;
1776 u8 Rd
= (opcode
>> 8) & 0x7;
1777 u32 L
= opcode
& (1<<11);
1782 instruction
->type
= ARM_LDR
;
1787 instruction
->type
= ARM_STR
;
1791 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [SP, #0x%x]", address
, opcode
, mnemonic
, Rd
, offset
*4);
1793 instruction
->info
.load_store
.Rd
= Rd
;
1794 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
1795 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1796 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1797 instruction
->info
.load_store
.offset
.offset
= offset
*4;
1802 int evaluate_add_sp_pc_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1804 u32 imm
= opcode
& 0xff;
1805 u8 Rd
= (opcode
>> 8) & 0x7;
1807 u32 SP
= opcode
& (1<<11);
1810 instruction
->type
= ARM_ADD
;
1823 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tADD r%i, %s, #0x%x", address
, opcode
, Rd
,reg_name
, imm
*4);
1825 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1826 instruction
->info
.data_proc
.Rd
= Rd
;
1827 instruction
->info
.data_proc
.Rn
= Rn
;
1828 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1833 int evaluate_adjust_stack_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1835 u32 imm
= opcode
& 0x7f;
1836 u8 opc
= opcode
& (1<<7);
1842 instruction
->type
= ARM_SUB
;
1847 instruction
->type
= ARM_ADD
;
1851 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s SP, #0x%x", address
, opcode
, mnemonic
, imm
*4);
1853 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1854 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
1855 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
1856 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1861 int evaluate_breakpoint_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1863 u32 imm
= opcode
& 0xff;
1865 instruction
->type
= ARM_BKPT
;
1867 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBKPT 0x%02x", address
, opcode
, imm
);
1872 int evaluate_load_store_multiple_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1874 u32 reg_list
= opcode
& 0xff;
1875 u32 L
= opcode
& (1<<11);
1876 u32 R
= opcode
& (1<<8);
1877 u8 Rn
= (opcode
>> 8) & 7;
1878 u8 addr_mode
= 0 /* IA */;
1882 char ptr_name
[7] = "";
1885 if ((opcode
& 0xf000) == 0xc000)
1886 { /* generic load/store multiple */
1889 instruction
->type
= ARM_LDM
;
1894 instruction
->type
= ARM_STM
;
1897 snprintf(ptr_name
,7,"r%i!, ",Rn
);
1904 instruction
->type
= ARM_LDM
;
1907 reg_list
|= (1<<15) /*PC*/;
1911 instruction
->type
= ARM_STM
;
1913 addr_mode
= 3; /*DB*/
1915 reg_list
|= (1<<14) /*LR*/;
1919 reg_names_p
= reg_names
;
1920 for (i
= 0; i
<= 15; i
++)
1922 if (reg_list
& (1<<i
))
1923 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
1925 if (reg_names_p
>reg_names
)
1926 reg_names_p
[-2] = '\0';
1927 else /* invalid op : no registers */
1928 reg_names
[0] = '\0';
1930 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s %s{%s}", address
, opcode
, mnemonic
, ptr_name
,reg_names
);
1932 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
1933 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1934 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
1939 int evaluate_cond_branch_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1941 u32 offset
= opcode
& 0xff;
1942 u8 cond
= (opcode
>> 8) & 0xf;
1947 instruction
->type
= ARM_SWI
;
1948 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tSWI 0x%02x", address
, opcode
, offset
);
1951 else if (cond
== 0xe)
1953 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1954 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
1958 /* sign extend 8-bit offset */
1959 if (offset
& 0x00000080)
1960 offset
= 0xffffff00 | offset
;
1962 target_address
= address
+ 4 + (offset
<<1);
1964 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tB%s 0x%8.8x", address
, opcode
,
1965 arm_condition_strings
[cond
], target_address
);
1967 instruction
->type
= ARM_B
;
1968 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1969 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1974 int thumb_evaluate_opcode(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1976 /* clear fields, to avoid confusion */
1977 memset(instruction
, 0, sizeof(arm_instruction_t
));
1978 instruction
->opcode
= opcode
;
1980 if ((opcode
& 0xe000) == 0x0000)
1982 /* add/substract register or immediate */
1983 if ((opcode
& 0x1800) == 0x1800)
1984 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
1985 /* shift by immediate */
1987 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
1990 /* Add/substract/compare/move immediate */
1991 if ((opcode
& 0xe000) == 0x2000)
1993 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
1996 /* Data processing instructions */
1997 if ((opcode
& 0xf800) == 0x4000)
1999 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2002 /* Load from literal pool */
2003 if ((opcode
& 0xf800) == 0x4800)
2005 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2008 /* Load/Store register offset */
2009 if ((opcode
& 0xf000) == 0x5000)
2011 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2014 /* Load/Store immediate offset */
2015 if (((opcode
& 0xe000) == 0x6000)
2016 ||((opcode
& 0xf000) == 0x8000))
2018 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2021 /* Load/Store from/to stack */
2022 if ((opcode
& 0xf000) == 0x9000)
2024 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2028 if ((opcode
& 0xf000) == 0xa000)
2030 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2034 if ((opcode
& 0xf000) == 0xb000)
2036 if ((opcode
& 0x0f00) == 0x0000)
2037 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2038 else if ((opcode
& 0x0f00) == 0x0e00)
2039 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2040 else if ((opcode
& 0x0600) == 0x0400) /* push pop */
2041 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2044 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2045 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
2050 /* Load/Store multiple */
2051 if ((opcode
& 0xf000) == 0xc000)
2053 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2056 /* Conditional branch + SWI */
2057 if ((opcode
& 0xf000) == 0xd000)
2059 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2062 if ((opcode
& 0xe000) == 0xe000)
2064 /* Undefined instructions */
2065 if ((opcode
& 0xf801) == 0xe801)
2067 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2068 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
2072 { /* Branch to offset */
2073 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2077 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2081 int arm_access_size(arm_instruction_t
*instruction
)
2083 if ((instruction
->type
== ARM_LDRB
)
2084 || (instruction
->type
== ARM_LDRBT
)
2085 || (instruction
->type
== ARM_LDRSB
)
2086 || (instruction
->type
== ARM_STRB
)
2087 || (instruction
->type
== ARM_STRBT
))
2091 else if ((instruction
->type
== ARM_LDRH
)
2092 || (instruction
->type
== ARM_LDRSH
)
2093 || (instruction
->type
== ARM_STRH
))
2097 else if ((instruction
->type
== ARM_LDR
)
2098 || (instruction
->type
== ARM_LDRT
)
2099 || (instruction
->type
== ARM_STR
)
2100 || (instruction
->type
== ARM_STRT
))
2104 else if ((instruction
->type
== ARM_LDRD
)
2105 || (instruction
->type
== ARM_STRD
))
2111 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)