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"
30 /* textual represenation of the condition field */
31 /* ALways (default) is ommitted (empty string) */
32 char *arm_condition_strings
[] =
34 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
37 /* make up for C's missing ROR */
38 u32
ror(u32 value
, int places
)
40 return (value
>> places
) | (value
<< (32 - places
));
43 int evaluate_pld(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
46 if ((opcode
& 0x0d70f0000) == 0x0550f000)
48 instruction
->type
= ARM_PLD
;
50 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tPLD ...TODO...", address
, opcode
);
56 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
60 LOG_ERROR("should never reach this point");
64 int evaluate_swi(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
66 instruction
->type
= ARM_SWI
;
68 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSWI 0x%6.6x", address
, opcode
, (opcode
& 0xffffff));
73 int evaluate_blx_imm(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
79 instruction
->type
= ARM_BLX
;
80 immediate
= opcode
& 0x00ffffff;
82 /* sign extend 24-bit immediate */
83 if (immediate
& 0x00800000)
84 offset
= 0xff000000 | immediate
;
88 /* shift two bits left */
91 /* odd/event halfword */
92 if (opcode
& 0x01000000)
95 target_address
= address
+ 8 + offset
;
97 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBLX 0x%8.8x", address
, opcode
, target_address
);
99 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
100 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
105 int evaluate_b_bl(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
112 immediate
= opcode
& 0x00ffffff;
113 L
= (opcode
& 0x01000000) >> 24;
115 /* sign extend 24-bit immediate */
116 if (immediate
& 0x00800000)
117 offset
= 0xff000000 | immediate
;
121 /* shift two bits left */
124 target_address
= address
+ 8 + offset
;
127 instruction
->type
= ARM_BL
;
129 instruction
->type
= ARM_B
;
131 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tB%s%s 0x%8.8x", address
, opcode
,
132 (L
) ? "L" : "", COND(opcode
), target_address
);
134 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
135 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
140 /* Coprocessor load/store and double register transfers */
141 /* both normal and extended instruction space (condition field b1111) */
142 int evaluate_ldc_stc_mcrr_mrrc(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
144 u8 cp_num
= (opcode
& 0xf00) >> 8;
147 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
149 u8 cp_opcode
, Rd
, Rn
, CRm
;
152 cp_opcode
= (opcode
& 0xf0) >> 4;
153 Rd
= (opcode
& 0xf000) >> 12;
154 Rn
= (opcode
& 0xf0000) >> 16;
155 CRm
= (opcode
& 0xf);
158 if ((opcode
& 0x0ff00000) == 0x0c400000)
160 instruction
->type
= ARM_MCRR
;
165 if ((opcode
& 0x0ff00000) == 0x0c500000)
167 instruction
->type
= ARM_MRRC
;
171 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, %x, r%i, r%i, c%i",
172 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
174 else /* LDC or STC */
179 char addressing_mode
[32];
181 CRd
= (opcode
& 0xf000) >> 12;
182 Rn
= (opcode
& 0xf0000) >> 16;
183 offset
= (opcode
& 0xff);
186 if (opcode
& 0x00100000)
188 instruction
->type
= ARM_LDC
;
193 instruction
->type
= ARM_STC
;
197 U
= (opcode
& 0x00800000) >> 23;
198 N
= (opcode
& 0x00400000) >> 22;
200 /* addressing modes */
201 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
202 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
203 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
204 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
205 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
206 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
207 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
208 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
210 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s p%i, c%i, %s",
211 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
213 cp_num
, CRd
, addressing_mode
);
219 /* Coprocessor data processing instructions */
220 /* Coprocessor register transfer instructions */
221 /* both normal and extended instruction space (condition field b1111) */
222 int evaluate_cdp_mcr_mrc(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
226 u8 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
228 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
229 cp_num
= (opcode
& 0xf00) >> 8;
230 CRd_Rd
= (opcode
& 0xf000) >> 12;
231 CRn
= (opcode
& 0xf0000) >> 16;
232 CRm
= (opcode
& 0xf);
233 opcode_2
= (opcode
& 0xe0) >> 5;
236 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
238 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
240 instruction
->type
= ARM_MRC
;
243 else /* bit 20 not set -> MCR */
245 instruction
->type
= ARM_MCR
;
249 opcode_1
= (opcode
& 0x00e00000) >> 21;
251 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",
252 address
, opcode
, mnemonic
, cond
,
253 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
255 else /* bit 4 not set -> CDP */
257 instruction
->type
= ARM_CDP
;
260 opcode_1
= (opcode
& 0x00f00000) >> 20;
262 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",
263 address
, opcode
, mnemonic
, cond
,
264 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
270 /* Load/store instructions */
271 int evaluate_load_store(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
275 char *operation
; /* "LDR" or "STR" */
276 char *suffix
; /* "", "B", "T", "BT" */
280 I
= (opcode
& 0x02000000) >> 25;
281 P
= (opcode
& 0x01000000) >> 24;
282 U
= (opcode
& 0x00800000) >> 23;
283 B
= (opcode
& 0x00400000) >> 22;
284 W
= (opcode
& 0x00200000) >> 21;
285 L
= (opcode
& 0x00100000) >> 20;
287 /* target register */
288 Rd
= (opcode
& 0xf000) >> 12;
291 Rn
= (opcode
& 0xf0000) >> 16;
293 instruction
->info
.load_store
.Rd
= Rd
;
294 instruction
->info
.load_store
.Rn
= Rn
;
295 instruction
->info
.load_store
.U
= U
;
297 /* determine operation */
303 /* determine instruction type and suffix */
306 if ((P
== 0) && (W
== 1))
309 instruction
->type
= ARM_LDRBT
;
311 instruction
->type
= ARM_STRBT
;
317 instruction
->type
= ARM_LDRB
;
319 instruction
->type
= ARM_STRB
;
325 if ((P
== 0) && (W
== 1))
328 instruction
->type
= ARM_LDRT
;
330 instruction
->type
= ARM_STRT
;
336 instruction
->type
= ARM_LDR
;
338 instruction
->type
= ARM_STR
;
343 if (!I
) /* #+-<offset_12> */
345 u32 offset_12
= (opcode
& 0xfff);
347 snprintf(offset
, 32, ", #%s0x%x", (U
) ? "" : "-", offset_12
);
349 snprintf(offset
, 32, "%s", "");
351 instruction
->info
.load_store
.offset_mode
= 0;
352 instruction
->info
.load_store
.offset
.offset
= offset_12
;
354 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
359 shift_imm
= (opcode
& 0xf80) >> 7;
360 shift
= (opcode
& 0x60) >> 5;
363 /* LSR encodes a shift by 32 bit as 0x0 */
364 if ((shift
== 0x1) && (shift_imm
== 0x0))
367 /* ASR encodes a shift by 32 bit as 0x0 */
368 if ((shift
== 0x2) && (shift_imm
== 0x0))
371 /* ROR by 32 bit is actually a RRX */
372 if ((shift
== 0x3) && (shift_imm
== 0x0))
375 instruction
->info
.load_store
.offset_mode
= 1;
376 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
377 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
378 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
380 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
382 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
384 else /* +-<Rm>, <Shift>, #<shift_imm> */
389 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
392 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
395 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
398 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
401 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
409 if (W
== 0) /* offset */
411 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]",
412 address
, opcode
, operation
, COND(opcode
), suffix
,
415 instruction
->info
.load_store
.index_mode
= 0;
417 else /* pre-indexed */
419 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!",
420 address
, opcode
, operation
, COND(opcode
), suffix
,
423 instruction
->info
.load_store
.index_mode
= 1;
426 else /* post-indexed */
428 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s",
429 address
, opcode
, operation
, COND(opcode
), suffix
,
432 instruction
->info
.load_store
.index_mode
= 2;
438 /* Miscellaneous load/store instructions */
439 int evaluate_misc_load_store(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
441 u8 P
, U
, I
, W
, L
, S
, H
;
443 char *operation
; /* "LDR" or "STR" */
444 char *suffix
; /* "H", "SB", "SH", "D" */
448 P
= (opcode
& 0x01000000) >> 24;
449 U
= (opcode
& 0x00800000) >> 23;
450 I
= (opcode
& 0x00400000) >> 22;
451 W
= (opcode
& 0x00200000) >> 21;
452 L
= (opcode
& 0x00100000) >> 20;
453 S
= (opcode
& 0x00000040) >> 6;
454 H
= (opcode
& 0x00000020) >> 5;
456 /* target register */
457 Rd
= (opcode
& 0xf000) >> 12;
460 Rn
= (opcode
& 0xf0000) >> 16;
462 instruction
->info
.load_store
.Rd
= Rd
;
463 instruction
->info
.load_store
.Rn
= Rn
;
464 instruction
->info
.load_store
.U
= U
;
466 /* determine instruction type and suffix */
474 instruction
->type
= ARM_LDRSH
;
480 instruction
->type
= ARM_LDRSB
;
484 else /* there are no signed stores, so this is used to encode double-register load/stores */
490 instruction
->type
= ARM_STRD
;
495 instruction
->type
= ARM_LDRD
;
505 instruction
->type
= ARM_LDRH
;
510 instruction
->type
= ARM_STRH
;
514 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
516 u32 offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
517 snprintf(offset
, 32, "#%s0x%x", (U
) ? "" : "-", offset_8
);
519 instruction
->info
.load_store
.offset_mode
= 0;
520 instruction
->info
.load_store
.offset
.offset
= offset_8
;
522 else /* Register offset/index (+-<Rm>) */
526 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
528 instruction
->info
.load_store
.offset_mode
= 1;
529 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
530 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
531 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
536 if (W
== 0) /* offset */
538 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
539 address
, opcode
, operation
, COND(opcode
), suffix
,
542 instruction
->info
.load_store
.index_mode
= 0;
544 else /* pre-indexed */
546 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
547 address
, opcode
, operation
, COND(opcode
), suffix
,
550 instruction
->info
.load_store
.index_mode
= 1;
553 else /* post-indexed */
555 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
556 address
, opcode
, operation
, COND(opcode
), suffix
,
559 instruction
->info
.load_store
.index_mode
= 2;
565 /* Load/store multiples instructions */
566 int evaluate_ldm_stm(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
568 u8 P
, U
, S
, W
, L
, Rn
;
570 char *addressing_mode
;
577 P
= (opcode
& 0x01000000) >> 24;
578 U
= (opcode
& 0x00800000) >> 23;
579 S
= (opcode
& 0x00400000) >> 22;
580 W
= (opcode
& 0x00200000) >> 21;
581 L
= (opcode
& 0x00100000) >> 20;
582 register_list
= (opcode
& 0xffff);
583 Rn
= (opcode
& 0xf0000) >> 16;
585 instruction
->info
.load_store_multiple
.Rn
= Rn
;
586 instruction
->info
.load_store_multiple
.register_list
= register_list
;
587 instruction
->info
.load_store_multiple
.S
= S
;
588 instruction
->info
.load_store_multiple
.W
= W
;
592 instruction
->type
= ARM_LDM
;
597 instruction
->type
= ARM_STM
;
605 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
606 addressing_mode
= "IB";
610 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
611 addressing_mode
= "DB";
618 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
619 addressing_mode
= "IA";
623 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
624 addressing_mode
= "DA";
628 reg_list_p
= reg_list
;
629 for (i
= 0; i
<= 15; i
++)
631 if ((register_list
>> i
) & 1)
636 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
640 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
645 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i%s, {%s}%s",
646 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
647 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
652 /* Multiplies, extra load/stores */
653 int evaluate_mul_and_extra_ld_st(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
655 /* Multiply (accumulate) (long) and Swap/swap byte */
656 if ((opcode
& 0x000000f0) == 0x00000090)
658 /* Multiply (accumulate) */
659 if ((opcode
& 0x0f800000) == 0x00000000)
661 u8 Rm
, Rs
, Rn
, Rd
, S
;
663 Rs
= (opcode
& 0xf00) >> 8;
664 Rn
= (opcode
& 0xf000) >> 12;
665 Rd
= (opcode
& 0xf0000) >> 16;
666 S
= (opcode
& 0x00100000) >> 20;
668 /* examine A bit (accumulate) */
669 if (opcode
& 0x00200000)
671 instruction
->type
= ARM_MLA
;
672 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMLA%s%s r%i, r%i, r%i, r%i",
673 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
677 instruction
->type
= ARM_MUL
;
678 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMUL%s%s r%i, r%i, r%i",
679 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
685 /* Multiply (accumulate) long */
686 if ((opcode
& 0x0f800000) == 0x00800000)
688 char* mnemonic
= NULL
;
689 u8 Rm
, Rs
, RdHi
, RdLow
, S
;
691 Rs
= (opcode
& 0xf00) >> 8;
692 RdHi
= (opcode
& 0xf000) >> 12;
693 RdLow
= (opcode
& 0xf0000) >> 16;
694 S
= (opcode
& 0x00100000) >> 20;
696 switch ((opcode
& 0x00600000) >> 21)
699 instruction
->type
= ARM_UMULL
;
703 instruction
->type
= ARM_UMLAL
;
707 instruction
->type
= ARM_SMULL
;
711 instruction
->type
= ARM_SMLAL
;
716 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, r%i, r%i",
717 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
718 RdLow
, RdHi
, Rm
, Rs
);
724 if ((opcode
& 0x0f800000) == 0x01000000)
728 Rd
= (opcode
& 0xf000) >> 12;
729 Rn
= (opcode
& 0xf0000) >> 16;
732 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
734 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, [r%i]",
735 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
741 return evaluate_misc_load_store(opcode
, address
, instruction
);
744 int evaluate_mrs_msr(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
746 int R
= (opcode
& 0x00400000) >> 22;
747 char *PSR
= (R
) ? "SPSR" : "CPSR";
749 /* Move register to status register (MSR) */
750 if (opcode
& 0x00200000)
752 instruction
->type
= ARM_MSR
;
754 /* immediate variant */
755 if (opcode
& 0x02000000)
757 u8 immediate
= (opcode
& 0xff);
758 u8 rotate
= (opcode
& 0xf00);
760 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, 0x%8.8x",
761 address
, opcode
, COND(opcode
), PSR
,
762 (opcode
& 0x10000) ? "c" : "",
763 (opcode
& 0x20000) ? "x" : "",
764 (opcode
& 0x40000) ? "s" : "",
765 (opcode
& 0x80000) ? "f" : "",
766 ror(immediate
, (rotate
* 2))
769 else /* register variant */
771 u8 Rm
= opcode
& 0xf;
772 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, r%i",
773 address
, opcode
, COND(opcode
), PSR
,
774 (opcode
& 0x10000) ? "c" : "",
775 (opcode
& 0x20000) ? "x" : "",
776 (opcode
& 0x40000) ? "s" : "",
777 (opcode
& 0x80000) ? "f" : "",
783 else /* Move status register to register (MRS) */
787 instruction
->type
= ARM_MRS
;
788 Rd
= (opcode
& 0x0000f000) >> 12;
790 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMRS%s r%i, %s",
791 address
, opcode
, COND(opcode
), Rd
, PSR
);
797 /* Miscellaneous instructions */
798 int evaluate_misc_instr(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
801 if ((opcode
& 0x000000f0) == 0x00000000)
803 evaluate_mrs_msr(opcode
, address
, instruction
);
807 if ((opcode
& 0x006000f0) == 0x00200010)
810 instruction
->type
= ARM_BX
;
813 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBX%s r%i",
814 address
, opcode
, COND(opcode
), Rm
);
816 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
817 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
821 if ((opcode
& 0x006000f0) == 0x00600010)
824 instruction
->type
= ARM_CLZ
;
826 Rd
= (opcode
& 0xf000) >> 12;
828 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tCLZ%s r%i, r%i",
829 address
, opcode
, COND(opcode
), Rd
, Rm
);
833 if ((opcode
& 0x006000f0) == 0x00200030)
836 instruction
->type
= ARM_BLX
;
839 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
840 address
, opcode
, COND(opcode
), Rm
);
842 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
843 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
846 /* Enhanced DSP add/subtracts */
847 if ((opcode
& 0x0000000f0) == 0x00000050)
850 char *mnemonic
= NULL
;
852 Rd
= (opcode
& 0xf000) >> 12;
853 Rn
= (opcode
& 0xf0000) >> 16;
855 switch ((opcode
& 0x00600000) >> 21)
858 instruction
->type
= ARM_QADD
;
862 instruction
->type
= ARM_QSUB
;
866 instruction
->type
= ARM_QDADD
;
870 instruction
->type
= ARM_QDSUB
;
875 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, r%i",
876 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
879 /* Software breakpoints */
880 if ((opcode
& 0x0000000f0) == 0x00000070)
883 instruction
->type
= ARM_BKPT
;
884 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
886 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBKPT 0x%4.4x",
887 address
, opcode
, immediate
);
890 /* Enhanced DSP multiplies */
891 if ((opcode
& 0x000000090) == 0x00000080)
893 int x
= (opcode
& 0x20) >> 5;
894 int y
= (opcode
& 0x40) >> 6;
897 if ((opcode
& 0x00600000) == 0x00000000)
900 instruction
->type
= ARM_SMLAxy
;
901 Rd
= (opcode
& 0xf0000) >> 16;
903 Rs
= (opcode
& 0xf00) >> 8;
904 Rn
= (opcode
& 0xf000) >> 12;
906 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
907 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
912 if ((opcode
& 0x00600000) == 0x00400000)
914 u8 RdLow
, RdHi
, Rm
, Rs
;
915 instruction
->type
= ARM_SMLAxy
;
916 RdHi
= (opcode
& 0xf0000) >> 16;
917 RdLow
= (opcode
& 0xf000) >> 12;
919 Rs
= (opcode
& 0xf00) >> 8;
921 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
922 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
923 RdLow
, RdHi
, Rm
, Rs
);
927 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
930 instruction
->type
= ARM_SMLAWy
;
931 Rd
= (opcode
& 0xf0000) >> 16;
933 Rs
= (opcode
& 0xf00) >> 8;
934 Rn
= (opcode
& 0xf000) >> 12;
936 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLAW%s%s r%i, r%i, r%i, r%i",
937 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
942 if ((opcode
& 0x00600000) == 0x00300000)
945 instruction
->type
= ARM_SMULxy
;
946 Rd
= (opcode
& 0xf0000) >> 16;
948 Rs
= (opcode
& 0xf00) >> 8;
950 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s%s r%i, r%i, r%i",
951 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
956 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
959 instruction
->type
= ARM_SMULWy
;
960 Rd
= (opcode
& 0xf0000) >> 16;
962 Rs
= (opcode
& 0xf00) >> 8;
964 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s r%i, r%i, r%i",
965 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
973 int evaluate_data_proc(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
976 char *mnemonic
= NULL
;
977 char shifter_operand
[32];
979 I
= (opcode
& 0x02000000) >> 25;
980 op
= (opcode
& 0x01e00000) >> 21;
981 S
= (opcode
& 0x00100000) >> 20;
983 Rd
= (opcode
& 0xf000) >> 12;
984 Rn
= (opcode
& 0xf0000) >> 16;
986 instruction
->info
.data_proc
.Rd
= Rd
;
987 instruction
->info
.data_proc
.Rn
= Rn
;
988 instruction
->info
.data_proc
.S
= S
;
993 instruction
->type
= ARM_AND
;
997 instruction
->type
= ARM_EOR
;
1001 instruction
->type
= ARM_SUB
;
1005 instruction
->type
= ARM_RSB
;
1009 instruction
->type
= ARM_ADD
;
1013 instruction
->type
= ARM_ADC
;
1017 instruction
->type
= ARM_SBC
;
1021 instruction
->type
= ARM_RSC
;
1025 instruction
->type
= ARM_TST
;
1029 instruction
->type
= ARM_TEQ
;
1033 instruction
->type
= ARM_CMP
;
1037 instruction
->type
= ARM_CMN
;
1041 instruction
->type
= ARM_ORR
;
1045 instruction
->type
= ARM_MOV
;
1049 instruction
->type
= ARM_BIC
;
1053 instruction
->type
= ARM_MVN
;
1058 if (I
) /* immediate shifter operand (#<immediate>)*/
1060 u8 immed_8
= opcode
& 0xff;
1061 u8 rotate_imm
= (opcode
& 0xf00) >> 8;
1064 immediate
= ror(immed_8
, rotate_imm
* 2);
1066 snprintf(shifter_operand
, 32, "#0x%x", immediate
);
1068 instruction
->info
.data_proc
.variant
= 0;
1069 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1071 else /* register-based shifter operand */
1074 shift
= (opcode
& 0x60) >> 5;
1075 Rm
= (opcode
& 0xf);
1077 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1080 shift_imm
= (opcode
& 0xf80) >> 7;
1082 instruction
->info
.data_proc
.variant
= 1;
1083 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1084 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1085 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1087 /* LSR encodes a shift by 32 bit as 0x0 */
1088 if ((shift
== 0x1) && (shift_imm
== 0x0))
1091 /* ASR encodes a shift by 32 bit as 0x0 */
1092 if ((shift
== 0x2) && (shift_imm
== 0x0))
1095 /* ROR by 32 bit is actually a RRX */
1096 if ((shift
== 0x3) && (shift_imm
== 0x0))
1099 if ((shift_imm
== 0x0) && (shift
== 0x0))
1101 snprintf(shifter_operand
, 32, "r%i", Rm
);
1105 if (shift
== 0x0) /* LSL */
1107 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1109 else if (shift
== 0x1) /* LSR */
1111 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1113 else if (shift
== 0x2) /* ASR */
1115 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1117 else if (shift
== 0x3) /* ROR */
1119 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1121 else if (shift
== 0x4) /* RRX */
1123 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1127 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1129 u8 Rs
= (opcode
& 0xf00) >> 8;
1131 instruction
->info
.data_proc
.variant
= 2;
1132 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1133 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1134 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1136 if (shift
== 0x0) /* LSL */
1138 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1140 else if (shift
== 0x1) /* LSR */
1142 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1144 else if (shift
== 0x2) /* ASR */
1146 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1148 else if (shift
== 0x3) /* ROR */
1150 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1155 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1157 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, %s",
1158 address
, opcode
, mnemonic
, COND(opcode
),
1159 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1161 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1163 if (opcode
==0xe1a00000) /* print MOV r0,r0 as NOP */
1164 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tNOP",address
, opcode
);
1166 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
1167 address
, opcode
, mnemonic
, COND(opcode
),
1168 (S
) ? "S" : "", Rd
, shifter_operand
);
1170 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1172 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, %s",
1173 address
, opcode
, mnemonic
, COND(opcode
),
1174 Rn
, shifter_operand
);
1180 int arm_evaluate_opcode(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
1182 /* clear fields, to avoid confusion */
1183 memset(instruction
, 0, sizeof(arm_instruction_t
));
1184 instruction
->opcode
= opcode
;
1186 /* catch opcodes with condition field [31:28] = b1111 */
1187 if ((opcode
& 0xf0000000) == 0xf0000000)
1189 /* Undefined instruction (or ARMv5E cache preload PLD) */
1190 if ((opcode
& 0x08000000) == 0x00000000)
1191 return evaluate_pld(opcode
, address
, instruction
);
1193 /* Undefined instruction */
1194 if ((opcode
& 0x0e000000) == 0x08000000)
1196 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1197 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1201 /* Branch and branch with link and change to Thumb */
1202 if ((opcode
& 0x0e000000) == 0x0a000000)
1203 return evaluate_blx_imm(opcode
, address
, instruction
);
1205 /* Extended coprocessor opcode space (ARMv5 and higher )*/
1206 /* Coprocessor load/store and double register transfers */
1207 if ((opcode
& 0x0e000000) == 0x0c000000)
1208 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1210 /* Coprocessor data processing */
1211 if ((opcode
& 0x0f000100) == 0x0c000000)
1212 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1214 /* Coprocessor register transfers */
1215 if ((opcode
& 0x0f000010) == 0x0c000010)
1216 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1218 /* Undefined instruction */
1219 if ((opcode
& 0x0f000000) == 0x0f000000)
1221 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1222 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1227 /* catch opcodes with [27:25] = b000 */
1228 if ((opcode
& 0x0e000000) == 0x00000000)
1230 /* Multiplies, extra load/stores */
1231 if ((opcode
& 0x00000090) == 0x00000090)
1232 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1234 /* Miscellaneous instructions */
1235 if ((opcode
& 0x0f900000) == 0x01000000)
1236 return evaluate_misc_instr(opcode
, address
, instruction
);
1238 return evaluate_data_proc(opcode
, address
, instruction
);
1241 /* catch opcodes with [27:25] = b001 */
1242 if ((opcode
& 0x0e000000) == 0x02000000)
1244 /* Undefined instruction */
1245 if ((opcode
& 0x0fb00000) == 0x03000000)
1247 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1248 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1252 /* Move immediate to status register */
1253 if ((opcode
& 0x0fb00000) == 0x03200000)
1254 return evaluate_mrs_msr(opcode
, address
, instruction
);
1256 return evaluate_data_proc(opcode
, address
, instruction
);
1260 /* catch opcodes with [27:25] = b010 */
1261 if ((opcode
& 0x0e000000) == 0x04000000)
1263 /* Load/store immediate offset */
1264 return evaluate_load_store(opcode
, address
, instruction
);
1267 /* catch opcodes with [27:25] = b011 */
1268 if ((opcode
& 0x0e000000) == 0x06000000)
1270 /* Undefined instruction */
1271 if ((opcode
& 0x00000010) == 0x00000010)
1273 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1274 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1278 /* Load/store register offset */
1279 return evaluate_load_store(opcode
, address
, instruction
);
1283 /* catch opcodes with [27:25] = b100 */
1284 if ((opcode
& 0x0e000000) == 0x08000000)
1286 /* Load/store multiple */
1287 return evaluate_ldm_stm(opcode
, address
, instruction
);
1290 /* catch opcodes with [27:25] = b101 */
1291 if ((opcode
& 0x0e000000) == 0x0a000000)
1293 /* Branch and branch with link */
1294 return evaluate_b_bl(opcode
, address
, instruction
);
1297 /* catch opcodes with [27:25] = b110 */
1298 if ((opcode
& 0x0e000000) == 0x0a000000)
1300 /* Coprocessor load/store and double register transfers */
1301 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1304 /* catch opcodes with [27:25] = b111 */
1305 if ((opcode
& 0x0e000000) == 0x0e000000)
1307 /* Software interrupt */
1308 if ((opcode
& 0x0f000000) == 0x0f000000)
1309 return evaluate_swi(opcode
, address
, instruction
);
1311 /* Coprocessor data processing */
1312 if ((opcode
& 0x0f000010) == 0x0e000000)
1313 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1315 /* Coprocessor register transfers */
1316 if ((opcode
& 0x0f000010) == 0x0e000010)
1317 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1320 LOG_ERROR("should never reach this point");
1324 int evaluate_b_bl_blx_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1326 u32 offset
= opcode
& 0x7ff;
1327 u32 opc
= (opcode
>> 11) & 0x3;
1329 char *mnemonic
= NULL
;
1331 /* sign extend 11-bit offset */
1332 if (((opc
==0) || (opc
==2)) && (offset
& 0x00000400))
1333 offset
= 0xfffff800 | offset
;
1335 target_address
= address
+ 4 + (offset
<<1);
1339 /* unconditional branch */
1341 instruction
->type
= ARM_B
;
1346 instruction
->type
= ARM_BLX
;
1351 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1352 mnemonic
= "prefix";
1353 target_address
= offset
<<12;
1357 instruction
->type
= ARM_BL
;
1361 /* TODO: deals correctly with dual opcodes BL/BLX ... */
1363 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s 0x%8.8x", address
, opcode
,mnemonic
, target_address
);
1365 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1366 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1371 int evaluate_add_sub_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1373 u8 Rd
= (opcode
>> 0) & 0x7;
1374 u8 Rn
= (opcode
>> 3) & 0x7;
1375 u8 Rm_imm
= (opcode
>> 6) & 0x7;
1376 u32 opc
= opcode
& (1<<9);
1377 u32 reg_imm
= opcode
& (1<<10);
1382 instruction
->type
= ARM_SUB
;
1387 instruction
->type
= ARM_ADD
;
1391 instruction
->info
.data_proc
.Rd
= Rd
;
1392 instruction
->info
.data_proc
.Rn
= Rn
;
1393 instruction
->info
.data_proc
.S
= 1;
1397 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1398 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1399 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #%d",
1400 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1404 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1405 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1406 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, r%i",
1407 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1413 int evaluate_shift_imm_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1415 u8 Rd
= (opcode
>> 0) & 0x7;
1416 u8 Rm
= (opcode
>> 3) & 0x7;
1417 u8 imm
= (opcode
>> 6) & 0x1f;
1418 u8 opc
= (opcode
>> 11) & 0x3;
1419 char *mnemonic
= NULL
;
1424 instruction
->type
= ARM_MOV
;
1426 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1429 instruction
->type
= ARM_MOV
;
1431 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1434 instruction
->type
= ARM_MOV
;
1436 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1440 if ((imm
==0) && (opc
!=0))
1443 instruction
->info
.data_proc
.Rd
= Rd
;
1444 instruction
->info
.data_proc
.Rn
= -1;
1445 instruction
->info
.data_proc
.S
= 1;
1447 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1448 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1449 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1451 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #0x%02x",
1452 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1457 int evaluate_data_proc_imm_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1459 u8 imm
= opcode
& 0xff;
1460 u8 Rd
= (opcode
>> 8) & 0x7;
1461 u32 opc
= (opcode
>> 11) & 0x3;
1462 char *mnemonic
= NULL
;
1464 instruction
->info
.data_proc
.Rd
= Rd
;
1465 instruction
->info
.data_proc
.Rn
= Rd
;
1466 instruction
->info
.data_proc
.S
= 1;
1467 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1468 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1473 instruction
->type
= ARM_MOV
;
1475 instruction
->info
.data_proc
.Rn
= -1;
1478 instruction
->type
= ARM_CMP
;
1480 instruction
->info
.data_proc
.Rd
= -1;
1483 instruction
->type
= ARM_ADD
;
1487 instruction
->type
= ARM_SUB
;
1492 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, #0x%02x",
1493 address
, opcode
, mnemonic
, Rd
, imm
);
1498 int evaluate_data_proc_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1500 u8 high_reg
, op
, Rm
, Rd
,H1
,H2
;
1501 char *mnemonic
= NULL
;
1503 high_reg
= (opcode
& 0x0400) >> 10;
1504 op
= (opcode
& 0x03C0) >> 6;
1506 Rd
= (opcode
& 0x0007);
1507 Rm
= (opcode
& 0x0038) >> 3;
1508 H1
= (opcode
& 0x0080) >> 7;
1509 H2
= (opcode
& 0x0040) >> 6;
1511 instruction
->info
.data_proc
.Rd
= Rd
;
1512 instruction
->info
.data_proc
.Rn
= Rd
;
1513 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1514 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1515 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1526 instruction
->type
= ARM_ADD
;
1530 instruction
->type
= ARM_CMP
;
1534 instruction
->type
= ARM_MOV
;
1538 if ((opcode
& 0x7) == 0x0)
1540 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1543 instruction
->type
= ARM_BLX
;
1544 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBLX r%i", address
, opcode
, Rm
);
1548 instruction
->type
= ARM_BX
;
1549 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBX r%i", address
, opcode
, Rm
);
1554 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1555 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
1566 instruction
->type
= ARM_AND
;
1570 instruction
->type
= ARM_EOR
;
1574 instruction
->type
= ARM_MOV
;
1576 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1577 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1578 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1579 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1582 instruction
->type
= ARM_MOV
;
1584 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1585 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1586 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1587 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1590 instruction
->type
= ARM_MOV
;
1592 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1593 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1594 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1595 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1598 instruction
->type
= ARM_ADC
;
1602 instruction
->type
= ARM_SBC
;
1606 instruction
->type
= ARM_MOV
;
1608 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1609 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1610 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1611 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1614 instruction
->type
= ARM_TST
;
1618 instruction
->type
= ARM_RSB
;
1620 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1621 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1622 instruction
->info
.data_proc
.Rn
= Rm
;
1625 instruction
->type
= ARM_CMP
;
1629 instruction
->type
= ARM_CMN
;
1633 instruction
->type
= ARM_ORR
;
1637 instruction
->type
= ARM_MUL
;
1641 instruction
->type
= ARM_BIC
;
1645 instruction
->type
= ARM_MVN
;
1651 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i",
1652 address
, opcode
, mnemonic
, Rd
, Rm
);
1657 int evaluate_load_literal_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1660 u8 Rd
= (opcode
>> 8) & 0x7;
1662 instruction
->type
= ARM_LDR
;
1663 immediate
= opcode
& 0x000000ff;
1665 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tLDR r%i, [PC, #0x%x]", address
, opcode
, Rd
, immediate
*4);
1667 instruction
->info
.load_store
.Rd
= Rd
;
1668 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
1669 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1670 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1671 instruction
->info
.load_store
.offset
.offset
= immediate
*4;
1676 int evaluate_load_store_reg_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1678 u8 Rd
= (opcode
>> 0) & 0x7;
1679 u8 Rn
= (opcode
>> 3) & 0x7;
1680 u8 Rm
= (opcode
>> 6) & 0x7;
1681 u8 opc
= (opcode
>> 9) & 0x7;
1682 char *mnemonic
= NULL
;
1687 instruction
->type
= ARM_STR
;
1691 instruction
->type
= ARM_STRH
;
1695 instruction
->type
= ARM_STRB
;
1699 instruction
->type
= ARM_LDRSB
;
1703 instruction
->type
= ARM_LDR
;
1707 instruction
->type
= ARM_LDRH
;
1711 instruction
->type
= ARM_LDRB
;
1715 instruction
->type
= ARM_LDRSH
;
1720 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [r%i, r%i]", address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
1722 instruction
->info
.load_store
.Rd
= Rd
;
1723 instruction
->info
.load_store
.Rn
= Rn
;
1724 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1725 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
1726 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1731 int evaluate_load_store_imm_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1733 u32 offset
= (opcode
>> 6) & 0x1f;
1734 u8 Rd
= (opcode
>> 0) & 0x7;
1735 u8 Rn
= (opcode
>> 3) & 0x7;
1736 u32 L
= opcode
& (1<<11);
1737 u32 B
= opcode
& (1<<12);
1744 instruction
->type
= ARM_LDR
;
1749 instruction
->type
= ARM_STR
;
1753 if ((opcode
&0xF000)==0x8000)
1764 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
);
1766 instruction
->info
.load_store
.Rd
= Rd
;
1767 instruction
->info
.load_store
.Rn
= Rn
;
1768 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1769 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1770 instruction
->info
.load_store
.offset
.offset
= offset
<<shift
;
1775 int evaluate_load_store_stack_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1777 u32 offset
= opcode
& 0xff;
1778 u8 Rd
= (opcode
>> 8) & 0x7;
1779 u32 L
= opcode
& (1<<11);
1784 instruction
->type
= ARM_LDR
;
1789 instruction
->type
= ARM_STR
;
1793 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [SP, #0x%x]", address
, opcode
, mnemonic
, Rd
, offset
*4);
1795 instruction
->info
.load_store
.Rd
= Rd
;
1796 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
1797 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1798 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1799 instruction
->info
.load_store
.offset
.offset
= offset
*4;
1804 int evaluate_add_sp_pc_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1806 u32 imm
= opcode
& 0xff;
1807 u8 Rd
= (opcode
>> 8) & 0x7;
1809 u32 SP
= opcode
& (1<<11);
1812 instruction
->type
= ARM_ADD
;
1825 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tADD r%i, %s, #0x%x", address
, opcode
, Rd
,reg_name
, imm
*4);
1827 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1828 instruction
->info
.data_proc
.Rd
= Rd
;
1829 instruction
->info
.data_proc
.Rn
= Rn
;
1830 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1835 int evaluate_adjust_stack_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1837 u32 imm
= opcode
& 0x7f;
1838 u8 opc
= opcode
& (1<<7);
1844 instruction
->type
= ARM_SUB
;
1849 instruction
->type
= ARM_ADD
;
1853 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s SP, #0x%x", address
, opcode
, mnemonic
, imm
*4);
1855 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1856 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
1857 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
1858 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1863 int evaluate_breakpoint_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1865 u32 imm
= opcode
& 0xff;
1867 instruction
->type
= ARM_BKPT
;
1869 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBKPT 0x%02x", address
, opcode
, imm
);
1874 int evaluate_load_store_multiple_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1876 u32 reg_list
= opcode
& 0xff;
1877 u32 L
= opcode
& (1<<11);
1878 u32 R
= opcode
& (1<<8);
1879 u8 Rn
= (opcode
>> 8) & 7;
1880 u8 addr_mode
= 0 /* IA */;
1884 char ptr_name
[7] = "";
1887 if ((opcode
& 0xf000) == 0xc000)
1888 { /* generic load/store multiple */
1891 instruction
->type
= ARM_LDM
;
1896 instruction
->type
= ARM_STM
;
1899 snprintf(ptr_name
,7,"r%i!, ",Rn
);
1906 instruction
->type
= ARM_LDM
;
1909 reg_list
|= (1<<15) /*PC*/;
1913 instruction
->type
= ARM_STM
;
1915 addr_mode
= 3; /*DB*/
1917 reg_list
|= (1<<14) /*LR*/;
1921 reg_names_p
= reg_names
;
1922 for (i
= 0; i
<= 15; i
++)
1924 if (reg_list
& (1<<i
))
1925 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
1927 if (reg_names_p
>reg_names
)
1928 reg_names_p
[-2] = '\0';
1929 else /* invalid op : no registers */
1930 reg_names
[0] = '\0';
1932 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s %s{%s}", address
, opcode
, mnemonic
, ptr_name
,reg_names
);
1934 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
1935 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1936 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
1941 int evaluate_cond_branch_thumb(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1943 u32 offset
= opcode
& 0xff;
1944 u8 cond
= (opcode
>> 8) & 0xf;
1949 instruction
->type
= ARM_SWI
;
1950 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tSWI 0x%02x", address
, opcode
, offset
);
1953 else if (cond
== 0xe)
1955 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1956 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
1960 /* sign extend 8-bit offset */
1961 if (offset
& 0x00000080)
1962 offset
= 0xffffff00 | offset
;
1964 target_address
= address
+ 4 + (offset
<<1);
1966 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tB%s 0x%8.8x", address
, opcode
,
1967 arm_condition_strings
[cond
], target_address
);
1969 instruction
->type
= ARM_B
;
1970 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1971 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1976 int thumb_evaluate_opcode(u16 opcode
, u32 address
, arm_instruction_t
*instruction
)
1978 /* clear fields, to avoid confusion */
1979 memset(instruction
, 0, sizeof(arm_instruction_t
));
1980 instruction
->opcode
= opcode
;
1982 if ((opcode
& 0xe000) == 0x0000)
1984 /* add/substract register or immediate */
1985 if ((opcode
& 0x1800) == 0x1800)
1986 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
1987 /* shift by immediate */
1989 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
1992 /* Add/substract/compare/move immediate */
1993 if ((opcode
& 0xe000) == 0x2000)
1995 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
1998 /* Data processing instructions */
1999 if ((opcode
& 0xf800) == 0x4000)
2001 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2004 /* Load from literal pool */
2005 if ((opcode
& 0xf800) == 0x4800)
2007 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2010 /* Load/Store register offset */
2011 if ((opcode
& 0xf000) == 0x5000)
2013 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2016 /* Load/Store immediate offset */
2017 if (((opcode
& 0xe000) == 0x6000)
2018 ||((opcode
& 0xf000) == 0x8000))
2020 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2023 /* Load/Store from/to stack */
2024 if ((opcode
& 0xf000) == 0x9000)
2026 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2030 if ((opcode
& 0xf000) == 0xa000)
2032 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2036 if ((opcode
& 0xf000) == 0xb000)
2038 if ((opcode
& 0x0f00) == 0x0000)
2039 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2040 else if ((opcode
& 0x0f00) == 0x0e00)
2041 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2042 else if ((opcode
& 0x0600) == 0x0400) /* push pop */
2043 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2046 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2047 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
2052 /* Load/Store multiple */
2053 if ((opcode
& 0xf000) == 0xc000)
2055 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2058 /* Conditional branch + SWI */
2059 if ((opcode
& 0xf000) == 0xd000)
2061 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2064 if ((opcode
& 0xe000) == 0xe000)
2066 /* Undefined instructions */
2067 if ((opcode
& 0xf801) == 0xe801)
2069 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2070 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
2074 { /* Branch to offset */
2075 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2079 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2083 int arm_access_size(arm_instruction_t
*instruction
)
2085 if ((instruction
->type
== ARM_LDRB
)
2086 || (instruction
->type
== ARM_LDRBT
)
2087 || (instruction
->type
== ARM_LDRSB
)
2088 || (instruction
->type
== ARM_STRB
)
2089 || (instruction
->type
== ARM_STRBT
))
2093 else if ((instruction
->type
== ARM_LDRH
)
2094 || (instruction
->type
== ARM_LDRSH
)
2095 || (instruction
->type
== ARM_STRH
))
2099 else if ((instruction
->type
== ARM_LDR
)
2100 || (instruction
->type
== ARM_LDRT
)
2101 || (instruction
->type
== ARM_STR
)
2102 || (instruction
->type
== ARM_STRT
))
2106 else if ((instruction
->type
== ARM_LDRD
)
2107 || (instruction
->type
== ARM_STRD
))
2113 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)