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 /* GCC 'uninitialized warning removal' */
451 switch ((opcode >> 24) & 0x3) {
456 sprintf(cp, "UNDEFINED");
457 return ARM_UNDEFINED_INSTRUCTION;
466 switch ((opcode >> 10) & 0x3) {
482 sprintf(cp, "%cXT%s%s\tr%d, r%d%s",
483 (opcode & (1 << 22)) ? 'U' : 'S',
488 sprintf(cp, "%cXTA%s%s\tr%d, r%d, r%d%s",
489 (opcode & (1 << 22)) ? 'U' : 'S',
496 static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp)
502 switch ((opcode >> 20) & 0x7) {
525 switch ((opcode >> 5) & 0x7) {
554 sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode),
555 (int) (opcode >> 12) & 0xf,
556 (int) (opcode >> 16) & 0xf,
557 (int) (opcode >> 0) & 0xf);
561 /* these opcodes might be used someday */
562 sprintf(cp, "UNDEFINED");
563 return ARM_UNDEFINED_INSTRUCTION;
566 /* ARMv6 and later support "media" instructions (includes SIMD) */
567 static int evaluate_media(uint32_t opcode, uint32_t address,
568 arm_instruction_t *instruction)
570 char *cp = instruction->text;
571 char *mnemonic = NULL;
574 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t",
578 /* parallel add/subtract */
579 if ((opcode & 0x01800000) == 0x00000000) {
580 instruction->type = evaluate_p_add_sub(opcode, address, cp);
585 if ((opcode & 0x01f00020) == 0x00800000) {
587 unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
589 if (opcode & (1 << 6)) {
598 sprintf(cp, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
600 (int) (opcode >> 12) & 0xf,
601 (int) (opcode >> 16) & 0xf,
602 (int) (opcode >> 0) & 0xf,
608 if ((opcode & 0x01a00020) == 0x00a00000) {
610 unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
612 if (opcode & (1 << 6)) {
620 sprintf(cp, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
621 (opcode & (1 << 22)) ? 'U' : 'S',
623 (int) (opcode >> 12) & 0xf,
624 (int) (opcode >> 16) & 0x1f,
625 (int) (opcode >> 0) & 0xf,
631 if ((opcode & 0x018000f0) == 0x00800070) {
632 instruction->type = evaluate_extend(opcode, address, cp);
637 if ((opcode & 0x01f00080) == 0x01000000) {
638 unsigned rn = (opcode >> 12) & 0xf;
641 sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
642 (opcode & (1 << 6)) ? 'S' : 'A',
643 (opcode & (1 << 5)) ? "X" : "",
645 (int) (opcode >> 16) & 0xf,
646 (int) (opcode >> 0) & 0xf,
647 (int) (opcode >> 8) & 0xf,
650 sprintf(cp, "SMU%cD%s%s\tr%d, r%d, r%d",
651 (opcode & (1 << 6)) ? 'S' : 'A',
652 (opcode & (1 << 5)) ? "X" : "",
654 (int) (opcode >> 16) & 0xf,
655 (int) (opcode >> 0) & 0xf,
656 (int) (opcode >> 8) & 0xf);
659 if ((opcode & 0x01f00000) == 0x01400000) {
660 sprintf(cp, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
661 (opcode & (1 << 6)) ? 'S' : 'A',
662 (opcode & (1 << 5)) ? "X" : "",
664 (int) (opcode >> 12) & 0xf,
665 (int) (opcode >> 16) & 0xf,
666 (int) (opcode >> 0) & 0xf,
667 (int) (opcode >> 8) & 0xf);
670 if ((opcode & 0x01f00000) == 0x01500000) {
671 unsigned rn = (opcode >> 12) & 0xf;
673 switch (opcode & 0xc0) {
685 sprintf(cp, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
686 (opcode & (1 << 6)) ? 'S' : 'A',
687 (opcode & (1 << 5)) ? "R" : "",
689 (int) (opcode >> 16) & 0xf,
690 (int) (opcode >> 0) & 0xf,
691 (int) (opcode >> 8) & 0xf,
694 sprintf(cp, "SMMUL%s%s\tr%d, r%d, r%d",
695 (opcode & (1 << 5)) ? "R" : "",
697 (int) (opcode >> 16) & 0xf,
698 (int) (opcode >> 0) & 0xf,
699 (int) (opcode >> 8) & 0xf);
704 /* simple matches against the remaining decode bits */
705 switch (opcode & 0x01f000f0) {
708 /* parallel halfword saturate */
709 sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d",
710 (opcode & (1 << 22)) ? 'U' : 'S',
712 (int) (opcode >> 12) & 0xf,
713 (int) (opcode >> 16) & 0xf,
714 (int) (opcode >> 0) & 0xf);
727 sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode),
728 (int) (opcode >> 12) & 0xf,
729 (int) (opcode >> 16) & 0xf,
730 (int) (opcode >> 0) & 0xf);
733 /* unsigned sum of absolute differences */
734 if (((opcode >> 12) & 0xf) == 0xf)
735 sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode),
736 (int) (opcode >> 16) & 0xf,
737 (int) (opcode >> 0) & 0xf,
738 (int) (opcode >> 8) & 0xf);
740 sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode),
741 (int) (opcode >> 16) & 0xf,
742 (int) (opcode >> 0) & 0xf,
743 (int) (opcode >> 8) & 0xf,
744 (int) (opcode >> 12) & 0xf);
748 unsigned rm = (opcode >> 0) & 0xf;
749 unsigned rd = (opcode >> 12) & 0xf;
751 sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd);
756 /* these opcodes might be used someday */
757 sprintf(cp, "UNDEFINED");
761 /* Miscellaneous load/store instructions */
762 int evaluate_misc_load_store(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
764 uint8_t P, U, I, W, L, S, H;
766 char *operation; /* "LDR" or "STR" */
767 char *suffix; /* "H", "SB", "SH", "D" */
771 P = (opcode & 0x01000000) >> 24;
772 U = (opcode & 0x00800000) >> 23;
773 I = (opcode & 0x00400000) >> 22;
774 W = (opcode & 0x00200000) >> 21;
775 L = (opcode & 0x00100000) >> 20;
776 S = (opcode & 0x00000040) >> 6;
777 H = (opcode & 0x00000020) >> 5;
779 /* target register */
780 Rd = (opcode & 0xf000) >> 12;
783 Rn = (opcode & 0xf0000) >> 16;
785 instruction->info.load_store.Rd = Rd;
786 instruction->info.load_store.Rn = Rn;
787 instruction->info.load_store.U = U;
789 /* determine instruction type and suffix */
797 instruction->type = ARM_LDRSH;
803 instruction->type = ARM_LDRSB;
807 else /* there are no signed stores, so this is used to encode double-register load/stores */
813 instruction->type = ARM_STRD;
818 instruction->type = ARM_LDRD;
828 instruction->type = ARM_LDRH;
833 instruction->type = ARM_STRH;
837 if (I) /* Immediate offset/index (#+-<offset_8>)*/
839 uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
840 snprintf(offset, 32, "#%s0x%" PRIx32 "", (U) ? "" : "-", offset_8);
842 instruction->info.load_store.offset_mode = 0;
843 instruction->info.load_store.offset.offset = offset_8;
845 else /* Register offset/index (+-<Rm>) */
849 snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
851 instruction->info.load_store.offset_mode = 1;
852 instruction->info.load_store.offset.reg.Rm = Rm;
853 instruction->info.load_store.offset.reg.shift = 0x0;
854 instruction->info.load_store.offset.reg.shift_imm = 0x0;
859 if (W == 0) /* offset */
861 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]",
862 address, opcode, operation, COND(opcode), suffix,
865 instruction->info.load_store.index_mode = 0;
867 else /* pre-indexed */
869 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]!",
870 address, opcode, operation, COND(opcode), suffix,
873 instruction->info.load_store.index_mode = 1;
876 else /* post-indexed */
878 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i], %s",
879 address, opcode, operation, COND(opcode), suffix,
882 instruction->info.load_store.index_mode = 2;
888 /* Load/store multiples instructions */
889 int evaluate_ldm_stm(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
891 uint8_t P, U, S, W, L, Rn;
892 uint32_t register_list;
893 char *addressing_mode;
900 P = (opcode & 0x01000000) >> 24;
901 U = (opcode & 0x00800000) >> 23;
902 S = (opcode & 0x00400000) >> 22;
903 W = (opcode & 0x00200000) >> 21;
904 L = (opcode & 0x00100000) >> 20;
905 register_list = (opcode & 0xffff);
906 Rn = (opcode & 0xf0000) >> 16;
908 instruction->info.load_store_multiple.Rn = Rn;
909 instruction->info.load_store_multiple.register_list = register_list;
910 instruction->info.load_store_multiple.S = S;
911 instruction->info.load_store_multiple.W = W;
915 instruction->type = ARM_LDM;
920 instruction->type = ARM_STM;
928 instruction->info.load_store_multiple.addressing_mode = 1;
929 addressing_mode = "IB";
933 instruction->info.load_store_multiple.addressing_mode = 3;
934 addressing_mode = "DB";
941 instruction->info.load_store_multiple.addressing_mode = 0;
942 /* "IA" is the default in UAL syntax */
943 addressing_mode = "";
947 instruction->info.load_store_multiple.addressing_mode = 2;
948 addressing_mode = "DA";
952 reg_list_p = reg_list;
953 for (i = 0; i <= 15; i++)
955 if ((register_list >> i) & 1)
960 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i);
964 reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i);
969 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i%s, {%s}%s",
970 address, opcode, mnemonic, COND(opcode), addressing_mode,
971 Rn, (W) ? "!" : "", reg_list, (S) ? "^" : "");
976 /* Multiplies, extra load/stores */
977 int evaluate_mul_and_extra_ld_st(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
979 /* Multiply (accumulate) (long) and Swap/swap byte */
980 if ((opcode & 0x000000f0) == 0x00000090)
982 /* Multiply (accumulate) */
983 if ((opcode & 0x0f800000) == 0x00000000)
985 uint8_t Rm, Rs, Rn, Rd, S;
987 Rs = (opcode & 0xf00) >> 8;
988 Rn = (opcode & 0xf000) >> 12;
989 Rd = (opcode & 0xf0000) >> 16;
990 S = (opcode & 0x00100000) >> 20;
992 /* examine A bit (accumulate) */
993 if (opcode & 0x00200000)
995 instruction->type = ARM_MLA;
996 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMLA%s%s r%i, r%i, r%i, r%i",
997 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs, Rn);
1001 instruction->type = ARM_MUL;
1002 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMUL%s%s r%i, r%i, r%i",
1003 address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs);
1009 /* Multiply (accumulate) long */
1010 if ((opcode & 0x0f800000) == 0x00800000)
1012 char* mnemonic = NULL;
1013 uint8_t Rm, Rs, RdHi, RdLow, S;
1015 Rs = (opcode & 0xf00) >> 8;
1016 RdHi = (opcode & 0xf000) >> 12;
1017 RdLow = (opcode & 0xf0000) >> 16;
1018 S = (opcode & 0x00100000) >> 20;
1020 switch ((opcode & 0x00600000) >> 21)
1023 instruction->type = ARM_UMULL;
1027 instruction->type = ARM_UMLAL;
1031 instruction->type = ARM_SMULL;
1035 instruction->type = ARM_SMLAL;
1040 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, r%i, r%i",
1041 address, opcode, mnemonic, COND(opcode), (S) ? "S" : "",
1042 RdLow, RdHi, Rm, Rs);
1047 /* Swap/swap byte */
1048 if ((opcode & 0x0f800000) == 0x01000000)
1052 Rd = (opcode & 0xf000) >> 12;
1053 Rn = (opcode & 0xf0000) >> 16;
1055 /* examine B flag */
1056 instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP;
1058 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, [r%i]",
1059 address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), Rd, Rm, Rn);
1065 return evaluate_misc_load_store(opcode, address, instruction);
1068 int evaluate_mrs_msr(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1070 int R = (opcode & 0x00400000) >> 22;
1071 char *PSR = (R) ? "SPSR" : "CPSR";
1073 /* Move register to status register (MSR) */
1074 if (opcode & 0x00200000)
1076 instruction->type = ARM_MSR;
1078 /* immediate variant */
1079 if (opcode & 0x02000000)
1081 uint8_t immediate = (opcode & 0xff);
1082 uint8_t rotate = (opcode & 0xf00);
1084 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32 ,
1085 address, opcode, COND(opcode), PSR,
1086 (opcode & 0x10000) ? "c" : "",
1087 (opcode & 0x20000) ? "x" : "",
1088 (opcode & 0x40000) ? "s" : "",
1089 (opcode & 0x80000) ? "f" : "",
1090 ror(immediate, (rotate * 2))
1093 else /* register variant */
1095 uint8_t Rm = opcode & 0xf;
1096 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, r%i",
1097 address, opcode, COND(opcode), PSR,
1098 (opcode & 0x10000) ? "c" : "",
1099 (opcode & 0x20000) ? "x" : "",
1100 (opcode & 0x40000) ? "s" : "",
1101 (opcode & 0x80000) ? "f" : "",
1107 else /* Move status register to register (MRS) */
1111 instruction->type = ARM_MRS;
1112 Rd = (opcode & 0x0000f000) >> 12;
1114 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMRS%s r%i, %s",
1115 address, opcode, COND(opcode), Rd, PSR);
1121 /* Miscellaneous instructions */
1122 int evaluate_misc_instr(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1125 if ((opcode & 0x000000f0) == 0x00000000)
1127 evaluate_mrs_msr(opcode, address, instruction);
1131 if ((opcode & 0x006000f0) == 0x00200010)
1134 instruction->type = ARM_BX;
1137 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBX%s r%i",
1138 address, opcode, COND(opcode), Rm);
1140 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1141 instruction->info.b_bl_bx_blx.target_address = -1;
1144 /* BXJ - "Jazelle" support (ARMv5-J) */
1145 if ((opcode & 0x006000f0) == 0x00200020)
1148 instruction->type = ARM_BX;
1151 snprintf(instruction->text, 128,
1152 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBXJ%s r%i",
1153 address, opcode, COND(opcode), Rm);
1155 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1156 instruction->info.b_bl_bx_blx.target_address = -1;
1160 if ((opcode & 0x006000f0) == 0x00600010)
1163 instruction->type = ARM_CLZ;
1165 Rd = (opcode & 0xf000) >> 12;
1167 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLZ%s r%i, r%i",
1168 address, opcode, COND(opcode), Rd, Rm);
1172 if ((opcode & 0x006000f0) == 0x00200030)
1175 instruction->type = ARM_BLX;
1178 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX%s r%i",
1179 address, opcode, COND(opcode), Rm);
1181 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1182 instruction->info.b_bl_bx_blx.target_address = -1;
1185 /* Enhanced DSP add/subtracts */
1186 if ((opcode & 0x0000000f0) == 0x00000050)
1189 char *mnemonic = NULL;
1191 Rd = (opcode & 0xf000) >> 12;
1192 Rn = (opcode & 0xf0000) >> 16;
1194 switch ((opcode & 0x00600000) >> 21)
1197 instruction->type = ARM_QADD;
1201 instruction->type = ARM_QSUB;
1205 instruction->type = ARM_QDADD;
1209 instruction->type = ARM_QDSUB;
1214 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, r%i",
1215 address, opcode, mnemonic, COND(opcode), Rd, Rm, Rn);
1218 /* Software breakpoints */
1219 if ((opcode & 0x0000000f0) == 0x00000070)
1222 instruction->type = ARM_BKPT;
1223 immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf);
1225 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBKPT 0x%4.4" PRIx32 "",
1226 address, opcode, immediate);
1229 /* Enhanced DSP multiplies */
1230 if ((opcode & 0x000000090) == 0x00000080)
1232 int x = (opcode & 0x20) >> 5;
1233 int y = (opcode & 0x40) >> 6;
1236 if ((opcode & 0x00600000) == 0x00000000)
1238 uint8_t Rd, Rm, Rs, Rn;
1239 instruction->type = ARM_SMLAxy;
1240 Rd = (opcode & 0xf0000) >> 16;
1241 Rm = (opcode & 0xf);
1242 Rs = (opcode & 0xf00) >> 8;
1243 Rn = (opcode & 0xf000) >> 12;
1245 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1246 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
1251 if ((opcode & 0x00600000) == 0x00400000)
1253 uint8_t RdLow, RdHi, Rm, Rs;
1254 instruction->type = ARM_SMLAxy;
1255 RdHi = (opcode & 0xf0000) >> 16;
1256 RdLow = (opcode & 0xf000) >> 12;
1257 Rm = (opcode & 0xf);
1258 Rs = (opcode & 0xf00) >> 8;
1260 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1261 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
1262 RdLow, RdHi, Rm, Rs);
1266 if (((opcode & 0x00600000) == 0x00100000) && (x == 0))
1268 uint8_t Rd, Rm, Rs, Rn;
1269 instruction->type = ARM_SMLAWy;
1270 Rd = (opcode & 0xf0000) >> 16;
1271 Rm = (opcode & 0xf);
1272 Rs = (opcode & 0xf00) >> 8;
1273 Rn = (opcode & 0xf000) >> 12;
1275 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLAW%s%s r%i, r%i, r%i, r%i",
1276 address, opcode, (y) ? "T" : "B", COND(opcode),
1281 if ((opcode & 0x00600000) == 0x00300000)
1284 instruction->type = ARM_SMULxy;
1285 Rd = (opcode & 0xf0000) >> 16;
1286 Rm = (opcode & 0xf);
1287 Rs = (opcode & 0xf00) >> 8;
1289 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s%s r%i, r%i, r%i",
1290 address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
1295 if (((opcode & 0x00600000) == 0x00100000) && (x == 1))
1298 instruction->type = ARM_SMULWy;
1299 Rd = (opcode & 0xf0000) >> 16;
1300 Rm = (opcode & 0xf);
1301 Rs = (opcode & 0xf00) >> 8;
1303 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s r%i, r%i, r%i",
1304 address, opcode, (y) ? "T" : "B", COND(opcode),
1312 int evaluate_data_proc(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1314 uint8_t I, op, S, Rn, Rd;
1315 char *mnemonic = NULL;
1316 char shifter_operand[32];
1318 I = (opcode & 0x02000000) >> 25;
1319 op = (opcode & 0x01e00000) >> 21;
1320 S = (opcode & 0x00100000) >> 20;
1322 Rd = (opcode & 0xf000) >> 12;
1323 Rn = (opcode & 0xf0000) >> 16;
1325 instruction->info.data_proc.Rd = Rd;
1326 instruction->info.data_proc.Rn = Rn;
1327 instruction->info.data_proc.S = S;
1332 instruction->type = ARM_AND;
1336 instruction->type = ARM_EOR;
1340 instruction->type = ARM_SUB;
1344 instruction->type = ARM_RSB;
1348 instruction->type = ARM_ADD;
1352 instruction->type = ARM_ADC;
1356 instruction->type = ARM_SBC;
1360 instruction->type = ARM_RSC;
1364 instruction->type = ARM_TST;
1368 instruction->type = ARM_TEQ;
1372 instruction->type = ARM_CMP;
1376 instruction->type = ARM_CMN;
1380 instruction->type = ARM_ORR;
1384 instruction->type = ARM_MOV;
1388 instruction->type = ARM_BIC;
1392 instruction->type = ARM_MVN;
1397 if (I) /* immediate shifter operand (#<immediate>)*/
1399 uint8_t immed_8 = opcode & 0xff;
1400 uint8_t rotate_imm = (opcode & 0xf00) >> 8;
1403 immediate = ror(immed_8, rotate_imm * 2);
1405 snprintf(shifter_operand, 32, "#0x%" PRIx32 "", immediate);
1407 instruction->info.data_proc.variant = 0;
1408 instruction->info.data_proc.shifter_operand.immediate.immediate = immediate;
1410 else /* register-based shifter operand */
1413 shift = (opcode & 0x60) >> 5;
1414 Rm = (opcode & 0xf);
1416 if ((opcode & 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1419 shift_imm = (opcode & 0xf80) >> 7;
1421 instruction->info.data_proc.variant = 1;
1422 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1423 instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = shift_imm;
1424 instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift;
1426 /* LSR encodes a shift by 32 bit as 0x0 */
1427 if ((shift == 0x1) && (shift_imm == 0x0))
1430 /* ASR encodes a shift by 32 bit as 0x0 */
1431 if ((shift == 0x2) && (shift_imm == 0x0))
1434 /* ROR by 32 bit is actually a RRX */
1435 if ((shift == 0x3) && (shift_imm == 0x0))
1438 if ((shift_imm == 0x0) && (shift == 0x0))
1440 snprintf(shifter_operand, 32, "r%i", Rm);
1444 if (shift == 0x0) /* LSL */
1446 snprintf(shifter_operand, 32, "r%i, LSL #0x%x", Rm, shift_imm);
1448 else if (shift == 0x1) /* LSR */
1450 snprintf(shifter_operand, 32, "r%i, LSR #0x%x", Rm, shift_imm);
1452 else if (shift == 0x2) /* ASR */
1454 snprintf(shifter_operand, 32, "r%i, ASR #0x%x", Rm, shift_imm);
1456 else if (shift == 0x3) /* ROR */
1458 snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm);
1460 else if (shift == 0x4) /* RRX */
1462 snprintf(shifter_operand, 32, "r%i, RRX", Rm);
1466 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1468 uint8_t Rs = (opcode & 0xf00) >> 8;
1470 instruction->info.data_proc.variant = 2;
1471 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rm;
1472 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rs;
1473 instruction->info.data_proc.shifter_operand.register_shift.shift = shift;
1475 if (shift == 0x0) /* LSL */
1477 snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs);
1479 else if (shift == 0x1) /* LSR */
1481 snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs);
1483 else if (shift == 0x2) /* ASR */
1485 snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs);
1487 else if (shift == 0x3) /* ROR */
1489 snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs);
1494 if ((op < 0x8) || (op == 0xc) || (op == 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1496 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, %s",
1497 address, opcode, mnemonic, COND(opcode),
1498 (S) ? "S" : "", Rd, Rn, shifter_operand);
1500 else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1502 if (opcode == 0xe1a00000) /* print MOV r0,r0 as NOP */
1503 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tNOP",address, opcode);
1505 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, %s",
1506 address, opcode, mnemonic, COND(opcode),
1507 (S) ? "S" : "", Rd, shifter_operand);
1509 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1511 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, %s",
1512 address, opcode, mnemonic, COND(opcode),
1513 Rn, shifter_operand);
1519 int arm_evaluate_opcode(uint32_t opcode, uint32_t address, arm_instruction_t *instruction)
1521 /* clear fields, to avoid confusion */
1522 memset(instruction, 0, sizeof(arm_instruction_t));
1523 instruction->opcode = opcode;
1524 instruction->instruction_size = 4;
1526 /* catch opcodes with condition field [31:28] = b1111 */
1527 if ((opcode & 0xf0000000) == 0xf0000000)
1529 /* Undefined instruction (or ARMv5E cache preload PLD) */
1530 if ((opcode & 0x08000000) == 0x00000000)
1531 return evaluate_pld(opcode, address, instruction);
1533 /* Undefined instruction */
1534 if ((opcode & 0x0e000000) == 0x08000000)
1536 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1537 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode);
1541 /* Branch and branch with link and change to Thumb */
1542 if ((opcode & 0x0e000000) == 0x0a000000)
1543 return evaluate_blx_imm(opcode, address, instruction);
1545 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1546 /* Coprocessor load/store and double register transfers */
1547 if ((opcode & 0x0e000000) == 0x0c000000)
1548 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1550 /* Coprocessor data processing */
1551 if ((opcode & 0x0f000100) == 0x0c000000)
1552 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1554 /* Coprocessor register transfers */
1555 if ((opcode & 0x0f000010) == 0x0c000010)
1556 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1558 /* Undefined instruction */
1559 if ((opcode & 0x0f000000) == 0x0f000000)
1561 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1562 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode);
1567 /* catch opcodes with [27:25] = b000 */
1568 if ((opcode & 0x0e000000) == 0x00000000)
1570 /* Multiplies, extra load/stores */
1571 if ((opcode & 0x00000090) == 0x00000090)
1572 return evaluate_mul_and_extra_ld_st(opcode, address, instruction);
1574 /* Miscellaneous instructions */
1575 if ((opcode & 0x0f900000) == 0x01000000)
1576 return evaluate_misc_instr(opcode, address, instruction);
1578 return evaluate_data_proc(opcode, address, instruction);
1581 /* catch opcodes with [27:25] = b001 */
1582 if ((opcode & 0x0e000000) == 0x02000000)
1584 /* Undefined instruction */
1585 if ((opcode & 0x0fb00000) == 0x03000000)
1587 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1588 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode);
1592 /* Move immediate to status register */
1593 if ((opcode & 0x0fb00000) == 0x03200000)
1594 return evaluate_mrs_msr(opcode, address, instruction);
1596 return evaluate_data_proc(opcode, address, instruction);
1600 /* catch opcodes with [27:25] = b010 */
1601 if ((opcode & 0x0e000000) == 0x04000000)
1603 /* Load/store immediate offset */
1604 return evaluate_load_store(opcode, address, instruction);
1607 /* catch opcodes with [27:25] = b011 */
1608 if ((opcode & 0x0e000000) == 0x06000000)
1610 /* Load/store register offset */
1611 if ((opcode & 0x00000010) == 0x00000000)
1612 return evaluate_load_store(opcode, address, instruction);
1614 /* Architecturally Undefined instruction
1615 * ... don't expect these to ever be used
1617 if ((opcode & 0x07f000f0) == 0x07f000f0)
1619 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1620 snprintf(instruction->text, 128,
1621 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEF",
1626 /* "media" instructions */
1627 return evaluate_media(opcode, address, instruction);
1630 /* catch opcodes with [27:25] = b100 */
1631 if ((opcode & 0x0e000000) == 0x08000000)
1633 /* Load/store multiple */
1634 return evaluate_ldm_stm(opcode, address, instruction);
1637 /* catch opcodes with [27:25] = b101 */
1638 if ((opcode & 0x0e000000) == 0x0a000000)
1640 /* Branch and branch with link */
1641 return evaluate_b_bl(opcode, address, instruction);
1644 /* catch opcodes with [27:25] = b110 */
1645 if ((opcode & 0x0e000000) == 0x0a000000)
1647 /* Coprocessor load/store and double register transfers */
1648 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1651 /* catch opcodes with [27:25] = b111 */
1652 if ((opcode & 0x0e000000) == 0x0e000000)
1654 /* Software interrupt */
1655 if ((opcode & 0x0f000000) == 0x0f000000)
1656 return evaluate_swi(opcode, address, instruction);
1658 /* Coprocessor data processing */
1659 if ((opcode & 0x0f000010) == 0x0e000000)
1660 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1662 /* Coprocessor register transfers */
1663 if ((opcode & 0x0f000010) == 0x0e000010)
1664 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1667 LOG_ERROR("should never reach this point");
1671 int evaluate_b_bl_blx_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1673 uint32_t offset = opcode & 0x7ff;
1674 uint32_t opc = (opcode >> 11) & 0x3;
1675 uint32_t target_address;
1676 char *mnemonic = NULL;
1678 /* sign extend 11-bit offset */
1679 if (((opc == 0) || (opc == 2)) && (offset & 0x00000400))
1680 offset = 0xfffff800 | offset;
1682 target_address = address + 4 + (offset << 1);
1686 /* unconditional branch */
1688 instruction->type = ARM_B;
1693 instruction->type = ARM_BLX;
1698 instruction->type = ARM_UNKNOWN_INSTUCTION;
1699 mnemonic = "prefix";
1700 target_address = offset << 12;
1704 instruction->type = ARM_BL;
1709 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1710 * these are effectively 32-bit instructions even in Thumb1.
1711 * Might be simplest to always use the Thumb2 decoder.
1714 snprintf(instruction->text, 128,
1715 "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%#8.8" PRIx32,
1716 address, opcode, mnemonic, target_address);
1718 instruction->info.b_bl_bx_blx.reg_operand = -1;
1719 instruction->info.b_bl_bx_blx.target_address = target_address;
1724 int evaluate_add_sub_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1726 uint8_t Rd = (opcode >> 0) & 0x7;
1727 uint8_t Rn = (opcode >> 3) & 0x7;
1728 uint8_t Rm_imm = (opcode >> 6) & 0x7;
1729 uint32_t opc = opcode & (1 << 9);
1730 uint32_t reg_imm = opcode & (1 << 10);
1735 instruction->type = ARM_SUB;
1740 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1741 instruction->type = ARM_ADD;
1745 instruction->info.data_proc.Rd = Rd;
1746 instruction->info.data_proc.Rn = Rn;
1747 instruction->info.data_proc.S = 1;
1751 instruction->info.data_proc.variant = 0; /*immediate*/
1752 instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm;
1753 snprintf(instruction->text, 128,
1754 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%d",
1755 address, opcode, mnemonic, Rd, Rn, Rm_imm);
1759 instruction->info.data_proc.variant = 1; /*immediate shift*/
1760 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm;
1761 snprintf(instruction->text, 128,
1762 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, r%i",
1763 address, opcode, mnemonic, Rd, Rn, Rm_imm);
1769 int evaluate_shift_imm_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1771 uint8_t Rd = (opcode >> 0) & 0x7;
1772 uint8_t Rm = (opcode >> 3) & 0x7;
1773 uint8_t imm = (opcode >> 6) & 0x1f;
1774 uint8_t opc = (opcode >> 11) & 0x3;
1775 char *mnemonic = NULL;
1780 instruction->type = ARM_MOV;
1782 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0;
1785 instruction->type = ARM_MOV;
1787 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1;
1790 instruction->type = ARM_MOV;
1792 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2;
1796 if ((imm == 0) && (opc != 0))
1799 instruction->info.data_proc.Rd = Rd;
1800 instruction->info.data_proc.Rn = -1;
1801 instruction->info.data_proc.S = 1;
1803 instruction->info.data_proc.variant = 1; /*immediate_shift*/
1804 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1805 instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm;
1807 snprintf(instruction->text, 128,
1808 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1809 address, opcode, mnemonic, Rd, Rm, imm);
1814 int evaluate_data_proc_imm_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1816 uint8_t imm = opcode & 0xff;
1817 uint8_t Rd = (opcode >> 8) & 0x7;
1818 uint32_t opc = (opcode >> 11) & 0x3;
1819 char *mnemonic = NULL;
1821 instruction->info.data_proc.Rd = Rd;
1822 instruction->info.data_proc.Rn = Rd;
1823 instruction->info.data_proc.S = 1;
1824 instruction->info.data_proc.variant = 0; /*immediate*/
1825 instruction->info.data_proc.shifter_operand.immediate.immediate = imm;
1830 instruction->type = ARM_MOV;
1832 instruction->info.data_proc.Rn = -1;
1835 instruction->type = ARM_CMP;
1837 instruction->info.data_proc.Rd = -1;
1840 instruction->type = ARM_ADD;
1844 instruction->type = ARM_SUB;
1849 snprintf(instruction->text, 128,
1850 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, #%#2.2x",
1851 address, opcode, mnemonic, Rd, imm);
1856 int evaluate_data_proc_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
1858 uint8_t high_reg, op, Rm, Rd,H1,H2;
1859 char *mnemonic = NULL;
1862 high_reg = (opcode & 0x0400) >> 10;
1863 op = (opcode & 0x03C0) >> 6;
1865 Rd = (opcode & 0x0007);
1866 Rm = (opcode & 0x0038) >> 3;
1867 H1 = (opcode & 0x0080) >> 7;
1868 H2 = (opcode & 0x0040) >> 6;
1870 instruction->info.data_proc.Rd = Rd;
1871 instruction->info.data_proc.Rn = Rd;
1872 instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP));
1873 instruction->info.data_proc.variant = 1 /*immediate shift*/;
1874 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1885 instruction->type = ARM_ADD;
1889 instruction->type = ARM_CMP;
1893 instruction->type = ARM_MOV;
1899 if ((opcode & 0x7) == 0x0)
1901 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1904 instruction->type = ARM_BLX;
1905 snprintf(instruction->text, 128,
1907 " 0x%4.4x \tBLX\tr%i",
1908 address, opcode, Rm);
1912 instruction->type = ARM_BX;
1913 snprintf(instruction->text, 128,
1915 " 0x%4.4x \tBX\tr%i",
1916 address, opcode, Rm);
1921 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1922 snprintf(instruction->text, 128,
1925 "UNDEFINED INSTRUCTION",
1937 instruction->type = ARM_AND;
1941 instruction->type = ARM_EOR;
1945 instruction->type = ARM_MOV;
1947 instruction->info.data_proc.variant = 2 /*register shift*/;
1948 instruction->info.data_proc.shifter_operand.register_shift.shift = 0;
1949 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1950 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1953 instruction->type = ARM_MOV;
1955 instruction->info.data_proc.variant = 2 /*register shift*/;
1956 instruction->info.data_proc.shifter_operand.register_shift.shift = 1;
1957 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1958 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1961 instruction->type = ARM_MOV;
1963 instruction->info.data_proc.variant = 2 /*register shift*/;
1964 instruction->info.data_proc.shifter_operand.register_shift.shift = 2;
1965 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1966 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1969 instruction->type = ARM_ADC;
1973 instruction->type = ARM_SBC;
1977 instruction->type = ARM_MOV;
1979 instruction->info.data_proc.variant = 2 /*register shift*/;
1980 instruction->info.data_proc.shifter_operand.register_shift.shift = 3;
1981 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
1982 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
1985 instruction->type = ARM_TST;
1989 instruction->type = ARM_RSB;
1991 instruction->info.data_proc.variant = 0 /*immediate*/;
1992 instruction->info.data_proc.shifter_operand.immediate.immediate = 0;
1993 instruction->info.data_proc.Rn = Rm;
1996 instruction->type = ARM_CMP;
2000 instruction->type = ARM_CMN;
2004 instruction->type = ARM_ORR;
2008 instruction->type = ARM_MUL;
2012 instruction->type = ARM_BIC;
2016 instruction->type = ARM_MVN;
2023 snprintf(instruction->text, 128,
2024 "0x%8.8" PRIx32 " 0x%4.4x \tNOP\t\t\t"
2026 address, opcode, mnemonic, Rd, Rm);
2028 snprintf(instruction->text, 128,
2029 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i",
2030 address, opcode, mnemonic, Rd, Rm);
2035 /* PC-relative data addressing is word-aligned even with Thumb */
2036 static inline uint32_t thumb_alignpc4(uint32_t addr)
2038 return (addr + 4) & ~3;
2041 int evaluate_load_literal_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2044 uint8_t Rd = (opcode >> 8) & 0x7;
2046 instruction->type = ARM_LDR;
2047 immediate = opcode & 0x000000ff;
2050 instruction->info.load_store.Rd = Rd;
2051 instruction->info.load_store.Rn = 15 /*PC*/;
2052 instruction->info.load_store.index_mode = 0; /*offset*/
2053 instruction->info.load_store.offset_mode = 0; /*immediate*/
2054 instruction->info.load_store.offset.offset = immediate;
2056 snprintf(instruction->text, 128,
2057 "0x%8.8" PRIx32 " 0x%4.4x \t"
2058 "LDR\tr%i, [pc, #%#" PRIx32 "]\t; %#8.8" PRIx32,
2059 address, opcode, Rd, immediate,
2060 thumb_alignpc4(address) + immediate);
2065 int evaluate_load_store_reg_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2067 uint8_t Rd = (opcode >> 0) & 0x7;
2068 uint8_t Rn = (opcode >> 3) & 0x7;
2069 uint8_t Rm = (opcode >> 6) & 0x7;
2070 uint8_t opc = (opcode >> 9) & 0x7;
2071 char *mnemonic = NULL;
2076 instruction->type = ARM_STR;
2080 instruction->type = ARM_STRH;
2084 instruction->type = ARM_STRB;
2088 instruction->type = ARM_LDRSB;
2092 instruction->type = ARM_LDR;
2096 instruction->type = ARM_LDRH;
2100 instruction->type = ARM_LDRB;
2104 instruction->type = ARM_LDRSH;
2109 snprintf(instruction->text, 128,
2110 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2111 address, opcode, mnemonic, Rd, Rn, Rm);
2113 instruction->info.load_store.Rd = Rd;
2114 instruction->info.load_store.Rn = Rn;
2115 instruction->info.load_store.index_mode = 0; /*offset*/
2116 instruction->info.load_store.offset_mode = 1; /*register*/
2117 instruction->info.load_store.offset.reg.Rm = Rm;
2122 int evaluate_load_store_imm_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2124 uint32_t offset = (opcode >> 6) & 0x1f;
2125 uint8_t Rd = (opcode >> 0) & 0x7;
2126 uint8_t Rn = (opcode >> 3) & 0x7;
2127 uint32_t L = opcode & (1 << 11);
2128 uint32_t B = opcode & (1 << 12);
2135 instruction->type = ARM_LDR;
2140 instruction->type = ARM_STR;
2144 if ((opcode&0xF000) == 0x8000)
2155 snprintf(instruction->text, 128,
2156 "0x%8.8" PRIx32 " 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32 "]",
2157 address, opcode, mnemonic, suffix, Rd, Rn, offset << shift);
2159 instruction->info.load_store.Rd = Rd;
2160 instruction->info.load_store.Rn = Rn;
2161 instruction->info.load_store.index_mode = 0; /*offset*/
2162 instruction->info.load_store.offset_mode = 0; /*immediate*/
2163 instruction->info.load_store.offset.offset = offset << shift;
2168 int evaluate_load_store_stack_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2170 uint32_t offset = opcode & 0xff;
2171 uint8_t Rd = (opcode >> 8) & 0x7;
2172 uint32_t L = opcode & (1 << 11);
2177 instruction->type = ARM_LDR;
2182 instruction->type = ARM_STR;
2186 snprintf(instruction->text, 128,
2187 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32 "]",
2188 address, opcode, mnemonic, Rd, offset*4);
2190 instruction->info.load_store.Rd = Rd;
2191 instruction->info.load_store.Rn = 13 /*SP*/;
2192 instruction->info.load_store.index_mode = 0; /*offset*/
2193 instruction->info.load_store.offset_mode = 0; /*immediate*/
2194 instruction->info.load_store.offset.offset = offset*4;
2199 int evaluate_add_sp_pc_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2201 uint32_t imm = opcode & 0xff;
2202 uint8_t Rd = (opcode >> 8) & 0x7;
2204 uint32_t SP = opcode & (1 << 11);
2207 instruction->type = ARM_ADD;
2220 snprintf(instruction->text, 128,
2221 "0x%8.8" PRIx32 " 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32,
2222 address, opcode, Rd, reg_name, imm * 4);
2224 instruction->info.data_proc.variant = 0 /* immediate */;
2225 instruction->info.data_proc.Rd = Rd;
2226 instruction->info.data_proc.Rn = Rn;
2227 instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
2232 int evaluate_adjust_stack_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2234 uint32_t imm = opcode & 0x7f;
2235 uint8_t opc = opcode & (1 << 7);
2241 instruction->type = ARM_SUB;
2246 instruction->type = ARM_ADD;
2250 snprintf(instruction->text, 128,
2251 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tSP, #%#" PRIx32,
2252 address, opcode, mnemonic, imm*4);
2254 instruction->info.data_proc.variant = 0 /* immediate */;
2255 instruction->info.data_proc.Rd = 13 /*SP*/;
2256 instruction->info.data_proc.Rn = 13 /*SP*/;
2257 instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
2262 int evaluate_breakpoint_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2264 uint32_t imm = opcode & 0xff;
2266 instruction->type = ARM_BKPT;
2268 snprintf(instruction->text, 128,
2269 "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32 "",
2270 address, opcode, imm);
2275 int evaluate_load_store_multiple_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2277 uint32_t reg_list = opcode & 0xff;
2278 uint32_t L = opcode & (1 << 11);
2279 uint32_t R = opcode & (1 << 8);
2280 uint8_t Rn = (opcode >> 8) & 7;
2281 uint8_t addr_mode = 0 /* IA */;
2285 char ptr_name[7] = "";
2288 if ((opcode & 0xf000) == 0xc000)
2289 { /* generic load/store multiple */
2294 instruction->type = ARM_LDM;
2296 if (opcode & (1 << Rn))
2301 instruction->type = ARM_STM;
2304 snprintf(ptr_name, sizeof ptr_name, "r%i%s, ", Rn, wback);
2311 instruction->type = ARM_LDM;
2314 reg_list |= (1 << 15) /*PC*/;
2318 instruction->type = ARM_STM;
2320 addr_mode = 3; /*DB*/
2322 reg_list |= (1 << 14) /*LR*/;
2326 reg_names_p = reg_names;
2327 for (i = 0; i <= 15; i++)
2329 if (reg_list & (1 << i))
2330 reg_names_p += snprintf(reg_names_p, (reg_names + 40 - reg_names_p), "r%i, ", i);
2332 if (reg_names_p > reg_names)
2333 reg_names_p[-2] = '\0';
2334 else /* invalid op : no registers */
2335 reg_names[0] = '\0';
2337 snprintf(instruction->text, 128,
2338 "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%s{%s}",
2339 address, opcode, mnemonic, ptr_name, reg_names);
2341 instruction->info.load_store_multiple.register_list = reg_list;
2342 instruction->info.load_store_multiple.Rn = Rn;
2343 instruction->info.load_store_multiple.addressing_mode = addr_mode;
2348 int evaluate_cond_branch_thumb(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2350 uint32_t offset = opcode & 0xff;
2351 uint8_t cond = (opcode >> 8) & 0xf;
2352 uint32_t target_address;
2356 instruction->type = ARM_SWI;
2357 snprintf(instruction->text, 128,
2358 "0x%8.8" PRIx32 " 0x%4.4x \tSVC\t%#2.2" PRIx32,
2359 address, opcode, offset);
2362 else if (cond == 0xe)
2364 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2365 snprintf(instruction->text, 128,
2366 "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION",
2371 /* sign extend 8-bit offset */
2372 if (offset & 0x00000080)
2373 offset = 0xffffff00 | offset;
2375 target_address = address + 4 + (offset << 1);
2377 snprintf(instruction->text, 128,
2378 "0x%8.8" PRIx32 " 0x%4.4x \tB%s\t%#8.8" PRIx32,
2380 arm_condition_strings[cond], target_address);
2382 instruction->type = ARM_B;
2383 instruction->info.b_bl_bx_blx.reg_operand = -1;
2384 instruction->info.b_bl_bx_blx.target_address = target_address;
2389 static int evaluate_cb_thumb(uint16_t opcode, uint32_t address,
2390 arm_instruction_t *instruction)
2394 /* added in Thumb2 */
2395 offset = (opcode >> 3) & 0x1f;
2396 offset |= (opcode & 0x0200) >> 4;
2398 snprintf(instruction->text, 128,
2399 "0x%8.8" PRIx32 " 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32,
2401 (opcode & 0x0800) ? "N" : "",
2402 opcode & 0x7, address + 4 + (offset << 1));
2407 static int evaluate_extend_thumb(uint16_t opcode, uint32_t address,
2408 arm_instruction_t *instruction)
2410 /* added in ARMv6 */
2411 snprintf(instruction->text, 128,
2412 "0x%8.8" PRIx32 " 0x%4.4x \t%cXT%c\tr%d, r%d",
2414 (opcode & 0x0080) ? 'U' : 'S',
2415 (opcode & 0x0040) ? 'B' : 'H',
2416 opcode & 0x7, (opcode >> 3) & 0x7);
2421 static int evaluate_cps_thumb(uint16_t opcode, uint32_t address,
2422 arm_instruction_t *instruction)
2424 /* added in ARMv6 */
2425 if ((opcode & 0x0ff0) == 0x0650)
2426 snprintf(instruction->text, 128,
2427 "0x%8.8" PRIx32 " 0x%4.4x \tSETEND %s",
2429 (opcode & 0x80) ? "BE" : "LE");
2430 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2431 snprintf(instruction->text, 128,
2432 "0x%8.8" PRIx32 " 0x%4.4x \tCPSI%c\t%s%s%s",
2434 (opcode & 0x0010) ? 'D' : 'E',
2435 (opcode & 0x0004) ? "A" : "",
2436 (opcode & 0x0002) ? "I" : "",
2437 (opcode & 0x0001) ? "F" : "");
2442 static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address,
2443 arm_instruction_t *instruction)
2447 /* added in ARMv6 */
2448 switch ((opcode >> 6) & 3) {
2459 snprintf(instruction->text, 128,
2460 "0x%8.8" PRIx32 " 0x%4.4x \tREV%s\tr%d, r%d",
2461 address, opcode, suffix,
2462 opcode & 0x7, (opcode >> 3) & 0x7);
2467 static int evaluate_hint_thumb(uint16_t opcode, uint32_t address,
2468 arm_instruction_t *instruction)
2472 switch ((opcode >> 4) & 0x0f) {
2489 hint = "HINT (UNRECOGNIZED)";
2493 snprintf(instruction->text, 128,
2494 "0x%8.8" PRIx32 " 0x%4.4x \t%s",
2495 address, opcode, hint);
2500 static int evaluate_ifthen_thumb(uint16_t opcode, uint32_t address,
2501 arm_instruction_t *instruction)
2503 unsigned cond = (opcode >> 4) & 0x0f;
2504 char *x = "", *y = "", *z = "";
2507 z = (opcode & 0x02) ? "T" : "E";
2509 y = (opcode & 0x04) ? "T" : "E";
2511 x = (opcode & 0x08) ? "T" : "E";
2513 snprintf(instruction->text, 128,
2514 "0x%8.8" PRIx32 " 0x%4.4x \tIT%s%s%s\t%s",
2516 x, y, z, arm_condition_strings[cond]);
2518 /* NOTE: strictly speaking, the next 1-4 instructions should
2519 * now be displayed with the relevant conditional suffix...
2525 int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
2527 /* clear fields, to avoid confusion */
2528 memset(instruction, 0, sizeof(arm_instruction_t));
2529 instruction->opcode = opcode;
2530 instruction->instruction_size = 2;
2532 if ((opcode & 0xe000) == 0x0000)
2534 /* add/substract register or immediate */
2535 if ((opcode & 0x1800) == 0x1800)
2536 return evaluate_add_sub_thumb(opcode, address, instruction);
2537 /* shift by immediate */
2539 return evaluate_shift_imm_thumb(opcode, address, instruction);
2542 /* Add/substract/compare/move immediate */
2543 if ((opcode & 0xe000) == 0x2000)
2545 return evaluate_data_proc_imm_thumb(opcode, address, instruction);
2548 /* Data processing instructions */
2549 if ((opcode & 0xf800) == 0x4000)
2551 return evaluate_data_proc_thumb(opcode, address, instruction);
2554 /* Load from literal pool */
2555 if ((opcode & 0xf800) == 0x4800)
2557 return evaluate_load_literal_thumb(opcode, address, instruction);
2560 /* Load/Store register offset */
2561 if ((opcode & 0xf000) == 0x5000)
2563 return evaluate_load_store_reg_thumb(opcode, address, instruction);
2566 /* Load/Store immediate offset */
2567 if (((opcode & 0xe000) == 0x6000)
2568 ||((opcode & 0xf000) == 0x8000))
2570 return evaluate_load_store_imm_thumb(opcode, address, instruction);
2573 /* Load/Store from/to stack */
2574 if ((opcode & 0xf000) == 0x9000)
2576 return evaluate_load_store_stack_thumb(opcode, address, instruction);
2580 if ((opcode & 0xf000) == 0xa000)
2582 return evaluate_add_sp_pc_thumb(opcode, address, instruction);
2586 if ((opcode & 0xf000) == 0xb000)
2588 switch ((opcode >> 8) & 0x0f) {
2590 return evaluate_adjust_stack_thumb(opcode, address, instruction);
2595 return evaluate_cb_thumb(opcode, address, instruction);
2597 return evaluate_extend_thumb(opcode, address, instruction);
2602 return evaluate_load_store_multiple_thumb(opcode, address,
2605 return evaluate_cps_thumb(opcode, address, instruction);
2607 if ((opcode & 0x00c0) == 0x0080)
2609 return evaluate_byterev_thumb(opcode, address, instruction);
2611 return evaluate_breakpoint_thumb(opcode, address, instruction);
2613 if (opcode & 0x000f)
2614 return evaluate_ifthen_thumb(opcode, address,
2617 return evaluate_hint_thumb(opcode, address,
2621 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2622 snprintf(instruction->text, 128,
2623 "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION",
2628 /* Load/Store multiple */
2629 if ((opcode & 0xf000) == 0xc000)
2631 return evaluate_load_store_multiple_thumb(opcode, address, instruction);
2634 /* Conditional branch + SWI */
2635 if ((opcode & 0xf000) == 0xd000)
2637 return evaluate_cond_branch_thumb(opcode, address, instruction);
2640 if ((opcode & 0xe000) == 0xe000)
2642 /* Undefined instructions */
2643 if ((opcode & 0xf801) == 0xe801)
2645 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2646 snprintf(instruction->text, 128,
2647 "0x%8.8" PRIx32 " 0x%8.8x\t"
2648 "UNDEFINED INSTRUCTION",
2653 { /* Branch to offset */
2654 return evaluate_b_bl_blx_thumb(opcode, address, instruction);
2658 LOG_ERROR("should never reach this point (opcode=%04x)",opcode);
2662 static int t2ev_b_bl(uint32_t opcode, uint32_t address,
2663 arm_instruction_t *instruction, char *cp)
2666 unsigned b21 = 1 << 21;
2667 unsigned b22 = 1 << 22;
2669 /* instead of combining two smaller 16-bit branch instructions,
2670 * Thumb2 uses only one larger 32-bit instruction.
2672 offset = opcode & 0x7ff;
2673 offset |= (opcode & 0x03ff0000) >> 5;
2674 if (opcode & (1 << 26)) {
2675 offset |= 0xff << 23;
2676 if ((opcode & (1 << 11)) == 0)
2678 if ((opcode & (1 << 13)) == 0)
2681 if (opcode & (1 << 11))
2683 if (opcode & (1 << 13))
2691 address += offset << 1;
2693 instruction->type = (opcode & (1 << 14)) ? ARM_BL : ARM_B;
2694 instruction->info.b_bl_bx_blx.reg_operand = -1;
2695 instruction->info.b_bl_bx_blx.target_address = address;
2696 sprintf(cp, "%s\t%#8.8" PRIx32,
2697 (opcode & (1 << 14)) ? "BL" : "B.W",
2703 static int t2ev_cond_b(uint32_t opcode, uint32_t address,
2704 arm_instruction_t *instruction, char *cp)
2707 unsigned b17 = 1 << 17;
2708 unsigned b18 = 1 << 18;
2709 unsigned cond = (opcode >> 22) & 0x0f;
2711 offset = opcode & 0x7ff;
2712 offset |= (opcode & 0x003f0000) >> 5;
2713 if (opcode & (1 << 26)) {
2714 offset |= 0xffff << 19;
2715 if ((opcode & (1 << 11)) == 0)
2717 if ((opcode & (1 << 13)) == 0)
2720 if (opcode & (1 << 11))
2722 if (opcode & (1 << 13))
2729 address += offset << 1;
2731 instruction->type = ARM_B;
2732 instruction->info.b_bl_bx_blx.reg_operand = -1;
2733 instruction->info.b_bl_bx_blx.target_address = address;
2734 sprintf(cp, "B%s.W\t%#8.8" PRIx32,
2735 arm_condition_strings[cond],
2741 static const char *special_name(int number)
2743 char *special = "(RESERVED)";
2774 special = "primask";
2777 special = "basepri";
2780 special = "basepri_max";
2783 special = "faultmask";
2786 special = "control";
2792 static int t2ev_hint(uint32_t opcode, uint32_t address,
2793 arm_instruction_t *instruction, char *cp)
2795 const char *mnemonic;
2797 if (opcode & 0x0700) {
2798 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2799 strcpy(cp, "UNDEFINED");
2803 if (opcode & 0x00f0) {
2804 sprintf(cp, "DBG\t#%d", (int) opcode & 0xf);
2808 switch (opcode & 0x0f) {
2813 mnemonic = "YIELD.W";
2825 mnemonic = "HINT.W (UNRECOGNIZED)";
2828 strcpy(cp, mnemonic);
2832 static int t2ev_misc(uint32_t opcode, uint32_t address,
2833 arm_instruction_t *instruction, char *cp)
2835 const char *mnemonic;
2837 switch ((opcode >> 4) & 0x0f) {
2851 return ERROR_INVALID_ARGUMENTS;
2853 strcpy(cp, mnemonic);
2857 static int t2ev_b_misc(uint32_t opcode, uint32_t address,
2858 arm_instruction_t *instruction, char *cp)
2860 /* permanently undefined */
2861 if ((opcode & 0x07f07000) == 0x07f02000) {
2862 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2863 strcpy(cp, "UNDEFINED");
2867 switch ((opcode >> 12) & 0x5) {
2870 return t2ev_b_bl(opcode, address, instruction, cp);
2874 if (((opcode >> 23) & 0x07) != 0x07)
2875 return t2ev_cond_b(opcode, address, instruction, cp);
2876 if (opcode & (1 << 26))
2881 switch ((opcode >> 20) & 0x7f) {
2884 sprintf(cp, "MSR\t%s, r%d", special_name(opcode & 0xff),
2885 (int) (opcode >> 16) & 0x0f);
2888 return t2ev_hint(opcode, address, instruction, cp);
2890 return t2ev_misc(opcode, address, instruction, cp);
2893 sprintf(cp, "MRS\tr%d, %s", (int) (opcode >> 8) & 0x0f,
2894 special_name(opcode & 0xff));
2899 return ERROR_INVALID_ARGUMENTS;
2902 static int t2ev_data_mod_immed(uint32_t opcode, uint32_t address,
2903 arm_instruction_t *instruction, char *cp)
2905 char *mnemonic = NULL;
2906 int rn = (opcode >> 16) & 0xf;
2907 int rd = (opcode >> 8) & 0xf;
2908 unsigned immed = opcode & 0xff;
2914 /* ARMv7-M: A5.3.2 Modified immediate constants */
2915 func = (opcode >> 11) & 0x0e;
2918 if (opcode & (1 << 26))
2921 /* "Modified" immediates */
2922 switch (func >> 1) {
2929 immed += immed << 16;
2932 immed += immed << 8;
2933 immed += immed << 16;
2937 immed = ror(immed, func);
2940 if (opcode & (1 << 20))
2943 switch ((opcode >> 21) & 0xf) {
2946 instruction->type = ARM_TST;
2952 instruction->type = ARM_AND;
2957 instruction->type = ARM_BIC;
2962 instruction->type = ARM_MOV;
2967 instruction->type = ARM_ORR;
2973 instruction->type = ARM_MVN;
2977 // instruction->type = ARM_ORN;
2983 instruction->type = ARM_TEQ;
2989 instruction->type = ARM_EOR;
2995 instruction->type = ARM_CMN;
3001 instruction->type = ARM_ADD;
3007 instruction->type = ARM_ADC;
3012 instruction->type = ARM_SBC;
3017 instruction->type = ARM_CMP;
3023 instruction->type = ARM_SUB;
3029 instruction->type = ARM_RSB;
3034 return ERROR_INVALID_ARGUMENTS;
3038 sprintf(cp, "%s%s\tr%d, #%d\t; %#8.8x",
3039 mnemonic, suffix2 ,rd, immed, immed);
3041 sprintf(cp, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3042 mnemonic, suffix, suffix2,
3043 rd, rn, immed, immed);
3048 static int t2ev_data_immed(uint32_t opcode, uint32_t address,
3049 arm_instruction_t *instruction, char *cp)
3051 char *mnemonic = NULL;
3052 int rn = (opcode >> 16) & 0xf;
3053 int rd = (opcode >> 8) & 0xf;
3056 bool is_signed = false;
3058 immed = (opcode & 0x0ff) | ((opcode & 0x7000) >> 4);
3059 if (opcode & (1 << 26))
3062 switch ((opcode >> 20) & 0x1f) {
3071 immed |= (opcode >> 4) & 0xf000;
3072 sprintf(cp, "MOVW\tr%d, #%d\t; %#3.3x", rd, immed, immed);
3080 /* move constant to top 16 bits of register */
3081 immed |= (opcode >> 4) & 0xf000;
3082 sprintf(cp, "MOVT\tr%d, #%d\t; %#4.4x", rn, immed, immed);
3089 /* signed/unsigned saturated add */
3090 immed = (opcode >> 6) & 0x03;
3091 immed |= (opcode >> 10) & 0x1c;
3092 sprintf(cp, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3093 is_signed ? "S" : "U",
3094 rd, (int) (opcode & 0x1f) + is_signed, rn,
3095 (opcode & (1 << 21)) ? "ASR" : "LSL",
3096 immed ? immed : 32);
3102 /* signed/unsigned bitfield extract */
3103 immed = (opcode >> 6) & 0x03;
3104 immed |= (opcode >> 10) & 0x1c;
3105 sprintf(cp, "%sBFX\tr%d, r%d, #%d, #%d\t",
3106 is_signed ? "S" : "U",
3108 (int) (opcode & 0x1f) + 1);
3111 immed = (opcode >> 6) & 0x03;
3112 immed |= (opcode >> 10) & 0x1c;
3113 if (rn == 0xf) /* bitfield clear */
3114 sprintf(cp, "BFC\tr%d, #%d, #%d\t",
3116 (int) (opcode & 0x1f) + 1 - immed);
3117 else /* bitfield insert */
3118 sprintf(cp, "BFI\tr%d, r%d, #%d, #%d\t",
3120 (int) (opcode & 0x1f) + 1 - immed);
3123 return ERROR_INVALID_ARGUMENTS;
3126 sprintf(cp, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic,
3127 rd, rn, immed, immed);
3131 address = thumb_alignpc4(address);
3136 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3137 * not hiding the pc-relative stuff will sometimes be useful.
3139 sprintf(cp, "ADR.W\tr%d, %#8.8" PRIx32, rd, address);
3143 static int t2ev_store_single(uint32_t opcode, uint32_t address,
3144 arm_instruction_t *instruction, char *cp)
3146 unsigned op = (opcode >> 20) & 0xf;
3152 unsigned rn = (opcode >> 16) & 0x0f;
3153 unsigned rt = (opcode >> 12) & 0x0f;
3156 return ERROR_INVALID_ARGUMENTS;
3158 if (opcode & 0x0800)
3193 return ERROR_INVALID_ARGUMENTS;
3196 sprintf(cp, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3197 size, rt, rn, (int) opcode & 0x0f,
3198 (int) (opcode >> 4) & 0x03);
3202 immed = opcode & 0x0fff;
3203 sprintf(cp, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3204 size, rt, rn, immed, immed);
3208 immed = opcode & 0x00ff;
3210 switch (opcode & 0x700) {
3216 return ERROR_INVALID_ARGUMENTS;
3219 /* two indexed modes will write back rn */
3220 if (opcode & 0x100) {
3221 if (opcode & 0x400) /* pre-indexed */
3223 else { /* post-indexed */
3229 sprintf(cp, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3230 size, suffix, rt, rn, p1,
3231 (opcode & 0x200) ? "" : "-",
3236 static int t2ev_mul32(uint32_t opcode, uint32_t address,
3237 arm_instruction_t *instruction, char *cp)
3239 int ra = (opcode >> 12) & 0xf;
3241 switch (opcode & 0x007000f0) {
3244 sprintf(cp, "MUL\tr%d, r%d, r%d",
3245 (int) (opcode >> 8) & 0xf,
3246 (int) (opcode >> 16) & 0xf,
3247 (int) (opcode >> 0) & 0xf);
3249 sprintf(cp, "MLA\tr%d, r%d, r%d, r%d",
3250 (int) (opcode >> 8) & 0xf,
3251 (int) (opcode >> 16) & 0xf,
3252 (int) (opcode >> 0) & 0xf, ra);
3255 sprintf(cp, "MLS\tr%d, r%d, r%d, r%d",
3256 (int) (opcode >> 8) & 0xf,
3257 (int) (opcode >> 16) & 0xf,
3258 (int) (opcode >> 0) & 0xf, ra);
3261 return ERROR_INVALID_ARGUMENTS;
3266 static int t2ev_mul64_div(uint32_t opcode, uint32_t address,
3267 arm_instruction_t *instruction, char *cp)
3269 int op = (opcode >> 4) & 0xf;
3270 char *infix = "MUL";
3272 op += (opcode >> 16) & 0x70;
3280 sprintf(cp, "%c%sL\tr%d, r%d, r%d, r%d",
3281 (op & 0x20) ? 'U' : 'S',
3283 (int) (opcode >> 12) & 0xf,
3284 (int) (opcode >> 8) & 0xf,
3285 (int) (opcode >> 16) & 0xf,
3286 (int) (opcode >> 0) & 0xf);
3290 sprintf(cp, "%cDIV\tr%d, r%d, r%d",
3291 (op & 0x20) ? 'U' : 'S',
3292 (int) (opcode >> 8) & 0xf,
3293 (int) (opcode >> 16) & 0xf,
3294 (int) (opcode >> 0) & 0xf);
3297 return ERROR_INVALID_ARGUMENTS;
3303 static int t2ev_ldm_stm(uint32_t opcode, uint32_t address,
3304 arm_instruction_t *instruction, char *cp)
3306 int rn = (opcode >> 16) & 0xf;
3307 int op = (opcode >> 22) & 0x6;
3308 int t = (opcode >> 21) & 1;
3309 unsigned registers = opcode & 0xffff;
3311 if (opcode & (1 << 20))
3316 sprintf(cp, "STM.W\tr%d%s, ", rn, t ? "!" : "");
3320 sprintf(cp, "POP.W\t");
3322 sprintf(cp, "LDM.W\tr%d%s, ", rn, t ? "!" : "");
3326 sprintf(cp, "PUSH.W\t");
3328 sprintf(cp, "STMDB\tr%d%s, ", rn, t ? "!" : "");
3331 sprintf(cp, "LDMDB.W\tr%d%s, ", rn, t ? "!" : "");
3334 return ERROR_INVALID_ARGUMENTS;
3339 for (t = 0; registers; t++, registers >>= 1) {
3340 if ((registers & 1) == 0)
3343 sprintf(cp, "r%d%s", t, registers ? ", " : "");
3352 /* load/store dual or exclusive, table branch */
3353 static int t2ev_ldrex_strex(uint32_t opcode, uint32_t address,
3354 arm_instruction_t *instruction, char *cp)
3356 unsigned op1op2 = (opcode >> 20) & 0x3;
3357 unsigned op3 = (opcode >> 4) & 0xf;
3359 unsigned rn = (opcode >> 16) & 0xf;
3360 unsigned rt = (opcode >> 12) & 0xf;
3361 unsigned rd = (opcode >> 8) & 0xf;
3362 unsigned imm = opcode & 0xff;
3366 op1op2 |= (opcode >> 21) & 0xc;
3396 mnemonic = "STREXB";
3399 mnemonic = "STREXH";
3402 return ERROR_INVALID_ARGUMENTS;
3410 sprintf(cp, "TBB\t[r%u, r%u]", rn, imm & 0xf);
3413 sprintf(cp, "TBH\t[r%u, r%u, LSL #1]", rn, imm & 0xf);
3416 mnemonic = "LDREXB";
3419 mnemonic = "LDREXH";
3422 return ERROR_INVALID_ARGUMENTS;
3427 return ERROR_INVALID_ARGUMENTS;
3432 sprintf(cp, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3433 mnemonic, rd, rt, rn, imm, imm);
3435 sprintf(cp, "%s\tr%u, r%u, [r%u]",
3436 mnemonic, rd, rt, rn);
3442 sprintf(cp, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3443 mnemonic, rt, rn, imm, imm);
3445 sprintf(cp, "%s\tr%u, [r%u]",
3450 /* two indexed modes will write back rn */
3451 if (opcode & (1 << 21)) {
3452 if (opcode & (1 << 24)) /* pre-indexed */
3454 else { /* post-indexed */
3461 sprintf(cp, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3462 mnemonic, rt, rd, rn, p1,
3463 (opcode & (1 << 23)) ? "" : "-",
3468 address = thumb_alignpc4(address);
3470 if (opcode & (1 << 23))
3474 sprintf(cp, "%s\tr%u, r%u, %#8.8" PRIx32,
3475 mnemonic, rt, rd, address);
3479 static int t2ev_data_shift(uint32_t opcode, uint32_t address,
3480 arm_instruction_t *instruction, char *cp)
3482 int op = (opcode >> 21) & 0xf;
3483 int rd = (opcode >> 8) & 0xf;
3484 int rn = (opcode >> 16) & 0xf;
3485 int type = (opcode >> 4) & 0x3;
3486 int immed = (opcode >> 6) & 0x3;
3490 immed |= (opcode >> 10) & 0x1c;
3491 if (opcode & (1 << 20))
3497 if (!(opcode & (1 << 20)))
3498 return ERROR_INVALID_ARGUMENTS;
3499 instruction->type = ARM_TST;
3504 instruction->type = ARM_AND;
3508 instruction->type = ARM_BIC;
3513 instruction->type = ARM_MOV;
3517 sprintf(cp, "MOV%s.W\tr%d, r%d",
3519 (int) (opcode & 0xf));
3532 sprintf(cp, "RRX%s\tr%d, r%d",
3534 (int) (opcode & 0xf));
3542 instruction->type = ARM_ORR;
3548 instruction->type = ARM_MVN;
3553 // instruction->type = ARM_ORN;
3559 if (!(opcode & (1 << 20)))
3560 return ERROR_INVALID_ARGUMENTS;
3561 instruction->type = ARM_TEQ;
3566 instruction->type = ARM_EOR;
3571 if (!(opcode & (1 << 20)))
3572 return ERROR_INVALID_ARGUMENTS;
3573 instruction->type = ARM_CMN;
3578 instruction->type = ARM_ADD;
3582 instruction->type = ARM_ADC;
3586 instruction->type = ARM_SBC;
3591 if (!(opcode & (1 << 21)))
3592 return ERROR_INVALID_ARGUMENTS;
3593 instruction->type = ARM_CMP;
3598 instruction->type = ARM_SUB;
3602 instruction->type = ARM_RSB;
3606 return ERROR_INVALID_ARGUMENTS;
3609 sprintf(cp, "%s%s.W\tr%d, r%d, r%d",
3610 mnemonic, suffix, rd, rn, (int) (opcode & 0xf));
3633 strcpy(cp, ", RRX");
3639 sprintf(cp, ", %s #%d", suffix, immed ? immed : 32);
3643 sprintf(cp, "%s%s.W\tr%d, r%d",
3644 mnemonic, suffix, rn, (int) (opcode & 0xf));
3648 sprintf(cp, "%s%s.W\tr%d, r%d, #%d",
3649 mnemonic, suffix, rd,
3650 (int) (opcode & 0xf), immed ? immed : 32);
3654 static int t2ev_data_reg(uint32_t opcode, uint32_t address,
3655 arm_instruction_t *instruction, char *cp)
3660 if (((opcode >> 4) & 0xf) == 0) {
3661 switch ((opcode >> 21) & 0x7) {
3675 return ERROR_INVALID_ARGUMENTS;
3678 instruction->type = ARM_MOV;
3679 if (opcode & (1 << 20))
3681 sprintf(cp, "%s%s.W\tr%d, r%d, r%d",
3683 (int) (opcode >> 8) & 0xf,
3684 (int) (opcode >> 16) & 0xf,
3685 (int) (opcode >> 0) & 0xf);
3687 } else if (opcode & (1 << 7)) {
3688 switch ((opcode >> 20) & 0xf) {
3693 switch ((opcode >> 4) & 0x3) {
3695 suffix = ", ROR #8";
3698 suffix = ", ROR #16";
3701 suffix = ", ROR #24";
3704 sprintf(cp, "%cXT%c.W\tr%d, r%d%s",
3705 (opcode & (1 << 24)) ? 'U' : 'S',
3706 (opcode & (1 << 26)) ? 'B' : 'H',
3707 (int) (opcode >> 8) & 0xf,
3708 (int) (opcode >> 0) & 0xf,
3715 if (opcode & (1 << 6))
3716 return ERROR_INVALID_ARGUMENTS;
3717 if (((opcode >> 12) & 0xf) != 0xf)
3718 return ERROR_INVALID_ARGUMENTS;
3719 if (!(opcode & (1 << 20)))
3720 return ERROR_INVALID_ARGUMENTS;
3722 switch (((opcode >> 19) & 0x04)
3723 | ((opcode >> 4) & 0x3)) {
3728 mnemonic = "REV16.W";
3734 mnemonic = "REVSH.W";
3740 return ERROR_INVALID_ARGUMENTS;
3742 sprintf(cp, "%s\tr%d, r%d",
3744 (int) (opcode >> 8) & 0xf,
3745 (int) (opcode >> 0) & 0xf);
3748 return ERROR_INVALID_ARGUMENTS;
3755 static int t2ev_load_word(uint32_t opcode, uint32_t address,
3756 arm_instruction_t *instruction, char *cp)
3758 int rn = (opcode >> 16) & 0xf;
3761 instruction->type = ARM_LDR;
3764 immed = opcode & 0x0fff;
3765 if ((opcode & (1 << 23)) == 0)
3767 sprintf(cp, "LDR\tr%d, %#8.8" PRIx32,
3768 (int) (opcode >> 12) & 0xf,
3769 thumb_alignpc4(address) + immed);
3773 if (opcode & (1 << 23)) {
3774 immed = opcode & 0x0fff;
3775 sprintf(cp, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3776 (int) (opcode >> 12) & 0xf,
3781 if (!(opcode & (0x3f << 6))) {
3782 sprintf(cp, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3783 (int) (opcode >> 12) & 0xf,
3785 (int) (opcode >> 0) & 0xf,
3786 (int) (opcode >> 4) & 0x3);
3791 if (((opcode >> 8) & 0xf) == 0xe) {
3792 immed = opcode & 0x00ff;
3794 sprintf(cp, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3795 (int) (opcode >> 12) & 0xf,
3800 if (((opcode >> 8) & 0xf) == 0xc || (opcode & 0x0900) == 0x0900) {
3801 char *p1 = "]", *p2 = "";
3803 if (!(opcode & 0x0500))
3804 return ERROR_INVALID_ARGUMENTS;
3806 immed = opcode & 0x00ff;
3808 /* two indexed modes will write back rn */
3809 if (opcode & 0x100) {
3810 if (opcode & 0x400) /* pre-indexed */
3812 else { /* post-indexed */
3818 sprintf(cp, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3819 (int) (opcode >> 12) & 0xf,
3821 (opcode & 0x200) ? "" : "-",
3826 return ERROR_INVALID_ARGUMENTS;
3829 static int t2ev_load_byte_hints(uint32_t opcode, uint32_t address,
3830 arm_instruction_t *instruction, char *cp)
3832 int rn = (opcode >> 16) & 0xf;
3833 int rt = (opcode >> 12) & 0xf;
3834 int op2 = (opcode >> 6) & 0x3f;
3836 char *p1 = "", *p2 = "]";
3839 switch ((opcode >> 23) & 0x3) {
3841 if ((rn & rt) == 0xf) {
3843 immed = opcode & 0xfff;
3844 address = thumb_alignpc4(address);
3845 if (opcode & (1 << 23))
3849 sprintf(cp, "PLD\tr%d, %#8.8" PRIx32,
3853 if (rn == 0x0f && rt != 0x0f) {
3855 immed = opcode & 0xfff;
3856 address = thumb_alignpc4(address);
3857 if (opcode & (1 << 23))
3861 sprintf(cp, "LDRB\tr%d, %#8.8" PRIx32,
3867 if ((op2 & 0x3c) == 0x38) {
3868 immed = opcode & 0xff;
3869 sprintf(cp, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
3870 rt, rn, immed, immed);
3873 if ((op2 & 0x3c) == 0x30) {
3875 immed = opcode & 0xff;
3878 p1 = (opcode & (1 << 21)) ? "W" : "";
3879 sprintf(cp, "PLD%s\t[r%d, #%d]\t; %#6.6x",
3880 p1, rn, immed, immed);
3885 immed = opcode & 0xff;
3886 if (!(opcode & 0x200))
3889 /* two indexed modes will write back rn */
3890 if (opcode & 0x100) {
3891 if (opcode & 0x400) /* pre-indexed */
3893 else { /* post-indexed */
3899 sprintf(cp, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
3900 mnemonic, rt, rn, p1,
3904 if ((op2 & 0x24) == 0x24) {
3906 goto ldrxb_immediate_t3;
3909 int rm = opcode & 0xf;
3912 sprintf(cp, "PLD\t");
3914 sprintf(cp, "LDRB.W\tr%d, ", rt);
3915 immed = (opcode >> 4) & 0x3;
3917 sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed);
3922 if ((rn & rt) == 0xf)
3925 immed = opcode & 0xfff;
3926 goto preload_immediate;
3930 mnemonic = "LDRB.W";
3931 immed = opcode & 0xfff;
3932 goto ldrxb_immediate_t2;
3934 if ((rn & rt) == 0xf) {
3935 immed = opcode & 0xfff;
3936 address = thumb_alignpc4(address);
3937 if (opcode & (1 << 23))
3941 sprintf(cp, "PLI\t%#8.8" PRIx32, address);
3944 if (rn == 0xf && rt != 0xf) {
3946 immed = opcode & 0xfff;
3947 address = thumb_alignpc4(address);
3948 if (opcode & (1 << 23))
3952 sprintf(cp, "LDRSB\t%#8.8" PRIx32, address);
3957 if ((op2 & 0x3c) == 0x38) {
3958 immed = opcode & 0xff;
3959 sprintf(cp, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
3960 rt, rn, immed, immed);
3963 if ((op2 & 0x3c) == 0x30) {
3965 immed = opcode & 0xff;
3966 immed = -immed; // pli
3967 sprintf(cp, "PLI\t[r%d, #%d]\t; -%#2.2x",
3972 goto ldrxb_immediate_t3;
3974 if ((op2 & 0x24) == 0x24) {
3976 goto ldrxb_immediate_t3;
3979 int rm = opcode & 0xf;
3982 sprintf(cp, "PLI\t");
3984 sprintf(cp, "LDRSB.W\tr%d, ", rt);
3985 immed = (opcode >> 4) & 0x3;
3987 sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed);
3993 immed = opcode & 0xfff;
3994 sprintf(cp, "PLI\t[r%d, #%d]\t; %#3.3x",
4000 immed = opcode & 0xfff;
4002 goto ldrxb_immediate_t2;
4005 return ERROR_INVALID_ARGUMENTS;
4008 static int t2ev_load_halfword(uint32_t opcode, uint32_t address,
4009 arm_instruction_t *instruction, char *cp)
4011 int rn = (opcode >> 16) & 0xf;
4012 int rt = (opcode >> 12) & 0xf;
4013 int op2 = (opcode >> 6) & 0x3f;
4018 sprintf(cp, "HINT (UNALLOCATED)");
4022 if (opcode & (1 << 24))
4025 if ((opcode & (1 << 23)) == 0) {
4028 immed = opcode & 0xfff;
4029 address = thumb_alignpc4(address);
4030 if (opcode & (1 << 23))
4034 sprintf(cp, "LDR%sH\tr%d, %#8.8" PRIx32,
4039 int rm = opcode & 0xf;
4041 immed = (opcode >> 4) & 0x3;
4042 sprintf(cp, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4043 sign, rt, rn, rm, immed);
4046 if ((op2 & 0x3c) == 0x38) {
4047 immed = opcode & 0xff;
4048 sprintf(cp, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4049 sign, rt, rn, immed, immed);
4052 if ((op2 & 0x3c) == 0x30 || (op2 & 0x24) == 0x24) {
4053 char *p1 = "", *p2 = "]";
4055 immed = opcode & 0xff;
4056 if (!(opcode & 0x200))
4059 /* two indexed modes will write back rn */
4060 if (opcode & 0x100) {
4061 if (opcode & 0x400) /* pre-indexed */
4063 else { /* post-indexed */
4068 sprintf(cp, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4069 sign, rt, rn, p1, immed, p2, immed);
4076 immed = opcode & 0xfff;
4077 sprintf(cp, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4078 sign, *sign ? "" : ".W",
4079 rt, rn, immed, immed);
4083 return ERROR_INVALID_ARGUMENTS;
4087 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4088 * always set. That means eventual arm_simulate_step() support for Thumb2
4089 * will need work in this area.
4091 int thumb2_opcode(target_t *target, uint32_t address, arm_instruction_t *instruction)
4098 /* clear low bit ... it's set on function pointers */
4101 /* clear fields, to avoid confusion */
4102 memset(instruction, 0, sizeof(arm_instruction_t));
4104 /* read first halfword, see if this is the only one */
4105 retval = target_read_u16(target, address, &op);
4106 if (retval != ERROR_OK)
4109 switch (op & 0xf800) {
4113 /* 32-bit instructions */
4114 instruction->instruction_size = 4;
4116 retval = target_read_u16(target, address + 2, &op);
4117 if (retval != ERROR_OK)
4120 instruction->opcode = opcode;
4123 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4124 return thumb_evaluate_opcode(op, address, instruction);
4127 snprintf(instruction->text, 128,
4128 "0x%8.8" PRIx32 " 0x%8.8" PRIx32 "\t",
4130 cp = strchr(instruction->text, 0);
4131 retval = ERROR_FAIL;
4133 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4134 if ((opcode & 0x1a008000) == 0x10000000)
4135 retval = t2ev_data_mod_immed(opcode, address, instruction, cp);
4137 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4138 else if ((opcode & 0x1a008000) == 0x12000000)
4139 retval = t2ev_data_immed(opcode, address, instruction, cp);
4141 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4142 else if ((opcode & 0x18008000) == 0x10008000)
4143 retval = t2ev_b_misc(opcode, address, instruction, cp);
4145 /* ARMv7-M: A5.3.5 Load/store multiple */
4146 else if ((opcode & 0x1e400000) == 0x08000000)
4147 retval = t2ev_ldm_stm(opcode, address, instruction, cp);
4149 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4150 else if ((opcode & 0x1e400000) == 0x08400000)
4151 retval = t2ev_ldrex_strex(opcode, address, instruction, cp);
4153 /* ARMv7-M: A5.3.7 Load word */
4154 else if ((opcode & 0x1f700000) == 0x18500000)
4155 retval = t2ev_load_word(opcode, address, instruction, cp);
4157 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4158 else if ((opcode & 0x1e700000) == 0x18300000)
4159 retval = t2ev_load_halfword(opcode, address, instruction, cp);
4161 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4162 else if ((opcode & 0x1e700000) == 0x18100000)
4163 retval = t2ev_load_byte_hints(opcode, address, instruction, cp);
4165 /* ARMv7-M: A5.3.10 Store single data item */
4166 else if ((opcode & 0x1f100000) == 0x18000000)
4167 retval = t2ev_store_single(opcode, address, instruction, cp);
4169 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4170 else if ((opcode & 0x1e000000) == 0x0a000000)
4171 retval = t2ev_data_shift(opcode, address, instruction, cp);
4173 /* ARMv7-M: A5.3.12 Data processing (register)
4174 * and A5.3.13 Miscellaneous operations
4176 else if ((opcode & 0x1f000000) == 0x1a000000)
4177 retval = t2ev_data_reg(opcode, address, instruction, cp);
4179 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4180 else if ((opcode & 0x1f800000) == 0x1b000000)
4181 retval = t2ev_mul32(opcode, address, instruction, cp);
4183 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4184 else if ((opcode & 0x1f800000) == 0x1b800000)
4185 retval = t2ev_mul64_div(opcode, address, instruction, cp);
4187 if (retval == ERROR_OK)
4191 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4192 * instructions; not yet handled here.
4195 if (retval == ERROR_INVALID_ARGUMENTS) {
4196 instruction->type = ARM_UNDEFINED_INSTRUCTION;
4197 strcpy(cp, "UNDEFINED OPCODE");
4201 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32 ")",
4204 strcpy(cp, "(32-bit Thumb2 ...)");
4208 int arm_access_size(arm_instruction_t *instruction)
4210 if ((instruction->type == ARM_LDRB)
4211 || (instruction->type == ARM_LDRBT)
4212 || (instruction->type == ARM_LDRSB)
4213 || (instruction->type == ARM_STRB)
4214 || (instruction->type == ARM_STRBT))
4218 else if ((instruction->type == ARM_LDRH)
4219 || (instruction->type == ARM_LDRSH)
4220 || (instruction->type == ARM_STRH))
4224 else if ((instruction->type == ARM_LDR)
4225 || (instruction->type == ARM_LDRT)
4226 || (instruction->type == ARM_STR)
4227 || (instruction->type == ARM_STRT))
4231 else if ((instruction->type == ARM_LDRD)
4232 || (instruction->type == ARM_STRD))
4238 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction->type);