1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
27 #include "arm_disassembler.h"
31 /* textual represenation of the condition field */
32 /* ALways (default) is ommitted (empty string) */
33 char *arm_condition_strings[] =
35 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
38 /* make up for C's missing ROR */
39 uint32_t ror(uint32_t value, int places)
41 return (value >> places) | (value << (32 - places));
44 int evaluate_pld(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
47 if ((opcode & 0x0d70f0000) == 0x0550f000)
49 instruction->type = ARM_PLD;
51 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD ...TODO...", address, opcode);
57 instruction->type = ARM_UNDEFINED_INSTRUCTION;
61 LOG_ERROR("should never reach this point");
65 int evaluate_swi(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
67 instruction->type = ARM_SWI;
69 snprintf(instruction->text, 128,
70 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVC %#6.6" PRIx32,
71 address, opcode, (opcode & 0xffffff));
76 int evaluate_blx_imm(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
80 uint32_t target_address;
82 instruction->type = ARM_BLX;
83 immediate = opcode & 0x00ffffff;
85 /* sign extend 24-bit immediate */
86 if (immediate & 0x00800000)
87 offset = 0xff000000 | immediate;
91 /* shift two bits left */
94 /* odd/event halfword */
95 if (opcode & 0x01000000)
98 target_address = address + 8 + offset;
100 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32 "", address, opcode, target_address);
102 instruction->info.b_bl_bx_blx.reg_operand = -1;
103 instruction->info.b_bl_bx_blx.target_address = target_address;
108 int evaluate_b_bl(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
113 uint32_t target_address;
115 immediate = opcode & 0x00ffffff;
116 L = (opcode & 0x01000000) >> 24;
118 /* sign extend 24-bit immediate */
119 if (immediate & 0x00800000)
120 offset = 0xff000000 | immediate;
124 /* shift two bits left */
127 target_address = address + 8 + offset;
130 instruction->type = ARM_BL;
132 instruction->type = ARM_B;
134 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tB%s%s 0x%8.8" PRIx32 , address, opcode,
135 (L) ? "L" : "", COND(opcode), target_address);
137 instruction->info.b_bl_bx_blx.reg_operand = -1;
138 instruction->info.b_bl_bx_blx.target_address = target_address;
143 /* Coprocessor load/store and double register transfers */
144 /* both normal and extended instruction space (condition field b1111) */
145 int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
147 uint8_t cp_num = (opcode & 0xf00) >> 8;
150 if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c400000))
152 uint8_t cp_opcode, Rd, Rn, CRm;
155 cp_opcode = (opcode & 0xf0) >> 4;
156 Rd = (opcode & 0xf000) >> 12;
157 Rn = (opcode & 0xf0000) >> 16;
158 CRm = (opcode & 0xf);
161 if ((opcode & 0x0ff00000) == 0x0c400000)
163 instruction->type = ARM_MCRR;
168 if ((opcode & 0x0ff00000) == 0x0c500000)
170 instruction->type = ARM_MRRC;
174 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, %x, r%i, r%i, c%i",
175 address, opcode, mnemonic, COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm);
177 else /* LDC or STC */
179 uint8_t CRd, Rn, offset;
182 char addressing_mode[32];
184 CRd = (opcode & 0xf000) >> 12;
185 Rn = (opcode & 0xf0000) >> 16;
186 offset = (opcode & 0xff);
189 if (opcode & 0x00100000)
191 instruction->type = ARM_LDC;
196 instruction->type = ARM_STC;
200 U = (opcode & 0x00800000) >> 23;
201 N = (opcode & 0x00400000) >> 22;
203 /* addressing modes */
204 if ((opcode & 0x01200000) == 0x01000000) /* immediate offset */
205 snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]", Rn, (U) ? "" : "-", offset);
206 else if ((opcode & 0x01200000) == 0x01200000) /* immediate pre-indexed */
207 snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]!", Rn, (U) ? "" : "-", offset);
208 else if ((opcode & 0x01200000) == 0x00200000) /* immediate post-indexed */
209 snprintf(addressing_mode, 32, "[r%i], #%s0x%2.2x*4", Rn, (U) ? "" : "-", offset);
210 else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */
211 snprintf(addressing_mode, 32, "[r%i], #0x%2.2x", Rn, offset);
213 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s p%i, c%i, %s",
214 address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? COND(opcode) : "2",
216 cp_num, CRd, addressing_mode);
222 /* Coprocessor data processing instructions */
223 /* Coprocessor register transfer instructions */
224 /* both normal and extended instruction space (condition field b1111) */
225 int evaluate_cdp_mcr_mrc(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
229 uint8_t cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2;
231 cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode);
232 cp_num = (opcode & 0xf00) >> 8;
233 CRd_Rd = (opcode & 0xf000) >> 12;
234 CRn = (opcode & 0xf0000) >> 16;
235 CRm = (opcode & 0xf);
236 opcode_2 = (opcode & 0xe0) >> 5;
239 if (opcode & 0x00000010) /* bit 4 set -> MRC/MCR */
241 if (opcode & 0x00100000) /* bit 20 set -> MRC */
243 instruction->type = ARM_MRC;
246 else /* bit 20 not set -> MCR */
248 instruction->type = ARM_MCR;
252 opcode_1 = (opcode & 0x00e00000) >> 21;
254 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
255 address, opcode, mnemonic, cond,
256 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
258 else /* bit 4 not set -> CDP */
260 instruction->type = ARM_CDP;
263 opcode_1 = (opcode & 0x00f00000) >> 20;
265 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
266 address, opcode, mnemonic, cond,
267 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
273 /* Load/store instructions */
274 int evaluate_load_store(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
276 uint8_t I, P, U, B, W, L;
278 char *operation; /* "LDR" or "STR" */
279 char *suffix; /* "", "B", "T", "BT" */
283 I = (opcode & 0x02000000) >> 25;
284 P = (opcode & 0x01000000) >> 24;
285 U = (opcode & 0x00800000) >> 23;
286 B = (opcode & 0x00400000) >> 22;
287 W = (opcode & 0x00200000) >> 21;
288 L = (opcode & 0x00100000) >> 20;
290 /* target register */
291 Rd = (opcode & 0xf000) >> 12;
294 Rn = (opcode & 0xf0000) >> 16;
296 instruction->info.load_store.Rd = Rd;
297 instruction->info.load_store.Rn = Rn;
298 instruction->info.load_store.U = U;
300 /* determine operation */
306 /* determine instruction type and suffix */
309 if ((P == 0) && (W == 1))
312 instruction->type = ARM_LDRBT;
314 instruction->type = ARM_STRBT;
320 instruction->type = ARM_LDRB;
322 instruction->type = ARM_STRB;
328 if ((P == 0) && (W == 1))
331 instruction->type = ARM_LDRT;
333 instruction->type = ARM_STRT;
339 instruction->type = ARM_LDR;
341 instruction->type = ARM_STR;
346 if (!I) /* #+-<offset_12> */
348 uint32_t offset_12 = (opcode & 0xfff);
350 snprintf(offset, 32, ", #%s0x%" PRIx32 "", (U) ? "" : "-", offset_12);
352 snprintf(offset, 32, "%s", "");
354 instruction->info.load_store.offset_mode = 0;
355 instruction->info.load_store.offset.offset = offset_12;
357 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
359 uint8_t shift_imm, shift;
362 shift_imm = (opcode & 0xf80) >> 7;
363 shift = (opcode & 0x60) >> 5;
366 /* LSR encodes a shift by 32 bit as 0x0 */
367 if ((shift == 0x1) && (shift_imm == 0x0))
370 /* ASR encodes a shift by 32 bit as 0x0 */
371 if ((shift == 0x2) && (shift_imm == 0x0))
374 /* ROR by 32 bit is actually a RRX */
375 if ((shift == 0x3) && (shift_imm == 0x0))
378 instruction->info.load_store.offset_mode = 1;
379 instruction->info.load_store.offset.reg.Rm = Rm;
380 instruction->info.load_store.offset.reg.shift = shift;
381 instruction->info.load_store.offset.reg.shift_imm = shift_imm;
383 if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
385 snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm);
387 else /* +-<Rm>, <Shift>, #<shift_imm> */
392 snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
395 snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
398 snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
401 snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
404 snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm);
412 if (W == 0) /* offset */
414 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]",
415 address, opcode, operation, COND(opcode), suffix,
418 instruction->info.load_store.index_mode = 0;
420 else /* pre-indexed */
422 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]!",
423 address, opcode, operation, COND(opcode), suffix,
426 instruction->info.load_store.index_mode = 1;
429 else /* post-indexed */
431 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i]%s",
432 address, opcode, operation, COND(opcode), suffix,
435 instruction->info.load_store.index_mode = 2;
441 static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp)
443 unsigned rm = (opcode >> 0) & 0xf;
444 unsigned rd = (opcode >> 12) & 0xf;
445 unsigned rn = (opcode >> 16) & 0xf;
448 switch ((opcode >> 24) & 0x3) {
453 sprintf(cp, "UNDEFINED");
454 return ARM_UNDEFINED_INSTRUCTION;
463 switch ((opcode >> 10) & 0x3) {
479 sprintf(cp, "%cXT%s%s\tr%d, r%d%s",
480 (opcode & (1 << 22)) ? 'U' : 'S',
485 sprintf(cp, "%cXTA%s%s\tr%d, r%d, r%d%s",
486 (opcode & (1 << 22)) ? 'U' : 'S',
493 static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp)
499 switch ((opcode >> 20) & 0x7) {
522 switch ((opcode >> 5) & 0x7) {
551 sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode),
552 (int) (opcode >> 12) & 0xf,
553 (int) (opcode >> 16) & 0xf,
554 (int) (opcode >> 0) & 0xf);
558 /* these opcodes might be used someday */
559 sprintf(cp, "UNDEFINED");
560 return ARM_UNDEFINED_INSTRUCTION;
563 /* ARMv6 and later support "media" instructions (includes SIMD) */
564 static int evaluate_media(uint32_t opcode, uint32_t address,
565 arm_instruction_t *instruction)
567 char *cp = instruction->text;
568 char *mnemonic = NULL;
571 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t",
575 /* parallel add/subtract */
576 if ((opcode & 0x01800000) == 0x00000000) {
577 instruction->type = evaluate_p_add_sub(opcode, address, cp);
582 if ((opcode & 0x01f00020) == 0x00800000) {
584 unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
586 if (opcode & (1 << 6)) {
595 sprintf(cp, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
597 (int) (opcode >> 12) & 0xf,
598 (int) (opcode >> 16) & 0xf,
599 (int) (opcode >> 0) & 0xf,
605 if ((opcode & 0x01a00020) == 0x00a00000) {
607 unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
609 if (opcode & (1 << 6)) {
617 sprintf(cp, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
618 (opcode & (1 << 22)) ? 'U' : 'S',
620 (int) (opcode >> 12) & 0xf,
621 (int) (opcode >> 16) & 0x1f,
622 (int) (opcode >> 0) & 0xf,
628 if ((opcode & 0x018000f0) == 0x00800070) {
629 instruction->type = evaluate_extend(opcode, address, cp);
634 if ((opcode & 0x01f00080) == 0x01000000) {
635 unsigned rn = (opcode >> 12) & 0xf;
638 sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
639 (opcode & (1 << 6)) ? 'S' : 'A',
640 (opcode & (1 << 5)) ? "X" : "",
642 (int) (opcode >> 16) & 0xf,
643 (int) (opcode >> 0) & 0xf,
644 (int) (opcode >> 8) & 0xf,
647 sprintf(cp, "SMU%cD%s%s\tr%d, r%d, r%d",
648 (opcode & (1 << 6)) ? 'S' : 'A',
649 (opcode & (1 << 5)) ? "X" : "",
651 (int) (opcode >> 16) & 0xf,
652 (int) (opcode >> 0) & 0xf,
653 (int) (opcode >> 8) & 0xf);
656 if ((opcode & 0x01f00000) == 0x01400000) {
657 sprintf(cp, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
658 (opcode & (1 << 6)) ? 'S' : 'A',
659 (opcode & (1 << 5)) ? "X" : "",
661 (int) (opcode >> 12) & 0xf,
662 (int) (opcode >> 16) & 0xf,
663 (int) (opcode >> 0) & 0xf,
664 (int) (opcode >> 8) & 0xf);
667 if ((opcode & 0x01f00000) == 0x01500000) {
668 unsigned rn = (opcode >> 12) & 0xf;
670 switch (opcode & 0xc0) {
682 sprintf(cp, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
683 (opcode & (1 << 6)) ? 'S' : 'A',
684 (opcode & (1 << 5)) ? "R" : "",
686 (int) (opcode >> 16) & 0xf,
687 (int) (opcode >> 0) & 0xf,
688 (int) (opcode >> 8) & 0xf,
691 sprintf(cp, "SMMUL%s%s\tr%d, r%d, r%d",
692 (opcode & (1 << 5)) ? "R" : "",
694 (int) (opcode >> 16) & 0xf,
695 (int) (opcode >> 0) & 0xf,
696 (int) (opcode >> 8) & 0xf);
701 /* simple matches against the remaining decode bits */
702 switch (opcode & 0x01f000f0) {
705 /* parallel halfword saturate */
706 sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d",
707 (opcode & (1 << 22)) ? 'U' : 'S',
709 (int) (opcode >> 12) & 0xf,
710 (int) (opcode >> 16) & 0xf,
711 (int) (opcode >> 0) & 0xf);
724 sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode),
725 (int) (opcode >> 12) & 0xf,
726 (int) (opcode >> 16) & 0xf,
727 (int) (opcode >> 0) & 0xf);
730 /* unsigned sum of absolute differences */
731 if (((opcode >> 12) & 0xf) == 0xf)
732 sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode),
733 (int) (opcode >> 16) & 0xf,
734 (int) (opcode >> 0) & 0xf,
735 (int) (opcode >> 8) & 0xf);
737 sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode),
738 (int) (opcode >> 16) & 0xf,
739 (int) (opcode >> 0) & 0xf,
740 (int) (opcode >> 8) & 0xf,
741 (int) (opcode >> 12) & 0xf);
745 unsigned rm = (opcode >> 0) & 0xf;
746 unsigned rd = (opcode >> 12) & 0xf;
748 sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd);
753 /* these opcodes might be used someday */
754 sprintf(cp, "UNDEFINED");
758 /* Miscellaneous load/store instructions */
759 int evaluate_misc_load_store(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
761 uint8_t P, U, I, W, L, S, H;
763 char *operation; /* "LDR" or "STR" */
764 char *suffix; /* "H", "SB", "SH", "D" */
768 P = (opcode & 0x01000000) >> 24;
769 U = (opcode & 0x00800000) >> 23;
770 I = (opcode & 0x00400000) >> 22;
771 W = (opcode & 0x00200000) >> 21;
772 L = (opcode & 0x00100000) >> 20;
773 S = (opcode & 0x00000040) >> 6;
774 H = (opcode & 0x00000020) >> 5;
776 /* target register */
777 Rd = (opcode & 0xf000) >> 12;
780 Rn = (opcode & 0xf0000) >> 16;
782 instruction->info.load_store.Rd = Rd;
783 instruction->info.load_store.Rn = Rn;
784 instruction->info.load_store.U = U;
786 /* determine instruction type and suffix */
794 instruction->type = ARM_LDRSH;
800 instruction->type = ARM_LDRSB;
804 else /* there are no signed stores, so this is used to encode double-register load/stores */
810 instruction->type = ARM_STRD;
815 instruction->type = ARM_LDRD;
825 instruction->type = ARM_LDRH;
830 instruction->type = ARM_STRH;
834 if (I) /* Immediate offset/index (#+-<offset_8>)*/
836 uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
837 snprintf(offset, 32, "#%s0x%" PRIx32 "", (U) ? "" : "-", offset_8);
839 instruction->info.load_store.offset_mode = 0;
840 instruction->info.load_store.offset.offset = offset_8;
842 else /* Register offset/index (+-<Rm>) */
846 snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
848 instruction->info.load_store.offset_mode = 1;
849 instruction->info.load_store.offset.reg.Rm = Rm;
850 instruction->info.load_store.offset.reg.shift = 0x0;
851 instruction->info.load_store.offset.reg.shift_imm = 0x0;
856 if (W == 0) /* offset */
858 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]",
859 address, opcode, operation, COND(opcode), suffix,
862 instruction->info.load_store.index_mode = 0;
864 else /* pre-indexed */
866 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]!",
867 address, opcode, operation, COND(opcode), suffix,
870 instruction->info.load_store.index_mode = 1;
873 else /* post-indexed */
875 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i], %s",
876 address, opcode, operation, COND(opcode), suffix,
879 instruction->info.load_store.index_mode = 2;
885 /* Load/store multiples instructions */
886 int evaluate_ldm_stm(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
888 uint8_t P, U, S, W, L, Rn;
889 uint32_t register_list;
890 char *addressing_mode;
897 P = (opcode & 0x01000000) >> 24;
898 U = (opcode & 0x00800000) >> 23;
899 S = (opcode & 0x00400000) >> 22;
900 W = (opcode & 0x00200000) >> 21;
901 L = (opcode & 0x00100000) >> 20;
902 register_list = (opcode & 0xffff);
903 Rn = (opcode & 0xf0000) >> 16;
905 instruction->info.load_store_multiple.Rn = Rn;
906 instruction->info.load_store_multiple.register_list = register_list;
907 instruction->info.load_store_multiple.S = S;
908 instruction->info.load_store_multiple.W = W;
912 instruction->type = ARM_LDM;
917 instruction->type = ARM_STM;
925 instruction->info.load_store_multiple.addressing_mode = 1;
926 addressing_mode = "IB";
930 instruction->info.load_store_multiple.addressing_mode = 3;
931 addressing_mode = "DB";
938 instruction->info.load_store_multiple.addressing_mode = 0;
939 /* "IA" is the default in UAL syntax */
940 addressing_mode = "";
944 instruction->info.load_store_multiple.addressing_mode = 2;
945 addressing_mode = "DA";
949 reg_list_p = reg_list;
950 for (i = 0; i <= 15; i++)
952 if ((register_list >> i) & 1)
957 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i);
961 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i);
966 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i%s, {%s}%s",
967 address, opcode, mnemonic, COND(opcode), addressing_mode,
968 Rn, (W) ? "!" : "", reg_list, (S) ? "^" : "");
973 /* Multiplies, extra load/stores */
974 int evaluate_mul_and_extra_ld_st(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
976 /* Multiply (accumulate) (long) and Swap/swap byte */
977 if ((opcode & 0x000000f0) == 0x00000090)
979 /* Multiply (accumulate) */
980 if ((opcode & 0x0f800000) == 0x00000000)
982 uint8_t Rm, Rs, Rn, Rd, S;
984 Rs = (opcode & 0xf00) >> 8;
985 Rn = (opcode & 0xf000) >> 12;
986 Rd = (opcode & 0xf0000) >> 16;
987 S = (opcode & 0x00100000) >> 20;
989 /* examine A bit (accumulate) */
990 if (opcode & 0x00200000)
992 instruction->type = ARM_MLA;
993 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMLA%s%s r%i, r%i, r%i, r%i",
994 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs, Rn);
998 instruction->type = ARM_MUL;
999 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMUL%s%s r%i, r%i, r%i",
1000 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs);
1006 /* Multiply (accumulate) long */
1007 if ((opcode & 0x0f800000) == 0x00800000)
1009 char* mnemonic = NULL;
1010 uint8_t Rm, Rs, RdHi, RdLow, S;
1012 Rs = (opcode & 0xf00) >> 8;
1013 RdHi = (opcode & 0xf000) >> 12;
1014 RdLow = (opcode & 0xf0000) >> 16;
1015 S = (opcode & 0x00100000) >> 20;
1017 switch ((opcode & 0x00600000) >> 21)
1020 instruction->type = ARM_UMULL;
1024 instruction->type = ARM_UMLAL;
1028 instruction->type = ARM_SMULL;
1032 instruction->type = ARM_SMLAL;
1037 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, r%i, r%i",
1038 address, opcode, mnemonic, COND(opcode), (S) ? "S" : "",
1039 RdLow, RdHi, Rm, Rs);
1044 /* Swap/swap byte */
1045 if ((opcode & 0x0f800000) == 0x01000000)
1049 Rd = (opcode & 0xf000) >> 12;
1050 Rn = (opcode & 0xf0000) >> 16;
1052 /* examine B flag */
1053 instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP;
1055 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, [r%i]",
1056 address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), Rd, Rm, Rn);
1062 return evaluate_misc_load_store(opcode, address, instruction);
1065 int evaluate_mrs_msr(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1067 int R = (opcode & 0x00400000) >> 22;
1068 char *PSR = (R) ? "SPSR" : "CPSR";
1070 /* Move register to status register (MSR) */
1071 if (opcode & 0x00200000)
1073 instruction->type = ARM_MSR;
1075 /* immediate variant */
1076 if (opcode & 0x02000000)
1078 uint8_t immediate = (opcode & 0xff);
1079 uint8_t rotate = (opcode & 0xf00);
1081 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32 ,
1082 address, opcode, COND(opcode), PSR,
1083 (opcode & 0x10000) ? "c" : "",
1084 (opcode & 0x20000) ? "x" : "",
1085 (opcode & 0x40000) ? "s" : "",
1086 (opcode & 0x80000) ? "f" : "",
1087 ror(immediate, (rotate * 2))
1090 else /* register variant */
1092 uint8_t Rm = opcode & 0xf;
1093 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, r%i",
1094 address, opcode, COND(opcode), PSR,
1095 (opcode & 0x10000) ? "c" : "",
1096 (opcode & 0x20000) ? "x" : "",
1097 (opcode & 0x40000) ? "s" : "",
1098 (opcode & 0x80000) ? "f" : "",
1104 else /* Move status register to register (MRS) */
1108 instruction->type = ARM_MRS;
1109 Rd = (opcode & 0x0000f000) >> 12;
1111 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMRS%s r%i, %s",
1112 address, opcode, COND(opcode), Rd, PSR);
1118 /* Miscellaneous instructions */
1119 int evaluate_misc_instr(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1122 if ((opcode & 0x000000f0) == 0x00000000)
1124 evaluate_mrs_msr(opcode, address, instruction);
1128 if ((opcode & 0x006000f0) == 0x00200010)
1131 instruction->type = ARM_BX;
1134 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBX%s r%i",
1135 address, opcode, COND(opcode), Rm);
1137 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1138 instruction->info.b_bl_bx_blx.target_address = -1;
1141 /* BXJ - "Jazelle" support (ARMv5-J) */
1142 if ((opcode & 0x006000f0) == 0x00200020)
1145 instruction->type = ARM_BX;
1148 snprintf(instruction->text, 128,
1149 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBXJ%s r%i",
1150 address, opcode, COND(opcode), Rm);
1152 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1153 instruction->info.b_bl_bx_blx.target_address = -1;
1157 if ((opcode & 0x006000f0) == 0x00600010)
1160 instruction->type = ARM_CLZ;
1162 Rd = (opcode & 0xf000) >> 12;
1164 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLZ%s r%i, r%i",
1165 address, opcode, COND(opcode), Rd, Rm);
1169 if ((opcode & 0x006000f0) == 0x00200030)
1172 instruction->type = ARM_BLX;
1175 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX%s r%i",
1176 address, opcode, COND(opcode), Rm);
1178 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1179 instruction->info.b_bl_bx_blx.target_address = -1;
1182 /* Enhanced DSP add/subtracts */
1183 if ((opcode & 0x0000000f0) == 0x00000050)
1186 char *mnemonic = NULL;
1188 Rd = (opcode & 0xf000) >> 12;
1189 Rn = (opcode & 0xf0000) >> 16;
1191 switch ((opcode & 0x00600000) >> 21)
1194 instruction->type = ARM_QADD;
1198 instruction->type = ARM_QSUB;
1202 instruction->type = ARM_QDADD;
1206 instruction->type = ARM_QDSUB;
1211 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, r%i",
1212 address, opcode, mnemonic, COND(opcode), Rd, Rm, Rn);
1215 /* Software breakpoints */
1216 if ((opcode & 0x0000000f0) == 0x00000070)
1219 instruction->type = ARM_BKPT;
1220 immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf);
1222 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBKPT 0x%4.4" PRIx32 "",
1223 address, opcode, immediate);
1226 /* Enhanced DSP multiplies */
1227 if ((opcode & 0x000000090) == 0x00000080)
1229 int x = (opcode & 0x20) >> 5;
1230 int y = (opcode & 0x40) >> 6;
1233 if ((opcode & 0x00600000) == 0x00000000)
1235 uint8_t Rd, Rm, Rs, Rn;
1236 instruction->type = ARM_SMLAxy;
1237 Rd = (opcode & 0xf0000) >> 16;
1238 Rm = (opcode & 0xf);
1239 Rs = (opcode & 0xf00) >> 8;
1240 Rn = (opcode & 0xf000) >> 12;
1242 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1243 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
1248 if ((opcode & 0x00600000) == 0x00400000)
1250 uint8_t RdLow, RdHi, Rm, Rs;
1251 instruction->type = ARM_SMLAxy;
1252 RdHi = (opcode & 0xf0000) >> 16;
1253 RdLow = (opcode & 0xf000) >> 12;
1254 Rm = (opcode & 0xf);
1255 Rs = (opcode & 0xf00) >> 8;
1257 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1258 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
1259 RdLow, RdHi, Rm, Rs);
1263 if (((opcode & 0x00600000) == 0x00100000) && (x == 0))
1265 uint8_t Rd, Rm, Rs, Rn;
1266 instruction->type = ARM_SMLAWy;
1267 Rd = (opcode & 0xf0000) >> 16;
1268 Rm = (opcode & 0xf);
1269 Rs = (opcode & 0xf00) >> 8;
1270 Rn = (opcode & 0xf000) >> 12;
1272 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLAW%s%s r%i, r%i, r%i, r%i",
1273 address, opcode, (y) ? "T" : "B", COND(opcode),
1278 if ((opcode & 0x00600000) == 0x00300000)
1281 instruction->type = ARM_SMULxy;
1282 Rd = (opcode & 0xf0000) >> 16;
1283 Rm = (opcode & 0xf);
1284 Rs = (opcode & 0xf00) >> 8;
1286 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s%s r%i, r%i, r%i",
1287 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
1292 if (((opcode & 0x00600000) == 0x00100000) && (x == 1))
1295 instruction->type = ARM_SMULWy;
1296 Rd = (opcode & 0xf0000) >> 16;
1297 Rm = (opcode & 0xf);
1298 Rs = (opcode & 0xf00) >> 8;
1300 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s r%i, r%i, r%i",
1301 address, opcode, (y) ? "T" : "B", COND(opcode),
1309 int evaluate_data_proc(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1311 uint8_t I, op, S, Rn, Rd;
1312 char *mnemonic = NULL;
1313 char shifter_operand[32];
1315 I = (opcode & 0x02000000) >> 25;
1316 op = (opcode & 0x01e00000) >> 21;
1317 S = (opcode & 0x00100000) >> 20;
1319 Rd = (opcode & 0xf000) >> 12;
1320 Rn = (opcode & 0xf0000) >> 16;
1322 instruction->info.data_proc.Rd = Rd;
1323 instruction->info.data_proc.Rn = Rn;
1324 instruction->info.data_proc.S = S;
1329 instruction->type = ARM_AND;
1333 instruction->type = ARM_EOR;
1337 instruction->type = ARM_SUB;
1341 instruction->type = ARM_RSB;
1345 instruction->type = ARM_ADD;
1349 instruction->type = ARM_ADC;
1353 instruction->type = ARM_SBC;
1357 instruction->type = ARM_RSC;
1361 instruction->type = ARM_TST;
1365 instruction->type = ARM_TEQ;
1369 instruction->type = ARM_CMP;
1373 instruction->type = ARM_CMN;
1377 instruction->type = ARM_ORR;
1381 instruction->type = ARM_MOV;
1385 instruction->type = ARM_BIC;
1389 instruction->type = ARM_MVN;
1394 if (I) /* immediate shifter operand (#<immediate>)*/
1396 uint8_t immed_8 = opcode & 0xff;
1397 uint8_t rotate_imm = (opcode & 0xf00) >> 8;
1400 immediate = ror(immed_8, rotate_imm * 2);
1402 snprintf(shifter_operand, 32, "#0x%" PRIx32 "", immediate);
1404 instruction->info.data_proc.variant = 0;
1405 instruction->info.data_proc.shifter_operand.immediate.immediate = immediate;
1407 else /* register-based shifter operand */
1410 shift = (opcode & 0x60) >> 5;
1411 Rm = (opcode & 0xf);
1413 if ((opcode & 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1416 shift_imm = (opcode & 0xf80) >> 7;
1418 instruction->info.data_proc.variant = 1;
1419 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1420 instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = shift_imm;
1421 instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift;
1423 /* LSR encodes a shift by 32 bit as 0x0 */
1424 if ((shift == 0x1) && (shift_imm == 0x0))
1427 /* ASR encodes a shift by 32 bit as 0x0 */
1428 if ((shift == 0x2) && (shift_imm == 0x0))
1431 /* ROR by 32 bit is actually a RRX */
1432 if ((shift == 0x3) && (shift_imm == 0x0))
1435 if ((shift_imm == 0x0) && (shift == 0x0))
1437 snprintf(shifter_operand, 32, "r%i", Rm);
1441 if (shift == 0x0) /* LSL */
1443 snprintf(shifter_operand, 32, "r%i, LSL #0x%x", Rm, shift_imm);
1445 else if (shift == 0x1) /* LSR */
1447 snprintf(shifter_operand, 32, "r%i, LSR #0x%x", Rm, shift_imm);
1449 else if (shift == 0x2) /* ASR */
1451 snprintf(shifter_operand, 32, "r%i, ASR #0x%x", Rm, shift_imm);
1453 else if (shift == 0x3) /* ROR */
1455 snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm);
1457 else if (shift == 0x4) /* RRX */
1459 snprintf(shifter_operand, 32, "r%i, RRX", Rm);
1463 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1465 uint8_t Rs = (opcode & 0xf00) >> 8;
1467 instruction->info.data_proc.variant = 2;
1468 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rm;
1469 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rs;
1470 instruction->info.data_proc.shifter_operand.register_shift.shift = shift;
1472 if (shift == 0x0) /* LSL */
1474 snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs);
1476 else if (shift == 0x1) /* LSR */
1478 snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs);
1480 else if (shift == 0x2) /* ASR */
1482 snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs);
1484 else if (shift == 0x3) /* ROR */
1486 snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs);
1491 if ((op < 0x8) || (op == 0xc) || (op == 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1493 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, %s",
1494 address, opcode, mnemonic, COND(opcode),
1495 (S) ? "S" : "", Rd, Rn, shifter_operand);
1497 else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1499 if (opcode == 0xe1a00000) /* print MOV r0,r0 as NOP */
1500 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tNOP",address, opcode);
1502 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, %s",
1503 address, opcode, mnemonic, COND(opcode),
1504 (S) ? "S" : "", Rd, shifter_operand);
1506 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1508 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, %s",
1509 address, opcode, mnemonic, COND(opcode),
1510 Rn, shifter_operand);
1516 int arm_evaluate_opcode(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1518 /* clear fields, to avoid confusion */
1519 memset(instruction, 0, sizeof(arm_instruction_t));
1520 instruction->opcode = opcode;
1521 instruction->instruction_size = 4;
1523 /* catch opcodes with condition field [31:28] = b1111 */
1524 if ((opcode & 0xf0000000) == 0xf0000000)
1526 /* Undefined instruction (or ARMv5E cache preload PLD) */
1527 if ((opcode & 0x08000000) == 0x00000000)
1528 return evaluate_pld(opcode, address, instruction);
1530 /* Undefined instruction */
1531 if ((opcode & 0x0e000000) == 0x08000000)
1533 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1534 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode);
1538 /* Branch and branch with link and change to Thumb */
1539 if ((opcode & 0x0e000000) == 0x0a000000)
1540 return evaluate_blx_imm(opcode, address, instruction);
1542 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1543 /* Coprocessor load/store and double register transfers */
1544 if ((opcode & 0x0e000000) == 0x0c000000)
1545 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1547 /* Coprocessor data processing */
1548 if ((opcode & 0x0f000100) == 0x0c000000)
1549 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1551 /* Coprocessor register transfers */
1552 if ((opcode & 0x0f000010) == 0x0c000010)
1553 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1555 /* Undefined instruction */
1556 if ((opcode & 0x0f000000) == 0x0f000000)
1558 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1559 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode);
1564 /* catch opcodes with [27:25] = b000 */
1565 if ((opcode & 0x0e000000) == 0x00000000)
1567 /* Multiplies, extra load/stores */
1568 if ((opcode & 0x00000090) == 0x00000090)
1569 return evaluate_mul_and_extra_ld_st(opcode, address, instruction);
1571 /* Miscellaneous instructions */
1572 if ((opcode & 0x0f900000) == 0x01000000)
1573 return evaluate_misc_instr(opcode, address, instruction);
1575 return evaluate_data_proc(opcode, address, instruction);
1578 /* catch opcodes with [27:25] = b001 */
1579 if ((opcode & 0x0e000000) == 0x02000000)
1581 /* Undefined instruction */
1582 if ((opcode & 0x0fb00000) == 0x03000000)
1584 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1585 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode);
1589 /* Move immediate to status register */
1590 if ((opcode & 0x0fb00000) == 0x03200000)
1591 return evaluate_mrs_msr(opcode, address, instruction);
1593 return evaluate_data_proc(opcode, address, instruction);
1597 /* catch opcodes with [27:25] = b010 */
1598 if ((opcode & 0x0e000000) == 0x04000000)
1600 /* Load/store immediate offset */
1601 return evaluate_load_store(opcode, address, instruction);
1604 /* catch opcodes with [27:25] = b011 */
1605 if ((opcode & 0x0e000000) == 0x06000000)
1607 /* Load/store register offset */
1608 if ((opcode & 0x00000010) == 0x00000000)
1609 return evaluate_load_store(opcode, address, instruction);
1611 /* Architecturally Undefined instruction
1612 * ... don't expect these to ever be used
1614 if ((opcode & 0x07f000f0) == 0x07f000f0)
1616 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1617 snprintf(instruction->text, 128,
1618 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEF",
1623 /* "media" instructions */
1624 return evaluate_media(opcode, address, instruction);
1627 /* catch opcodes with [27:25] = b100 */
1628 if ((opcode & 0x0e000000) == 0x08000000)
1630 /* Load/store multiple */
1631 return evaluate_ldm_stm(opcode, address, instruction);
1634 /* catch opcodes with [27:25] = b101 */
1635 if ((opcode & 0x0e000000) == 0x0a000000)
1637 /* Branch and branch with link */
1638 return evaluate_b_bl(opcode, address, instruction);
1641 /* catch opcodes with [27:25] = b110 */
1642 if ((opcode & 0x0e000000) == 0x0a000000)
1644 /* Coprocessor load/store and double register transfers */
1645 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1648 /* catch opcodes with [27:25] = b111 */
1649 if ((opcode & 0x0e000000) == 0x0e000000)
1651 /* Software interrupt */
1652 if ((opcode & 0x0f000000) == 0x0f000000)
1653 return evaluate_swi(opcode, address, instruction);
1655 /* Coprocessor data processing */
1656 if ((opcode & 0x0f000010) == 0x0e000000)
1657 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1659 /* Coprocessor register transfers */
1660 if ((opcode & 0x0f000010) == 0x0e000010)
1661 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1664 LOG_ERROR("should never reach this point");
1668 int evaluate_b_bl_blx_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1670 uint32_t offset = opcode & 0x7ff;
1671 uint32_t opc = (opcode >> 11) & 0x3;
1672 uint32_t target_address;
1673 char *mnemonic = NULL;
1675 /* sign extend 11-bit offset */
1676 if (((opc == 0) || (opc == 2)) && (offset & 0x00000400))
1677 offset = 0xfffff800 | offset;
1679 target_address = address + 4 + (offset << 1);
1683 /* unconditional branch */
1685 instruction->type = ARM_B;
1690 instruction->type = ARM_BLX;
1695 instruction->type = ARM_UNKNOWN_INSTUCTION;
1696 mnemonic = "prefix";
1697 target_address = offset << 12;
1701 instruction->type = ARM_BL;
1706 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1707 * these are effectively 32-bit instructions even in Thumb1.
1708 * Might be simplest to always use the Thumb2 decoder.
1711 snprintf(instruction->text, 128,
1712 "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%#8.8" PRIx32,
1713 address, opcode, mnemonic, target_address);
1715 instruction->info.b_bl_bx_blx.reg_operand = -1;
1716 instruction->info.b_bl_bx_blx.target_address = target_address;
1721 int evaluate_add_sub_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1723 uint8_t Rd = (opcode >> 0) & 0x7;
1724 uint8_t Rn = (opcode >> 3) & 0x7;
1725 uint8_t Rm_imm = (opcode >> 6) & 0x7;
1726 uint32_t opc = opcode & (1 << 9);
1727 uint32_t reg_imm = opcode & (1 << 10);
1732 instruction->type = ARM_SUB;
1737 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1738 instruction->type = ARM_ADD;
1742 instruction->info.data_proc.Rd = Rd;
1743 instruction->info.data_proc.Rn = Rn;
1744 instruction->info.data_proc.S = 1;
1748 instruction->info.data_proc.variant = 0; /*immediate*/
1749 instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm;
1750 snprintf(instruction->text, 128,
1751 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%d",
1752 address, opcode, mnemonic, Rd, Rn, Rm_imm);
1756 instruction->info.data_proc.variant = 1; /*immediate shift*/
1757 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm;
1758 snprintf(instruction->text, 128,
1759 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, r%i",
1760 address, opcode, mnemonic, Rd, Rn, Rm_imm);
1766 int evaluate_shift_imm_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1768 uint8_t Rd = (opcode >> 0) & 0x7;
1769 uint8_t Rm = (opcode >> 3) & 0x7;
1770 uint8_t imm = (opcode >> 6) & 0x1f;
1771 uint8_t opc = (opcode >> 11) & 0x3;
1772 char *mnemonic = NULL;
1777 instruction->type = ARM_MOV;
1779 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0;
1782 instruction->type = ARM_MOV;
1784 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1;
1787 instruction->type = ARM_MOV;
1789 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2;
1793 if ((imm == 0) && (opc != 0))
1796 instruction->info.data_proc.Rd = Rd;
1797 instruction->info.data_proc.Rn = -1;
1798 instruction->info.data_proc.S = 1;
1800 instruction->info.data_proc.variant = 1; /*immediate_shift*/
1801 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1802 instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm;
1804 snprintf(instruction->text, 128,
1805 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1806 address, opcode, mnemonic, Rd, Rm, imm);
1811 int evaluate_data_proc_imm_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1813 uint8_t imm = opcode & 0xff;
1814 uint8_t Rd = (opcode >> 8) & 0x7;
1815 uint32_t opc = (opcode >> 11) & 0x3;
1816 char *mnemonic = NULL;
1818 instruction->info.data_proc.Rd = Rd;
1819 instruction->info.data_proc.Rn = Rd;
1820 instruction->info.data_proc.S = 1;
1821 instruction->info.data_proc.variant = 0; /*immediate*/
1822 instruction->info.data_proc.shifter_operand.immediate.immediate = imm;
1827 instruction->type = ARM_MOV;
1829 instruction->info.data_proc.Rn = -1;
1832 instruction->type = ARM_CMP;
1834 instruction->info.data_proc.Rd = -1;
1837 instruction->type = ARM_ADD;
1841 instruction->type = ARM_SUB;
1846 snprintf(instruction->text, 128,
1847 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, #%#2.2x",
1848 address, opcode, mnemonic, Rd, imm);
1853 int evaluate_data_proc_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1855 uint8_t high_reg, op, Rm, Rd,H1,H2;
1856 char *mnemonic = NULL;
1859 high_reg = (opcode & 0x0400) >> 10;
1860 op = (opcode & 0x03C0) >> 6;
1862 Rd = (opcode & 0x0007);
1863 Rm = (opcode & 0x0038) >> 3;
1864 H1 = (opcode & 0x0080) >> 7;
1865 H2 = (opcode & 0x0040) >> 6;
1867 instruction->info.data_proc.Rd = Rd;
1868 instruction->info.data_proc.Rn = Rd;
1869 instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP));
1870 instruction->info.data_proc.variant = 1 /*immediate shift*/;
1871 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1882 instruction->type = ARM_ADD;
1886 instruction->type = ARM_CMP;
1890 instruction->type = ARM_MOV;
1896 if ((opcode & 0x7) == 0x0)
1898 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1901 instruction->type = ARM_BLX;
1902 snprintf(instruction->text, 128,
1904 " 0x%4.4x \tBLX\tr%i",
1905 address, opcode, Rm);
1909 instruction->type = ARM_BX;
1910 snprintf(instruction->text, 128,
1912 " 0x%4.4x \tBX\tr%i",
1913 address, opcode, Rm);
1918 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1919 snprintf(instruction->text, 128,
1922 "UNDEFINED INSTRUCTION",
1934 instruction->type = ARM_AND;
1938 instruction->type = ARM_EOR;
1942 instruction->type = ARM_MOV;
1944 instruction->info.data_proc.variant = 2 /*register shift*/;
1945 instruction->info.data_proc.shifter_operand.register_shift.shift = 0;
1946 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1947 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1950 instruction->type = ARM_MOV;
1952 instruction->info.data_proc.variant = 2 /*register shift*/;
1953 instruction->info.data_proc.shifter_operand.register_shift.shift = 1;
1954 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1955 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1958 instruction->type = ARM_MOV;
1960 instruction->info.data_proc.variant = 2 /*register shift*/;
1961 instruction->info.data_proc.shifter_operand.register_shift.shift = 2;
1962 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1963 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1966 instruction->type = ARM_ADC;
1970 instruction->type = ARM_SBC;
1974 instruction->type = ARM_MOV;
1976 instruction->info.data_proc.variant = 2 /*register shift*/;
1977 instruction->info.data_proc.shifter_operand.register_shift.shift = 3;
1978 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1979 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1982 instruction->type = ARM_TST;
1986 instruction->type = ARM_RSB;
1988 instruction->info.data_proc.variant = 0 /*immediate*/;
1989 instruction->info.data_proc.shifter_operand.immediate.immediate = 0;
1990 instruction->info.data_proc.Rn = Rm;
1993 instruction->type = ARM_CMP;
1997 instruction->type = ARM_CMN;
2001 instruction->type = ARM_ORR;
2005 instruction->type = ARM_MUL;
2009 instruction->type = ARM_BIC;
2013 instruction->type = ARM_MVN;
2020 snprintf(instruction->text, 128,
2021 "0x%8.8" PRIx32 " 0x%4.4x \tNOP\t\t\t"
2023 address, opcode, mnemonic, Rd, Rm);
2025 snprintf(instruction->text, 128,
2026 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i",
2027 address, opcode, mnemonic, Rd, Rm);
2032 /* PC-relative data addressing is word-aligned even with Thumb */
2033 static inline uint32_t thumb_alignpc4(uint32_t addr)
2035 return (addr + 4) & ~3;
2038 int evaluate_load_literal_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2041 uint8_t Rd = (opcode >> 8) & 0x7;
2043 instruction->type = ARM_LDR;
2044 immediate = opcode & 0x000000ff;
2047 instruction->info.load_store.Rd = Rd;
2048 instruction->info.load_store.Rn = 15 /*PC*/;
2049 instruction->info.load_store.index_mode = 0; /*offset*/
2050 instruction->info.load_store.offset_mode = 0; /*immediate*/
2051 instruction->info.load_store.offset.offset = immediate;
2053 snprintf(instruction->text, 128,
2054 "0x%8.8" PRIx32 " 0x%4.4x \t"
2055 "LDR\tr%i, [pc, #%#" PRIx32 "]\t; %#8.8" PRIx32,
2056 address, opcode, Rd, immediate,
2057 thumb_alignpc4(address) + immediate);
2062 int evaluate_load_store_reg_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2064 uint8_t Rd = (opcode >> 0) & 0x7;
2065 uint8_t Rn = (opcode >> 3) & 0x7;
2066 uint8_t Rm = (opcode >> 6) & 0x7;
2067 uint8_t opc = (opcode >> 9) & 0x7;
2068 char *mnemonic = NULL;
2073 instruction->type = ARM_STR;
2077 instruction->type = ARM_STRH;
2081 instruction->type = ARM_STRB;
2085 instruction->type = ARM_LDRSB;
2089 instruction->type = ARM_LDR;
2093 instruction->type = ARM_LDRH;
2097 instruction->type = ARM_LDRB;
2101 instruction->type = ARM_LDRSH;
2106 snprintf(instruction->text, 128,
2107 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2108 address, opcode, mnemonic, Rd, Rn, Rm);
2110 instruction->info.load_store.Rd = Rd;
2111 instruction->info.load_store.Rn = Rn;
2112 instruction->info.load_store.index_mode = 0; /*offset*/
2113 instruction->info.load_store.offset_mode = 1; /*register*/
2114 instruction->info.load_store.offset.reg.Rm = Rm;
2119 int evaluate_load_store_imm_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2121 uint32_t offset = (opcode >> 6) & 0x1f;
2122 uint8_t Rd = (opcode >> 0) & 0x7;
2123 uint8_t Rn = (opcode >> 3) & 0x7;
2124 uint32_t L = opcode & (1 << 11);
2125 uint32_t B = opcode & (1 << 12);
2132 instruction->type = ARM_LDR;
2137 instruction->type = ARM_STR;
2141 if ((opcode&0xF000) == 0x8000)
2152 snprintf(instruction->text, 128,
2153 "0x%8.8" PRIx32 " 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32 "]",
2154 address, opcode, mnemonic, suffix, Rd, Rn, offset << shift);
2156 instruction->info.load_store.Rd = Rd;
2157 instruction->info.load_store.Rn = Rn;
2158 instruction->info.load_store.index_mode = 0; /*offset*/
2159 instruction->info.load_store.offset_mode = 0; /*immediate*/
2160 instruction->info.load_store.offset.offset = offset << shift;
2165 int evaluate_load_store_stack_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2167 uint32_t offset = opcode & 0xff;
2168 uint8_t Rd = (opcode >> 8) & 0x7;
2169 uint32_t L = opcode & (1 << 11);
2174 instruction->type = ARM_LDR;
2179 instruction->type = ARM_STR;
2183 snprintf(instruction->text, 128,
2184 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32 "]",
2185 address, opcode, mnemonic, Rd, offset*4);
2187 instruction->info.load_store.Rd = Rd;
2188 instruction->info.load_store.Rn = 13 /*SP*/;
2189 instruction->info.load_store.index_mode = 0; /*offset*/
2190 instruction->info.load_store.offset_mode = 0; /*immediate*/
2191 instruction->info.load_store.offset.offset = offset*4;
2196 int evaluate_add_sp_pc_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2198 uint32_t imm = opcode & 0xff;
2199 uint8_t Rd = (opcode >> 8) & 0x7;
2201 uint32_t SP = opcode & (1 << 11);
2204 instruction->type = ARM_ADD;
2217 snprintf(instruction->text, 128,
2218 "0x%8.8" PRIx32 " 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32,
2219 address, opcode, Rd, reg_name, imm * 4);
2221 instruction->info.data_proc.variant = 0 /* immediate */;
2222 instruction->info.data_proc.Rd = Rd;
2223 instruction->info.data_proc.Rn = Rn;
2224 instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
2229 int evaluate_adjust_stack_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2231 uint32_t imm = opcode & 0x7f;
2232 uint8_t opc = opcode & (1 << 7);
2238 instruction->type = ARM_SUB;
2243 instruction->type = ARM_ADD;
2247 snprintf(instruction->text, 128,
2248 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tSP, #%#" PRIx32,
2249 address, opcode, mnemonic, imm*4);
2251 instruction->info.data_proc.variant = 0 /* immediate */;
2252 instruction->info.data_proc.Rd = 13 /*SP*/;
2253 instruction->info.data_proc.Rn = 13 /*SP*/;
2254 instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
2259 int evaluate_breakpoint_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2261 uint32_t imm = opcode & 0xff;
2263 instruction->type = ARM_BKPT;
2265 snprintf(instruction->text, 128,
2266 "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32 "",
2267 address, opcode, imm);
2272 int evaluate_load_store_multiple_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2274 uint32_t reg_list = opcode & 0xff;
2275 uint32_t L = opcode & (1 << 11);
2276 uint32_t R = opcode & (1 << 8);
2277 uint8_t Rn = (opcode >> 8) & 7;
2278 uint8_t addr_mode = 0 /* IA */;
2282 char ptr_name[7] = "";
2285 if ((opcode & 0xf000) == 0xc000)
2286 { /* generic load/store multiple */
2291 instruction->type = ARM_LDM;
2293 if (opcode & (1 << Rn))
2298 instruction->type = ARM_STM;
2301 snprintf(ptr_name, sizeof ptr_name, "r%i%s, ", Rn, wback);
2308 instruction->type = ARM_LDM;
2311 reg_list |= (1 << 15) /*PC*/;
2315 instruction->type = ARM_STM;
2317 addr_mode = 3; /*DB*/
2319 reg_list |= (1 << 14) /*LR*/;
2323 reg_names_p = reg_names;
2324 for (i = 0; i <= 15; i++)
2326 if (reg_list & (1 << i))
2327 reg_names_p += snprintf(reg_names_p, (reg_names + 40 - reg_names_p), "r%i, ", i);
2329 if (reg_names_p > reg_names)
2330 reg_names_p[-2] = '\0';
2331 else /* invalid op : no registers */
2332 reg_names[0] = '\0';
2334 snprintf(instruction->text, 128,
2335 "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%s{%s}",
2336 address, opcode, mnemonic, ptr_name, reg_names);
2338 instruction->info.load_store_multiple.register_list = reg_list;
2339 instruction->info.load_store_multiple.Rn = Rn;
2340 instruction->info.load_store_multiple.addressing_mode = addr_mode;
2345 int evaluate_cond_branch_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2347 uint32_t offset = opcode & 0xff;
2348 uint8_t cond = (opcode >> 8) & 0xf;
2349 uint32_t target_address;
2353 instruction->type = ARM_SWI;
2354 snprintf(instruction->text, 128,
2355 "0x%8.8" PRIx32 " 0x%4.4x \tSVC\t%#2.2" PRIx32,
2356 address, opcode, offset);
2359 else if (cond == 0xe)
2361 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2362 snprintf(instruction->text, 128,
2363 "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION",
2368 /* sign extend 8-bit offset */
2369 if (offset & 0x00000080)
2370 offset = 0xffffff00 | offset;
2372 target_address = address + 4 + (offset << 1);
2374 snprintf(instruction->text, 128,
2375 "0x%8.8" PRIx32 " 0x%4.4x \tB%s\t%#8.8" PRIx32,
2377 arm_condition_strings[cond], target_address);
2379 instruction->type = ARM_B;
2380 instruction->info.b_bl_bx_blx.reg_operand = -1;
2381 instruction->info.b_bl_bx_blx.target_address = target_address;
2386 static int evaluate_cb_thumb(uint16_t opcode, uint32_t address,
2387 arm_instruction_t *instruction)
2391 /* added in Thumb2 */
2392 offset = (opcode >> 3) & 0x1f;
2393 offset |= (opcode & 0x0200) >> 4;
2395 snprintf(instruction->text, 128,
2396 "0x%8.8" PRIx32 " 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32,
2398 (opcode & 0x0800) ? "N" : "",
2399 opcode & 0x7, address + 4 + (offset << 1));
2404 static int evaluate_extend_thumb(uint16_t opcode, uint32_t address,
2405 arm_instruction_t *instruction)
2407 /* added in ARMv6 */
2408 snprintf(instruction->text, 128,
2409 "0x%8.8" PRIx32 " 0x%4.4x \t%cXT%c\tr%d, r%d",
2411 (opcode & 0x0080) ? 'U' : 'S',
2412 (opcode & 0x0040) ? 'B' : 'H',
2413 opcode & 0x7, (opcode >> 3) & 0x7);
2418 static int evaluate_cps_thumb(uint16_t opcode, uint32_t address,
2419 arm_instruction_t *instruction)
2421 /* added in ARMv6 */
2422 if ((opcode & 0x0ff0) == 0x0650)
2423 snprintf(instruction->text, 128,
2424 "0x%8.8" PRIx32 " 0x%4.4x \tSETEND %s",
2426 (opcode & 0x80) ? "BE" : "LE");
2427 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2428 snprintf(instruction->text, 128,
2429 "0x%8.8" PRIx32 " 0x%4.4x \tCPSI%c\t%s%s%s",
2431 (opcode & 0x0010) ? 'D' : 'E',
2432 (opcode & 0x0004) ? "A" : "",
2433 (opcode & 0x0002) ? "I" : "",
2434 (opcode & 0x0001) ? "F" : "");
2439 static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address,
2440 arm_instruction_t *instruction)
2444 /* added in ARMv6 */
2445 switch ((opcode >> 6) & 3) {
2456 snprintf(instruction->text, 128,
2457 "0x%8.8" PRIx32 " 0x%4.4x \tREV%s\tr%d, r%d",
2458 address, opcode, suffix,
2459 opcode & 0x7, (opcode >> 3) & 0x7);
2464 static int evaluate_hint_thumb(uint16_t opcode, uint32_t address,
2465 arm_instruction_t *instruction)
2469 switch ((opcode >> 4) & 0x0f) {
2486 hint = "HINT (UNRECOGNIZED)";
2490 snprintf(instruction->text, 128,
2491 "0x%8.8" PRIx32 " 0x%4.4x \t%s",
2492 address, opcode, hint);
2497 static int evaluate_ifthen_thumb(uint16_t opcode, uint32_t address,
2498 arm_instruction_t *instruction)
2500 unsigned cond = (opcode >> 4) & 0x0f;
2501 char *x = "", *y = "", *z = "";
2504 z = (opcode & 0x02) ? "T" : "E";
2506 y = (opcode & 0x04) ? "T" : "E";
2508 x = (opcode & 0x08) ? "T" : "E";
2510 snprintf(instruction->text, 128,
2511 "0x%8.8" PRIx32 " 0x%4.4x \tIT%s%s%s\t%s",
2513 x, y, z, arm_condition_strings[cond]);
2515 /* NOTE: strictly speaking, the next 1-4 instructions should
2516 * now be displayed with the relevant conditional suffix...
2522 int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2524 /* clear fields, to avoid confusion */
2525 memset(instruction, 0, sizeof(arm_instruction_t));
2526 instruction->opcode = opcode;
2527 instruction->instruction_size = 2;
2529 if ((opcode & 0xe000) == 0x0000)
2531 /* add/substract register or immediate */
2532 if ((opcode & 0x1800) == 0x1800)
2533 return evaluate_add_sub_thumb(opcode, address, instruction);
2534 /* shift by immediate */
2536 return evaluate_shift_imm_thumb(opcode, address, instruction);
2539 /* Add/substract/compare/move immediate */
2540 if ((opcode & 0xe000) == 0x2000)
2542 return evaluate_data_proc_imm_thumb(opcode, address, instruction);
2545 /* Data processing instructions */
2546 if ((opcode & 0xf800) == 0x4000)
2548 return evaluate_data_proc_thumb(opcode, address, instruction);
2551 /* Load from literal pool */
2552 if ((opcode & 0xf800) == 0x4800)
2554 return evaluate_load_literal_thumb(opcode, address, instruction);
2557 /* Load/Store register offset */
2558 if ((opcode & 0xf000) == 0x5000)
2560 return evaluate_load_store_reg_thumb(opcode, address, instruction);
2563 /* Load/Store immediate offset */
2564 if (((opcode & 0xe000) == 0x6000)
2565 ||((opcode & 0xf000) == 0x8000))
2567 return evaluate_load_store_imm_thumb(opcode, address, instruction);
2570 /* Load/Store from/to stack */
2571 if ((opcode & 0xf000) == 0x9000)
2573 return evaluate_load_store_stack_thumb(opcode, address, instruction);
2577 if ((opcode & 0xf000) == 0xa000)
2579 return evaluate_add_sp_pc_thumb(opcode, address, instruction);
2583 if ((opcode & 0xf000) == 0xb000)
2585 switch ((opcode >> 8) & 0x0f) {
2587 return evaluate_adjust_stack_thumb(opcode, address, instruction);
2592 return evaluate_cb_thumb(opcode, address, instruction);
2594 return evaluate_extend_thumb(opcode, address, instruction);
2599 return evaluate_load_store_multiple_thumb(opcode, address,
2602 return evaluate_cps_thumb(opcode, address, instruction);
2604 if ((opcode & 0x00c0) == 0x0080)
2606 return evaluate_byterev_thumb(opcode, address, instruction);
2608 return evaluate_breakpoint_thumb(opcode, address, instruction);
2610 if (opcode & 0x000f)
2611 return evaluate_ifthen_thumb(opcode, address,
2614 return evaluate_hint_thumb(opcode, address,
2618 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2619 snprintf(instruction->text, 128,
2620 "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION",
2625 /* Load/Store multiple */
2626 if ((opcode & 0xf000) == 0xc000)
2628 return evaluate_load_store_multiple_thumb(opcode, address, instruction);
2631 /* Conditional branch + SWI */
2632 if ((opcode & 0xf000) == 0xd000)
2634 return evaluate_cond_branch_thumb(opcode, address, instruction);
2637 if ((opcode & 0xe000) == 0xe000)
2639 /* Undefined instructions */
2640 if ((opcode & 0xf801) == 0xe801)
2642 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2643 snprintf(instruction->text, 128,
2644 "0x%8.8" PRIx32 " 0x%8.8x\t"
2645 "UNDEFINED INSTRUCTION",
2650 { /* Branch to offset */
2651 return evaluate_b_bl_blx_thumb(opcode, address, instruction);
2655 LOG_ERROR("should never reach this point (opcode=%04x)",opcode);
2659 static int t2ev_b_bl(uint32_t opcode, uint32_t address,
2660 arm_instruction_t *instruction, char *cp)
2663 unsigned b21 = 1 << 21;
2664 unsigned b22 = 1 << 22;
2666 /* instead of combining two smaller 16-bit branch instructions,
2667 * Thumb2 uses only one larger 32-bit instruction.
2669 offset = opcode & 0x7ff;
2670 offset |= (opcode & 0x03ff0000) >> 5;
2671 if (opcode & (1 << 26)) {
2672 offset |= 0xff << 23;
2673 if ((opcode & (1 << 11)) == 0)
2675 if ((opcode & (1 << 13)) == 0)
2678 if (opcode & (1 << 11))
2680 if (opcode & (1 << 13))
2688 address += offset << 1;
2690 instruction->type = (opcode & (1 << 14)) ? ARM_BL : ARM_B;
2691 instruction->info.b_bl_bx_blx.reg_operand = -1;
2692 instruction->info.b_bl_bx_blx.target_address = address;
2693 sprintf(cp, "%s\t%#8.8" PRIx32,
2694 (opcode & (1 << 14)) ? "BL" : "B.W",
2700 static int t2ev_cond_b(uint32_t opcode, uint32_t address,
2701 arm_instruction_t *instruction, char *cp)
2704 unsigned b17 = 1 << 17;
2705 unsigned b18 = 1 << 18;
2706 unsigned cond = (opcode >> 22) & 0x0f;
2708 offset = opcode & 0x7ff;
2709 offset |= (opcode & 0x003f0000) >> 5;
2710 if (opcode & (1 << 26)) {
2711 offset |= 0xffff << 19;
2712 if ((opcode & (1 << 11)) == 0)
2714 if ((opcode & (1 << 13)) == 0)
2717 if (opcode & (1 << 11))
2719 if (opcode & (1 << 13))
2726 address += offset << 1;
2728 instruction->type = ARM_B;
2729 instruction->info.b_bl_bx_blx.reg_operand = -1;
2730 instruction->info.b_bl_bx_blx.target_address = address;
2731 sprintf(cp, "B%s.W\t%#8.8" PRIx32,
2732 arm_condition_strings[cond],
2738 static const char *special_name(int number)
2740 char *special = "(RESERVED)";
2771 special = "primask";
2774 special = "basepri";
2777 special = "basepri_max";
2780 special = "faultmask";
2783 special = "control";
2789 static int t2ev_hint(uint32_t opcode, uint32_t address,
2790 arm_instruction_t *instruction, char *cp)
2792 const char *mnemonic;
2794 if (opcode & 0x0700) {
2795 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2796 strcpy(cp, "UNDEFINED");
2800 if (opcode & 0x00f0) {
2801 sprintf(cp, "DBG\t#%d", (int) opcode & 0xf);
2805 switch (opcode & 0x0f) {
2810 mnemonic = "YIELD.W";
2822 mnemonic = "HINT.W (UNRECOGNIZED)";
2825 strcpy(cp, mnemonic);
2829 static int t2ev_misc(uint32_t opcode, uint32_t address,
2830 arm_instruction_t *instruction, char *cp)
2832 const char *mnemonic;
2834 switch ((opcode >> 4) & 0x0f) {
2848 return ERROR_INVALID_ARGUMENTS;
2850 strcpy(cp, mnemonic);
2854 static int t2ev_b_misc(uint32_t opcode, uint32_t address,
2855 arm_instruction_t *instruction, char *cp)
2857 /* permanently undefined */
2858 if ((opcode & 0x07f07000) == 0x07f02000) {
2859 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2860 strcpy(cp, "UNDEFINED");
2864 switch ((opcode >> 12) & 0x5) {
2867 return t2ev_b_bl(opcode, address, instruction, cp);
2871 if (((opcode >> 23) & 0x07) != 0x07)
2872 return t2ev_cond_b(opcode, address, instruction, cp);
2873 if (opcode & (1 << 26))
2878 switch ((opcode >> 20) & 0x7f) {
2881 sprintf(cp, "MSR\t%s, r%d", special_name(opcode & 0xff),
2882 (int) (opcode >> 16) & 0x0f);
2885 return t2ev_hint(opcode, address, instruction, cp);
2887 return t2ev_misc(opcode, address, instruction, cp);
2890 sprintf(cp, "MRS\tr%d, %s", (int) (opcode >> 8) & 0x0f,
2891 special_name(opcode & 0xff));
2896 return ERROR_INVALID_ARGUMENTS;
2899 static int t2ev_data_mod_immed(uint32_t opcode, uint32_t address,
2900 arm_instruction_t *instruction, char *cp)
2902 char *mnemonic = NULL;
2903 int rn = (opcode >> 16) & 0xf;
2904 int rd = (opcode >> 8) & 0xf;
2905 unsigned immed = opcode & 0xff;
2911 /* ARMv7-M: A5.3.2 Modified immediate constants */
2912 func = (opcode >> 11) & 0x0e;
2915 if (opcode & (1 << 26))
2918 /* "Modified" immediates */
2919 switch (func >> 1) {
2926 immed += immed << 16;
2929 immed += immed << 8;
2930 immed += immed << 16;
2934 immed = ror(immed, func);
2937 if (opcode & (1 << 20))
2940 switch ((opcode >> 21) & 0xf) {
2943 instruction->type = ARM_TST;
2949 instruction->type = ARM_AND;
2954 instruction->type = ARM_BIC;
2959 instruction->type = ARM_MOV;
2964 instruction->type = ARM_ORR;
2970 instruction->type = ARM_MVN;
2974 // instruction->type = ARM_ORN;
2980 instruction->type = ARM_TEQ;
2986 instruction->type = ARM_EOR;
2992 instruction->type = ARM_CMN;
2998 instruction->type = ARM_ADD;
3004 instruction->type = ARM_ADC;
3009 instruction->type = ARM_SBC;
3014 instruction->type = ARM_CMP;
3020 instruction->type = ARM_SUB;
3026 instruction->type = ARM_RSB;
3031 return ERROR_INVALID_ARGUMENTS;
3035 sprintf(cp, "%s%s\tr%d, #%d\t; %#8.8x",
3036 mnemonic, suffix2 ,rd, immed, immed);
3038 sprintf(cp, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3039 mnemonic, suffix, suffix2,
3040 rd, rn, immed, immed);
3045 static int t2ev_data_immed(uint32_t opcode, uint32_t address,
3046 arm_instruction_t *instruction, char *cp)
3048 char *mnemonic = NULL;
3049 int rn = (opcode >> 16) & 0xf;
3050 int rd = (opcode >> 8) & 0xf;
3053 bool is_signed = false;
3055 immed = (opcode & 0x0ff) | ((opcode & 0x7000) >> 4);
3056 if (opcode & (1 << 26))
3059 switch ((opcode >> 20) & 0x1f) {
3068 immed |= (opcode >> 4) & 0xf000;
3069 sprintf(cp, "MOVW\tr%d, #%d\t; %#3.3x", rd, immed, immed);
3077 /* move constant to top 16 bits of register */
3078 immed |= (opcode >> 4) & 0xf000;
3079 sprintf(cp, "MOVT\tr%d, #%d\t; %#4.4x", rn, immed, immed);
3086 /* signed/unsigned saturated add */
3087 immed = (opcode >> 6) & 0x03;
3088 immed |= (opcode >> 10) & 0x1c;
3089 sprintf(cp, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3090 is_signed ? "S" : "U",
3091 rd, (int) (opcode & 0x1f) + is_signed, rn,
3092 (opcode & (1 << 21)) ? "ASR" : "LSL",
3093 immed ? immed : 32);
3099 /* signed/unsigned bitfield extract */
3100 immed = (opcode >> 6) & 0x03;
3101 immed |= (opcode >> 10) & 0x1c;
3102 sprintf(cp, "%sBFX\tr%d, r%d, #%d, #%d\t",
3103 is_signed ? "S" : "U",
3105 (int) (opcode & 0x1f) + 1);
3108 immed = (opcode >> 6) & 0x03;
3109 immed |= (opcode >> 10) & 0x1c;
3110 if (rn == 0xf) /* bitfield clear */
3111 sprintf(cp, "BFC\tr%d, #%d, #%d\t",
3113 (int) (opcode & 0x1f) + 1 - immed);
3114 else /* bitfield insert */
3115 sprintf(cp, "BFI\tr%d, r%d, #%d, #%d\t",
3117 (int) (opcode & 0x1f) + 1 - immed);
3120 return ERROR_INVALID_ARGUMENTS;
3123 sprintf(cp, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic,
3124 rd, rn, immed, immed);
3128 address = thumb_alignpc4(address);
3133 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3134 * not hiding the pc-relative stuff will sometimes be useful.
3136 sprintf(cp, "ADR.W\tr%d, %#8.8" PRIx32, rd, address);
3140 static int t2ev_store_single(uint32_t opcode, uint32_t address,
3141 arm_instruction_t *instruction, char *cp)
3143 unsigned op = (opcode >> 20) & 0xf;
3149 unsigned rn = (opcode >> 16) & 0x0f;
3150 unsigned rt = (opcode >> 12) & 0x0f;
3153 return ERROR_INVALID_ARGUMENTS;
3155 if (opcode & 0x0800)
3190 return ERROR_INVALID_ARGUMENTS;
3193 sprintf(cp, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3194 size, rt, rn, (int) opcode & 0x0f,
3195 (int) (opcode >> 4) & 0x03);
3199 immed = opcode & 0x0fff;
3200 sprintf(cp, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3201 size, rt, rn, immed, immed);
3205 immed = opcode & 0x00ff;
3207 switch (opcode & 0x700) {
3213 return ERROR_INVALID_ARGUMENTS;
3216 /* two indexed modes will write back rn */
3217 if (opcode & 0x100) {
3218 if (opcode & 0x400) /* pre-indexed */
3220 else { /* post-indexed */
3226 sprintf(cp, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3227 size, suffix, rt, rn, p1,
3228 (opcode & 0x200) ? "" : "-",
3233 static int t2ev_mul32(uint32_t opcode, uint32_t address,
3234 arm_instruction_t *instruction, char *cp)
3236 int ra = (opcode >> 12) & 0xf;
3238 switch (opcode & 0x007000f0) {
3241 sprintf(cp, "MUL\tr%d, r%d, r%d",
3242 (int) (opcode >> 8) & 0xf,
3243 (int) (opcode >> 16) & 0xf,
3244 (int) (opcode >> 0) & 0xf);
3246 sprintf(cp, "MLA\tr%d, r%d, r%d, r%d",
3247 (int) (opcode >> 8) & 0xf,
3248 (int) (opcode >> 16) & 0xf,
3249 (int) (opcode >> 0) & 0xf, ra);
3252 sprintf(cp, "MLS\tr%d, r%d, r%d, r%d",
3253 (int) (opcode >> 8) & 0xf,
3254 (int) (opcode >> 16) & 0xf,
3255 (int) (opcode >> 0) & 0xf, ra);
3258 return ERROR_INVALID_ARGUMENTS;
3263 static int t2ev_mul64_div(uint32_t opcode, uint32_t address,
3264 arm_instruction_t *instruction, char *cp)
3266 int op = (opcode >> 4) & 0xf;
3267 char *infix = "MUL";
3269 op += (opcode >> 16) & 0x70;
3277 sprintf(cp, "%c%sL\tr%d, r%d, r%d, r%d",
3278 (op & 0x20) ? 'U' : 'S',
3280 (int) (opcode >> 12) & 0xf,
3281 (int) (opcode >> 8) & 0xf,
3282 (int) (opcode >> 16) & 0xf,
3283 (int) (opcode >> 0) & 0xf);
3287 sprintf(cp, "%cDIV\tr%d, r%d, r%d",
3288 (op & 0x20) ? 'U' : 'S',
3289 (int) (opcode >> 8) & 0xf,
3290 (int) (opcode >> 16) & 0xf,
3291 (int) (opcode >> 0) & 0xf);
3294 return ERROR_INVALID_ARGUMENTS;
3300 static int t2ev_ldm_stm(uint32_t opcode, uint32_t address,
3301 arm_instruction_t *instruction, char *cp)
3303 int rn = (opcode >> 16) & 0xf;
3304 int op = (opcode >> 22) & 0x6;
3305 int t = (opcode >> 21) & 1;
3306 unsigned registers = opcode & 0xffff;
3308 if (opcode & (1 << 20))
3313 sprintf(cp, "STM.W\tr%d%s, ", rn, t ? "!" : "");
3317 sprintf(cp, "POP.W\t");
3319 sprintf(cp, "LDM.W\tr%d%s, ", rn, t ? "!" : "");
3323 sprintf(cp, "PUSH.W\t");
3325 sprintf(cp, "STMDB\tr%d%s, ", rn, t ? "!" : "");
3328 sprintf(cp, "LDMDB.W\tr%d%s, ", rn, t ? "!" : "");
3331 return ERROR_INVALID_ARGUMENTS;
3336 for (t = 0; registers; t++, registers >>= 1) {
3337 if ((registers & 1) == 0)
3340 sprintf(cp, "r%d%s", t, registers ? ", " : "");
3349 /* load/store dual or exclusive, table branch */
3350 static int t2ev_ldrex_strex(uint32_t opcode, uint32_t address,
3351 arm_instruction_t *instruction, char *cp)
3353 unsigned op1op2 = (opcode >> 20) & 0x3;
3354 unsigned op3 = (opcode >> 4) & 0xf;
3356 unsigned rn = (opcode >> 16) & 0xf;
3357 unsigned rt = (opcode >> 12) & 0xf;
3358 unsigned rd = (opcode >> 8) & 0xf;
3359 unsigned imm = opcode & 0xff;
3363 op1op2 |= (opcode >> 21) & 0xc;
3393 mnemonic = "STREXB";
3396 mnemonic = "STREXH";
3399 return ERROR_INVALID_ARGUMENTS;
3407 sprintf(cp, "TBB\t[r%u, r%u]", rn, imm & 0xf);
3410 sprintf(cp, "TBH\t[r%u, r%u, LSL #1]", rn, imm & 0xf);
3413 mnemonic = "LDREXB";
3416 mnemonic = "LDREXH";
3419 return ERROR_INVALID_ARGUMENTS;
3424 return ERROR_INVALID_ARGUMENTS;
3429 sprintf(cp, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3430 mnemonic, rd, rt, rn, imm, imm);
3432 sprintf(cp, "%s\tr%u, r%u, [r%u]",
3433 mnemonic, rd, rt, rn);
3439 sprintf(cp, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3440 mnemonic, rt, rn, imm, imm);
3442 sprintf(cp, "%s\tr%u, [r%u]",
3447 /* two indexed modes will write back rn */
3448 if (opcode & (1 << 21)) {
3449 if (opcode & (1 << 24)) /* pre-indexed */
3451 else { /* post-indexed */
3458 sprintf(cp, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3459 mnemonic, rt, rd, rn, p1,
3460 (opcode & (1 << 23)) ? "" : "-",
3465 address = thumb_alignpc4(address);
3467 if (opcode & (1 << 23))
3471 sprintf(cp, "%s\tr%u, r%u, %#8.8" PRIx32,
3472 mnemonic, rt, rd, address);
3476 static int t2ev_data_shift(uint32_t opcode, uint32_t address,
3477 arm_instruction_t *instruction, char *cp)
3479 int op = (opcode >> 21) & 0xf;
3480 int rd = (opcode >> 8) & 0xf;
3481 int rn = (opcode >> 16) & 0xf;
3482 int type = (opcode >> 4) & 0x3;
3483 int immed = (opcode >> 6) & 0x3;
3487 immed |= (opcode >> 10) & 0x1c;
3488 if (opcode & (1 << 20))
3494 if (!(opcode & (1 << 20)))
3495 return ERROR_INVALID_ARGUMENTS;
3496 instruction->type = ARM_TST;
3501 instruction->type = ARM_AND;
3505 instruction->type = ARM_BIC;
3510 instruction->type = ARM_MOV;
3514 sprintf(cp, "MOV%s.W\tr%d, r%d",
3516 (int) (opcode & 0xf));
3529 sprintf(cp, "RRX%s\tr%d, r%d",
3531 (int) (opcode & 0xf));
3539 instruction->type = ARM_ORR;
3545 instruction->type = ARM_MVN;
3550 // instruction->type = ARM_ORN;
3556 if (!(opcode & (1 << 20)))
3557 return ERROR_INVALID_ARGUMENTS;
3558 instruction->type = ARM_TEQ;
3563 instruction->type = ARM_EOR;
3568 if (!(opcode & (1 << 20)))
3569 return ERROR_INVALID_ARGUMENTS;
3570 instruction->type = ARM_CMN;
3575 instruction->type = ARM_ADD;
3579 instruction->type = ARM_ADC;
3583 instruction->type = ARM_SBC;
3588 if (!(opcode & (1 << 21)))
3589 return ERROR_INVALID_ARGUMENTS;
3590 instruction->type = ARM_CMP;
3595 instruction->type = ARM_SUB;
3599 instruction->type = ARM_RSB;
3603 return ERROR_INVALID_ARGUMENTS;
3606 sprintf(cp, "%s%s.W\tr%d, r%d, r%d",
3607 mnemonic, suffix, rd, rn, (int) (opcode & 0xf));
3630 strcpy(cp, ", RRX");
3636 sprintf(cp, ", %s #%d", suffix, immed ? immed : 32);
3640 sprintf(cp, "%s%s.W\tr%d, r%d",
3641 mnemonic, suffix, rn, (int) (opcode & 0xf));
3645 sprintf(cp, "%s%s.W\tr%d, r%d, #%d",
3646 mnemonic, suffix, rd,
3647 (int) (opcode & 0xf), immed ? immed : 32);
3651 static int t2ev_data_reg(uint32_t opcode, uint32_t address,
3652 arm_instruction_t *instruction, char *cp)
3657 if (((opcode >> 4) & 0xf) == 0) {
3658 switch ((opcode >> 21) & 0x7) {
3672 return ERROR_INVALID_ARGUMENTS;
3675 instruction->type = ARM_MOV;
3676 if (opcode & (1 << 20))
3678 sprintf(cp, "%s%s.W\tr%d, r%d, r%d",
3680 (int) (opcode >> 8) & 0xf,
3681 (int) (opcode >> 16) & 0xf,
3682 (int) (opcode >> 0) & 0xf);
3684 } else if (opcode & (1 << 7)) {
3685 switch ((opcode >> 20) & 0xf) {
3690 switch ((opcode >> 4) & 0x3) {
3692 suffix = ", ROR #8";
3695 suffix = ", ROR #16";
3698 suffix = ", ROR #24";
3701 sprintf(cp, "%cXT%c.W\tr%d, r%d%s",
3702 (opcode & (1 << 24)) ? 'U' : 'S',
3703 (opcode & (1 << 26)) ? 'B' : 'H',
3704 (int) (opcode >> 8) & 0xf,
3705 (int) (opcode >> 0) & 0xf,
3712 if (opcode & (1 << 6))
3713 return ERROR_INVALID_ARGUMENTS;
3714 if (((opcode >> 12) & 0xf) != 0xf)
3715 return ERROR_INVALID_ARGUMENTS;
3716 if (!(opcode & (1 << 20)))
3717 return ERROR_INVALID_ARGUMENTS;
3719 switch (((opcode >> 19) & 0x04)
3720 | ((opcode >> 4) & 0x3)) {
3725 mnemonic = "REV16.W";
3731 mnemonic = "REVSH.W";
3737 return ERROR_INVALID_ARGUMENTS;
3739 sprintf(cp, "%s\tr%d, r%d",
3741 (int) (opcode >> 8) & 0xf,
3742 (int) (opcode >> 0) & 0xf);
3745 return ERROR_INVALID_ARGUMENTS;
3752 static int t2ev_load_word(uint32_t opcode, uint32_t address,
3753 arm_instruction_t *instruction, char *cp)
3755 int rn = (opcode >> 16) & 0xf;
3758 instruction->type = ARM_LDR;
3761 immed = opcode & 0x0fff;
3762 if ((opcode & (1 << 23)) == 0)
3764 sprintf(cp, "LDR\tr%d, %#8.8" PRIx32,
3765 (int) (opcode >> 12) & 0xf,
3766 thumb_alignpc4(address) + immed);
3770 if (opcode & (1 << 23)) {
3771 immed = opcode & 0x0fff;
3772 sprintf(cp, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3773 (int) (opcode >> 12) & 0xf,
3778 if (!(opcode & (0x3f << 6))) {
3779 sprintf(cp, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3780 (int) (opcode >> 12) & 0xf,
3782 (int) (opcode >> 0) & 0xf,
3783 (int) (opcode >> 4) & 0x3);
3788 if (((opcode >> 8) & 0xf) == 0xe) {
3789 immed = opcode & 0x00ff;
3791 sprintf(cp, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3792 (int) (opcode >> 12) & 0xf,
3797 if (((opcode >> 8) & 0xf) == 0xc || (opcode & 0x0900) == 0x0900) {
3798 char *p1 = "]", *p2 = "";
3800 if (!(opcode & 0x0500))
3801 return ERROR_INVALID_ARGUMENTS;
3803 immed = opcode & 0x00ff;
3805 /* two indexed modes will write back rn */
3806 if (opcode & 0x100) {
3807 if (opcode & 0x400) /* pre-indexed */
3809 else { /* post-indexed */
3815 sprintf(cp, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3816 (int) (opcode >> 12) & 0xf,
3818 (opcode & 0x200) ? "" : "-",
3823 return ERROR_INVALID_ARGUMENTS;
3826 static int t2ev_load_byte_hints(uint32_t opcode, uint32_t address,
3827 arm_instruction_t *instruction, char *cp)
3829 int rn = (opcode >> 16) & 0xf;
3830 int rt = (opcode >> 12) & 0xf;
3831 int op2 = (opcode >> 6) & 0x3f;
3833 char *p1 = "", *p2 = "]";
3836 switch ((opcode >> 23) & 0x3) {
3838 if ((rn & rt) == 0xf) {
3840 immed = opcode & 0xfff;
3841 address = thumb_alignpc4(address);
3842 if (opcode & (1 << 23))
3846 sprintf(cp, "PLD\tr%d, %#8.8" PRIx32,
3850 if (rn == 0x0f && rt != 0x0f) {
3852 immed = opcode & 0xfff;
3853 address = thumb_alignpc4(address);
3854 if (opcode & (1 << 23))
3858 sprintf(cp, "LDRB\tr%d, %#8.8" PRIx32,
3864 if ((op2 & 0x3c) == 0x38) {
3865 immed = opcode & 0xff;
3866 sprintf(cp, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3867 rt, rn, immed, immed);
3870 if ((op2 & 0x3c) == 0x30) {
3872 immed = opcode & 0xff;
3875 p1 = (opcode & (1 << 21)) ? "W" : "";
3876 sprintf(cp, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3877 p1, rn, immed, immed);
3882 immed = opcode & 0xff;
3883 if (!(opcode & 0x200))
3886 /* two indexed modes will write back rn */
3887 if (opcode & 0x100) {
3888 if (opcode & 0x400) /* pre-indexed */
3890 else { /* post-indexed */
3896 sprintf(cp, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3897 mnemonic, rt, rn, p1,
3901 if ((op2 & 0x24) == 0x24) {
3903 goto ldrxb_immediate_t3;
3906 int rm = opcode & 0xf;
3909 sprintf(cp, "PLD\t");
3911 sprintf(cp, "LDRB.W\tr%d, ", rt);
3912 immed = (opcode >> 4) & 0x3;
3914 sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed);
3919 if ((rn & rt) == 0xf)
3922 immed = opcode & 0xfff;
3923 goto preload_immediate;
3927 mnemonic = "LDRB.W";
3928 immed = opcode & 0xfff;
3929 goto ldrxb_immediate_t2;
3931 if ((rn & rt) == 0xf) {
3932 immed = opcode & 0xfff;
3933 address = thumb_alignpc4(address);
3934 if (opcode & (1 << 23))
3938 sprintf(cp, "PLI\t%#8.8" PRIx32, address);
3941 if (rn == 0xf && rt != 0xf) {
3943 immed = opcode & 0xfff;
3944 address = thumb_alignpc4(address);
3945 if (opcode & (1 << 23))
3949 sprintf(cp, "LDRSB\t%#8.8" PRIx32, address);
3954 if ((op2 & 0x3c) == 0x38) {
3955 immed = opcode & 0xff;
3956 sprintf(cp, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
3957 rt, rn, immed, immed);
3960 if ((op2 & 0x3c) == 0x30) {
3962 immed = opcode & 0xff;
3963 immed = -immed; // pli
3964 sprintf(cp, "PLI\t[r%d, #%d]\t; -%#2.2x",
3969 goto ldrxb_immediate_t3;
3971 if ((op2 & 0x24) == 0x24) {
3973 goto ldrxb_immediate_t3;
3976 int rm = opcode & 0xf;
3979 sprintf(cp, "PLI\t");
3981 sprintf(cp, "LDRSB.W\tr%d, ", rt);
3982 immed = (opcode >> 4) & 0x3;
3984 sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed);
3990 immed = opcode & 0xfff;
3991 sprintf(cp, "PLI\t[r%d, #%d]\t; %#3.3x",
3997 immed = opcode & 0xfff;
3999 goto ldrxb_immediate_t2;
4002 return ERROR_INVALID_ARGUMENTS;
4005 static int t2ev_load_halfword(uint32_t opcode, uint32_t address,
4006 arm_instruction_t *instruction, char *cp)
4008 int rn = (opcode >> 16) & 0xf;
4009 int rt = (opcode >> 12) & 0xf;
4010 int op2 = (opcode >> 6) & 0x3f;
4015 sprintf(cp, "HINT (UNALLOCATED)");
4019 if (opcode & (1 << 24))
4022 if ((opcode & (1 << 23)) == 0) {
4025 immed = opcode & 0xfff;
4026 address = thumb_alignpc4(address);
4027 if (opcode & (1 << 23))
4031 sprintf(cp, "LDR%sH\tr%d, %#8.8" PRIx32,
4036 int rm = opcode & 0xf;
4038 immed = (opcode >> 4) & 0x3;
4039 sprintf(cp, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4040 sign, rt, rn, rm, immed);
4043 if ((op2 & 0x3c) == 0x38) {
4044 immed = opcode & 0xff;
4045 sprintf(cp, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4046 sign, rt, rn, immed, immed);
4049 if ((op2 & 0x3c) == 0x30 || (op2 & 0x24) == 0x24) {
4050 char *p1 = "", *p2 = "]";
4052 immed = opcode & 0xff;
4053 if (!(opcode & 0x200))
4056 /* two indexed modes will write back rn */
4057 if (opcode & 0x100) {
4058 if (opcode & 0x400) /* pre-indexed */
4060 else { /* post-indexed */
4065 sprintf(cp, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4066 sign, rt, rn, p1, immed, p2, immed);
4073 immed = opcode & 0xfff;
4074 sprintf(cp, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4075 sign, *sign ? "" : ".W",
4076 rt, rn, immed, immed);
4080 return ERROR_INVALID_ARGUMENTS;
4084 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4085 * always set. That means eventual arm_simulate_step() support for Thumb2
4086 * will need work in this area.
4088 int thumb2_opcode(target_t *target, uint32_t address, arm_instruction_t *instruction)
4095 /* clear low bit ... it's set on function pointers */
4098 /* clear fields, to avoid confusion */
4099 memset(instruction, 0, sizeof(arm_instruction_t));
4101 /* read first halfword, see if this is the only one */
4102 retval = target_read_u16(target, address, &op);
4103 if (retval != ERROR_OK)
4106 switch (op & 0xf800) {
4110 /* 32-bit instructions */
4111 instruction->instruction_size = 4;
4113 retval = target_read_u16(target, address + 2, &op);
4114 if (retval != ERROR_OK)
4117 instruction->opcode = opcode;
4120 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4121 return thumb_evaluate_opcode(op, address, instruction);
4124 snprintf(instruction->text, 128,
4125 "0x%8.8" PRIx32 " 0x%8.8" PRIx32 "\t",
4127 cp = strchr(instruction->text, 0);
4128 retval = ERROR_FAIL;
4130 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4131 if ((opcode & 0x1a008000) == 0x10000000)
4132 retval = t2ev_data_mod_immed(opcode, address, instruction, cp);
4134 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4135 else if ((opcode & 0x1a008000) == 0x12000000)
4136 retval = t2ev_data_immed(opcode, address, instruction, cp);
4138 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4139 else if ((opcode & 0x18008000) == 0x10008000)
4140 retval = t2ev_b_misc(opcode, address, instruction, cp);
4142 /* ARMv7-M: A5.3.5 Load/store multiple */
4143 else if ((opcode & 0x1e400000) == 0x08000000)
4144 retval = t2ev_ldm_stm(opcode, address, instruction, cp);
4146 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4147 else if ((opcode & 0x1e400000) == 0x08400000)
4148 retval = t2ev_ldrex_strex(opcode, address, instruction, cp);
4150 /* ARMv7-M: A5.3.7 Load word */
4151 else if ((opcode & 0x1f700000) == 0x18500000)
4152 retval = t2ev_load_word(opcode, address, instruction, cp);
4154 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4155 else if ((opcode & 0x1e700000) == 0x18300000)
4156 retval = t2ev_load_halfword(opcode, address, instruction, cp);
4158 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4159 else if ((opcode & 0x1e700000) == 0x18100000)
4160 retval = t2ev_load_byte_hints(opcode, address, instruction, cp);
4162 /* ARMv7-M: A5.3.10 Store single data item */
4163 else if ((opcode & 0x1f100000) == 0x18000000)
4164 retval = t2ev_store_single(opcode, address, instruction, cp);
4166 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4167 else if ((opcode & 0x1e000000) == 0x0a000000)
4168 retval = t2ev_data_shift(opcode, address, instruction, cp);
4170 /* ARMv7-M: A5.3.12 Data processing (register)
4171 * and A5.3.13 Miscellaneous operations
4173 else if ((opcode & 0x1f000000) == 0x1a000000)
4174 retval = t2ev_data_reg(opcode, address, instruction, cp);
4176 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4177 else if ((opcode & 0x1f800000) == 0x1b000000)
4178 retval = t2ev_mul32(opcode, address, instruction, cp);
4180 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4181 else if ((opcode & 0x1f800000) == 0x1b800000)
4182 retval = t2ev_mul64_div(opcode, address, instruction, cp);
4184 if (retval == ERROR_OK)
4188 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4189 * instructions; not yet handled here.
4192 if (retval == ERROR_INVALID_ARGUMENTS) {
4193 instruction->type = ARM_UNDEFINED_INSTRUCTION;
4194 strcpy(cp, "UNDEFINED OPCODE");
4198 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32 ")",
4201 strcpy(cp, "(32-bit Thumb2 ...)");
4205 int arm_access_size(arm_instruction_t *instruction)
4207 if ((instruction->type == ARM_LDRB)
4208 || (instruction->type == ARM_LDRBT)
4209 || (instruction->type == ARM_LDRSB)
4210 || (instruction->type == ARM_STRB)
4211 || (instruction->type == ARM_STRBT))
4215 else if ((instruction->type == ARM_LDRH)
4216 || (instruction->type == ARM_LDRSH)
4217 || (instruction->type == ARM_STRH))
4221 else if ((instruction->type == ARM_LDR)
4222 || (instruction->type == ARM_LDRT)
4223 || (instruction->type == ARM_STR)
4224 || (instruction->type == ARM_STRT))
4228 else if ((instruction->type == ARM_LDRD)
4229 || (instruction->type == ARM_STRD))
4235 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction->type);