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 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);
346 snprintf(offset
, 32, "#%s0x%x", (U
) ? "" : "-", offset_12
);
348 instruction
->info
.load_store
.offset_mode
= 0;
349 instruction
->info
.load_store
.offset
.offset
= offset_12
;
351 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
356 shift_imm
= (opcode
& 0xf80) >> 7;
357 shift
= (opcode
& 0x60) >> 5;
360 /* LSR encodes a shift by 32 bit as 0x0 */
361 if ((shift
== 0x1) && (shift_imm
== 0x0))
364 /* ASR encodes a shift by 32 bit as 0x0 */
365 if ((shift
== 0x2) && (shift_imm
== 0x0))
368 /* ROR by 32 bit is actually a RRX */
369 if ((shift
== 0x3) && (shift_imm
== 0x0))
372 instruction
->info
.load_store
.offset_mode
= 1;
373 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
374 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
375 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
377 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
379 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
381 else /* +-<Rm>, <Shift>, #<shift_imm> */
386 snprintf(offset
, 32, "%sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
389 snprintf(offset
, 32, "%sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
392 snprintf(offset
, 32, "%sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
395 snprintf(offset
, 32, "%sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
398 snprintf(offset
, 32, "%sr%i, RRX", (U
) ? "" : "-", Rm
);
406 if (W
== 0) /* offset */
408 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
409 address
, opcode
, operation
, COND(opcode
), suffix
,
412 instruction
->info
.load_store
.index_mode
= 0;
414 else /* pre-indexed */
416 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
417 address
, opcode
, operation
, COND(opcode
), suffix
,
420 instruction
->info
.load_store
.index_mode
= 1;
423 else /* post-indexed */
425 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
426 address
, opcode
, operation
, COND(opcode
), suffix
,
429 instruction
->info
.load_store
.index_mode
= 2;
435 /* Miscellaneous load/store instructions */
436 int evaluate_misc_load_store(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
438 u8 P
, U
, I
, W
, L
, S
, H
;
440 char *operation
; /* "LDR" or "STR" */
441 char *suffix
; /* "H", "SB", "SH", "D" */
445 P
= (opcode
& 0x01000000) >> 24;
446 U
= (opcode
& 0x00800000) >> 23;
447 I
= (opcode
& 0x00400000) >> 22;
448 W
= (opcode
& 0x00200000) >> 21;
449 L
= (opcode
& 0x00100000) >> 20;
450 S
= (opcode
& 0x00000040) >> 6;
451 H
= (opcode
& 0x00000020) >> 5;
453 /* target register */
454 Rd
= (opcode
& 0xf000) >> 12;
457 Rn
= (opcode
& 0xf0000) >> 16;
459 instruction
->info
.load_store
.Rd
= Rd
;
460 instruction
->info
.load_store
.Rn
= Rn
;
461 instruction
->info
.load_store
.U
= U
;
463 /* determine instruction type and suffix */
471 instruction
->type
= ARM_LDRSH
;
477 instruction
->type
= ARM_LDRSB
;
481 else /* there are no signed stores, so this is used to encode double-register load/stores */
487 instruction
->type
= ARM_STRD
;
492 instruction
->type
= ARM_LDRD
;
502 instruction
->type
= ARM_LDRH
;
507 instruction
->type
= ARM_STRH
;
511 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
513 u32 offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
514 snprintf(offset
, 32, "#%s0x%x", (U
) ? "" : "-", offset_8
);
516 instruction
->info
.load_store
.offset_mode
= 0;
517 instruction
->info
.load_store
.offset
.offset
= offset_8
;
519 else /* Register offset/index (+-<Rm>) */
523 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
525 instruction
->info
.load_store
.offset_mode
= 1;
526 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
527 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
528 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
533 if (W
== 0) /* offset */
535 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
536 address
, opcode
, operation
, COND(opcode
), suffix
,
539 instruction
->info
.load_store
.index_mode
= 0;
541 else /* pre-indexed */
543 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
544 address
, opcode
, operation
, COND(opcode
), suffix
,
547 instruction
->info
.load_store
.index_mode
= 1;
550 else /* post-indexed */
552 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
553 address
, opcode
, operation
, COND(opcode
), suffix
,
556 instruction
->info
.load_store
.index_mode
= 2;
562 /* Load/store multiples instructions */
563 int evaluate_ldm_stm(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
565 u8 P
, U
, S
, W
, L
, Rn
;
567 char *addressing_mode
;
574 P
= (opcode
& 0x01000000) >> 24;
575 U
= (opcode
& 0x00800000) >> 23;
576 S
= (opcode
& 0x00400000) >> 22;
577 W
= (opcode
& 0x00200000) >> 21;
578 L
= (opcode
& 0x00100000) >> 20;
579 register_list
= (opcode
& 0xffff);
580 Rn
= (opcode
& 0xf0000) >> 16;
582 instruction
->info
.load_store_multiple
.Rn
= Rn
;
583 instruction
->info
.load_store_multiple
.register_list
= register_list
;
584 instruction
->info
.load_store_multiple
.S
= S
;
585 instruction
->info
.load_store_multiple
.W
= W
;
589 instruction
->type
= ARM_LDM
;
594 instruction
->type
= ARM_STM
;
602 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
603 addressing_mode
= "IB";
607 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
608 addressing_mode
= "DB";
615 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
616 addressing_mode
= "IA";
620 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
621 addressing_mode
= "DA";
625 reg_list_p
= reg_list
;
626 for (i
= 0; i
<= 15; i
++)
628 if ((register_list
>> i
) & 1)
633 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
637 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
642 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i%s, {%s}%s",
643 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
644 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
649 /* Multiplies, extra load/stores */
650 int evaluate_mul_and_extra_ld_st(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
652 /* Multiply (accumulate) (long) and Swap/swap byte */
653 if ((opcode
& 0x000000f0) == 0x00000090)
655 /* Multiply (accumulate) */
656 if ((opcode
& 0x0f800000) == 0x00000000)
658 u8 Rm
, Rs
, Rn
, Rd
, S
;
660 Rs
= (opcode
& 0xf00) >> 8;
661 Rn
= (opcode
& 0xf000) >> 12;
662 Rd
= (opcode
& 0xf0000) >> 16;
663 S
= (opcode
& 0x00100000) >> 20;
665 /* examine A bit (accumulate) */
666 if (opcode
& 0x00200000)
668 instruction
->type
= ARM_MLA
;
669 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMLA%s%s r%i, r%i, r%i, r%i",
670 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
674 instruction
->type
= ARM_MUL
;
675 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMUL%s%s r%i, r%i, r%i",
676 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
682 /* Multiply (accumulate) long */
683 if ((opcode
& 0x0f800000) == 0x00800000)
686 u8 Rm
, Rs
, RdHi
, RdLow
, S
;
688 Rs
= (opcode
& 0xf00) >> 8;
689 RdHi
= (opcode
& 0xf000) >> 12;
690 RdLow
= (opcode
& 0xf0000) >> 16;
691 S
= (opcode
& 0x00100000) >> 20;
693 switch ((opcode
& 0x00600000) >> 21)
696 instruction
->type
= ARM_UMULL
;
700 instruction
->type
= ARM_UMLAL
;
704 instruction
->type
= ARM_SMULL
;
708 instruction
->type
= ARM_SMLAL
;
713 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, r%i, r%i",
714 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
715 RdLow
, RdHi
, Rm
, Rs
);
721 if ((opcode
& 0x0f800000) == 0x01000000)
725 Rd
= (opcode
& 0xf000) >> 12;
726 Rn
= (opcode
& 0xf0000) >> 16;
729 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
731 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, [r%i]",
732 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
738 return evaluate_misc_load_store(opcode
, address
, instruction
);
741 int evaluate_mrs_msr(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
743 int R
= (opcode
& 0x00400000) >> 22;
744 char *PSR
= (R
) ? "SPSR" : "CPSR";
746 /* Move register to status register (MSR) */
747 if (opcode
& 0x00200000)
749 instruction
->type
= ARM_MSR
;
751 /* immediate variant */
752 if (opcode
& 0x02000000)
754 u8 immediate
= (opcode
& 0xff);
755 u8 rotate
= (opcode
& 0xf00);
757 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, 0x%8.8x",
758 address
, opcode
, COND(opcode
), PSR
,
759 (opcode
& 0x10000) ? "c" : "",
760 (opcode
& 0x20000) ? "x" : "",
761 (opcode
& 0x40000) ? "s" : "",
762 (opcode
& 0x80000) ? "f" : "",
763 ror(immediate
, (rotate
* 2))
766 else /* register variant */
768 u8 Rm
= opcode
& 0xf;
769 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, r%i",
770 address
, opcode
, COND(opcode
), PSR
,
771 (opcode
& 0x10000) ? "c" : "",
772 (opcode
& 0x20000) ? "x" : "",
773 (opcode
& 0x40000) ? "s" : "",
774 (opcode
& 0x80000) ? "f" : "",
780 else /* Move status register to register (MRS) */
784 instruction
->type
= ARM_MRS
;
785 Rd
= (opcode
& 0x0000f000) >> 12;
787 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMRS%s r%i, %s",
788 address
, opcode
, COND(opcode
), Rd
, PSR
);
794 /* Miscellaneous instructions */
795 int evaluate_misc_instr(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
798 if ((opcode
& 0x000000f0) == 0x00000000)
800 evaluate_mrs_msr(opcode
, address
, instruction
);
804 if ((opcode
& 0x006000f0) == 0x00200010)
807 instruction
->type
= ARM_BX
;
810 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBX%s r%i",
811 address
, opcode
, COND(opcode
), Rm
);
813 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
814 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
818 if ((opcode
& 0x0060000f0) == 0x00300010)
821 instruction
->type
= ARM_CLZ
;
823 Rd
= (opcode
& 0xf000) >> 12;
825 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tCLZ%s r%i, r%i",
826 address
, opcode
, COND(opcode
), Rd
, Rm
);
830 if ((opcode
& 0x0060000f0) == 0x00200030)
833 instruction
->type
= ARM_BLX
;
836 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
837 address
, opcode
, COND(opcode
), Rm
);
840 /* Enhanced DSP add/subtracts */
841 if ((opcode
& 0x0000000f0) == 0x00000050)
846 Rd
= (opcode
& 0xf000) >> 12;
847 Rn
= (opcode
& 0xf0000) >> 16;
849 switch ((opcode
& 0x00600000) >> 21)
852 instruction
->type
= ARM_QADD
;
856 instruction
->type
= ARM_QSUB
;
860 instruction
->type
= ARM_QDADD
;
864 instruction
->type
= ARM_QDSUB
;
869 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, r%i",
870 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
873 /* Software breakpoints */
874 if ((opcode
& 0x0000000f0) == 0x00000070)
877 instruction
->type
= ARM_BKPT
;
878 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
880 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBKPT 0x%4.4x",
881 address
, opcode
, immediate
);
884 /* Enhanced DSP multiplies */
885 if ((opcode
& 0x000000090) == 0x00000080)
887 int x
= (opcode
& 0x20) >> 5;
888 int y
= (opcode
& 0x40) >> 6;
891 if ((opcode
& 0x00600000) == 0x00000000)
894 instruction
->type
= ARM_SMLAxy
;
895 Rd
= (opcode
& 0xf0000) >> 16;
897 Rs
= (opcode
& 0xf00) >> 8;
898 Rn
= (opcode
& 0xf000) >> 12;
900 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
901 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
906 if ((opcode
& 0x00600000) == 0x00400000)
908 u8 RdLow
, RdHi
, Rm
, Rs
;
909 instruction
->type
= ARM_SMLAxy
;
910 RdHi
= (opcode
& 0xf0000) >> 16;
911 RdLow
= (opcode
& 0xf000) >> 12;
913 Rs
= (opcode
& 0xf00) >> 8;
915 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
916 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
917 RdLow
, RdHi
, Rm
, Rs
);
921 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
924 instruction
->type
= ARM_SMLAWy
;
925 Rd
= (opcode
& 0xf0000) >> 16;
927 Rs
= (opcode
& 0xf00) >> 8;
928 Rn
= (opcode
& 0xf000) >> 12;
930 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLAW%s%s r%i, r%i, r%i, r%i",
931 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
936 if ((opcode
& 0x00600000) == 0x00300000)
939 instruction
->type
= ARM_SMULxy
;
940 Rd
= (opcode
& 0xf0000) >> 16;
942 Rs
= (opcode
& 0xf00) >> 8;
944 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s%s r%i, r%i, r%i",
945 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
950 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
953 instruction
->type
= ARM_SMULWy
;
954 Rd
= (opcode
& 0xf0000) >> 16;
956 Rs
= (opcode
& 0xf00) >> 8;
958 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s r%i, r%i, r%i",
959 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
967 int evaluate_data_proc(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
971 char shifter_operand
[32];
973 I
= (opcode
& 0x02000000) >> 25;
974 op
= (opcode
& 0x01e00000) >> 21;
975 S
= (opcode
& 0x00100000) >> 20;
977 Rd
= (opcode
& 0xf000) >> 12;
978 Rn
= (opcode
& 0xf0000) >> 16;
980 instruction
->info
.data_proc
.Rd
= Rd
;
981 instruction
->info
.data_proc
.Rn
= Rn
;
982 instruction
->info
.data_proc
.S
= S
;
987 instruction
->type
= ARM_AND
;
991 instruction
->type
= ARM_EOR
;
995 instruction
->type
= ARM_SUB
;
999 instruction
->type
= ARM_RSB
;
1003 instruction
->type
= ARM_ADD
;
1007 instruction
->type
= ARM_ADC
;
1011 instruction
->type
= ARM_SBC
;
1015 instruction
->type
= ARM_RSC
;
1019 instruction
->type
= ARM_TST
;
1023 instruction
->type
= ARM_TEQ
;
1027 instruction
->type
= ARM_CMP
;
1031 instruction
->type
= ARM_CMN
;
1035 instruction
->type
= ARM_ORR
;
1039 instruction
->type
= ARM_MOV
;
1043 instruction
->type
= ARM_BIC
;
1047 instruction
->type
= ARM_MVN
;
1052 if (I
) /* immediate shifter operand (#<immediate>)*/
1054 u8 immed_8
= opcode
& 0xff;
1055 u8 rotate_imm
= (opcode
& 0xf00) >> 8;
1058 immediate
= ror(immed_8
, rotate_imm
* 2);
1060 snprintf(shifter_operand
, 32, "#0x%x", immediate
);
1062 instruction
->info
.data_proc
.variant
= 0;
1063 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1065 else /* register-based shifter operand */
1068 shift
= (opcode
& 0x60) >> 5;
1069 Rm
= (opcode
& 0xf);
1071 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1074 shift_imm
= (opcode
& 0xf80) >> 7;
1076 instruction
->info
.data_proc
.variant
= 1;
1077 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1078 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1079 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1081 if ((shift_imm
== 0x0) && (shift
== 0x0))
1083 snprintf(shifter_operand
, 32, "r%i", Rm
);
1087 if (shift
== 0x0) /* LSL */
1089 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1091 else if (shift
== 0x1) /* LSR */
1093 if (shift_imm
== 0x0)
1095 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1097 else if (shift
== 0x2) /* ASR */
1099 if (shift_imm
== 0x0)
1101 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1103 else if (shift
== 0x3) /* ROR or RRX */
1105 if (shift_imm
== 0x0) /* RRX */
1106 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1108 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1112 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1114 u8 Rs
= (opcode
& 0xf00) >> 8;
1116 instruction
->info
.data_proc
.variant
= 2;
1117 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1118 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1119 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1121 if (shift
== 0x0) /* LSL */
1123 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1125 else if (shift
== 0x1) /* LSR */
1127 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1129 else if (shift
== 0x2) /* ASR */
1131 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1133 else if (shift
== 0x3) /* ROR or RRX */
1135 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1140 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1142 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, %s",
1143 address
, opcode
, mnemonic
, COND(opcode
),
1144 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1146 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1148 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
1149 address
, opcode
, mnemonic
, COND(opcode
),
1150 (S
) ? "S" : "", Rd
, shifter_operand
);
1152 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1154 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, %s",
1155 address
, opcode
, mnemonic
, COND(opcode
),
1156 Rn
, shifter_operand
);
1162 int evaluate_opcode(u32 opcode
, u32 address
, arm_instruction_t
*instruction
)
1164 /* clear fields, to avoid confusion */
1165 memset(instruction
, 0, sizeof(arm_instruction_t
));
1166 instruction
->opcode
= opcode
;
1168 /* catch opcodes with condition field [31:28] = b1111 */
1169 if ((opcode
& 0xf0000000) == 0xf0000000)
1171 /* Undefined instruction (or ARMv5E cache preload PLD) */
1172 if ((opcode
& 0x08000000) == 0x00000000)
1173 return evaluate_pld(opcode
, address
, instruction
);
1175 /* Undefined instruction */
1176 if ((opcode
& 0x0e000000) == 0x08000000)
1178 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1179 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1183 /* Branch and branch with link and change to Thumb */
1184 if ((opcode
& 0x0e000000) == 0x0a000000)
1185 return evaluate_blx_imm(opcode
, address
, instruction
);
1187 /* Extended coprocessor opcode space (ARMv5 and higher )*/
1188 /* Coprocessor load/store and double register transfers */
1189 if ((opcode
& 0x0e000000) == 0x0c000000)
1190 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1192 /* Coprocessor data processing */
1193 if ((opcode
& 0x0f000100) == 0x0c000000)
1194 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1196 /* Coprocessor register transfers */
1197 if ((opcode
& 0x0f000010) == 0x0c000010)
1198 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1200 /* Undefined instruction */
1201 if ((opcode
& 0x0f000000) == 0x0f000000)
1203 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1204 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1209 /* catch opcodes with [27:25] = b000 */
1210 if ((opcode
& 0x0e000000) == 0x00000000)
1212 /* Multiplies, extra load/stores */
1213 if ((opcode
& 0x00000090) == 0x00000090)
1214 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1216 /* Miscellaneous instructions */
1217 if ((opcode
& 0x0f900000) == 0x01000000)
1218 return evaluate_misc_instr(opcode
, address
, instruction
);
1220 return evaluate_data_proc(opcode
, address
, instruction
);
1223 /* catch opcodes with [27:25] = b001 */
1224 if ((opcode
& 0x0e000000) == 0x02000000)
1226 /* Undefined instruction */
1227 if ((opcode
& 0x0fb00000) == 0x03000000)
1229 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1230 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1234 /* Move immediate to status register */
1235 if ((opcode
& 0x0fb00000) == 0x03200000)
1236 return evaluate_mrs_msr(opcode
, address
, instruction
);
1238 return evaluate_data_proc(opcode
, address
, instruction
);
1242 /* catch opcodes with [27:25] = b010 */
1243 if ((opcode
& 0x0e000000) == 0x04000000)
1245 /* Load/store immediate offset */
1246 return evaluate_load_store(opcode
, address
, instruction
);
1249 /* catch opcodes with [27:25] = b011 */
1250 if ((opcode
& 0x0e000000) == 0x06000000)
1252 /* Undefined instruction */
1253 if ((opcode
& 0x00000010) == 0x00000010)
1255 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1256 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1260 /* Load/store register offset */
1261 return evaluate_load_store(opcode
, address
, instruction
);
1265 /* catch opcodes with [27:25] = b100 */
1266 if ((opcode
& 0x0e000000) == 0x08000000)
1268 /* Load/store multiple */
1269 return evaluate_ldm_stm(opcode
, address
, instruction
);
1272 /* catch opcodes with [27:25] = b101 */
1273 if ((opcode
& 0x0e000000) == 0x0a000000)
1275 /* Branch and branch with link */
1276 return evaluate_b_bl(opcode
, address
, instruction
);
1279 /* catch opcodes with [27:25] = b110 */
1280 if ((opcode
& 0x0e000000) == 0x0a000000)
1282 /* Coprocessor load/store and double register transfers */
1283 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1286 /* catch opcodes with [27:25] = b111 */
1287 if ((opcode
& 0x0e000000) == 0x0e000000)
1289 /* Software interrupt */
1290 if ((opcode
& 0x0f000000) == 0x0f000000)
1291 return evaluate_swi(opcode
, address
, instruction
);
1293 /* Coprocessor data processing */
1294 if ((opcode
& 0x0f000010) == 0x0e000000)
1295 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1297 /* Coprocessor register transfers */
1298 if ((opcode
& 0x0f000010) == 0x0e000010)
1299 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1302 ERROR("should never reach this point");
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)