- the 'help' command now takes an optional argument to display help only on a certain...
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 12 Jun 2006 16:49:49 +0000 (16:49 +0000)
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 12 Jun 2006 16:49:49 +0000 (16:49 +0000)
- OpenOCD now includes the ability to diassemble instructions on its own (only ARM for now, Thumb might follow).
The command is "armv4_5 disassemble <address> <count> ['thumb']" (thumb is currently unsupported).
I've compared the produced disassembly against GDB/GNU Objdump output, and it seems to be correct, but there may still be some bugs left.

git-svn-id: svn://svn.berlios.de/openocd/trunk@68 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/helper/command.c
src/target/Makefile.am
src/target/arm_disassembler.c [new file with mode: 0644]
src/target/arm_disassembler.h [new file with mode: 0644]
src/target/armv4_5.c

index 00d4b356150abe31a5ea40b82847a8fa490617b0..9fc78422c7c52d6da74cccf718bb8940f53726f1 100644 (file)
@@ -443,6 +443,15 @@ int command_print_help(command_context_t* context, char* name, char** args, int
 
        for (c = context->commands; c; c = c->next)
        {
+               if (argc == 1)
+               {
+                        if (strncasecmp(c->name, args[0], c->unique_len))
+                                continue;
+
+                        if (strncasecmp(c->name, args[0], strlen(args[0])))
+                                continue;
+               } 
+
                command_print_help_line(context, c, 0);
        }
        
index 7e26762b4bebc770125b320e3068cb719e42cec6..2192469c3e0db542c85839919a15986a09cc2ef7 100644 (file)
@@ -2,6 +2,7 @@ INCLUDES = -I$(top_srcdir)/src/gdb -I$(top_srcdir)/src/helper   -I$(top_srcdir)/s
 METASOURCES = AUTO
 noinst_LIBRARIES = libtarget.a
 libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \
-       arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c
+       arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c arm_disassembler.c
 noinst_HEADERS = target.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \
-               arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h
+               arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h \
+               arm_disassembler.h
diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c
new file mode 100644 (file)
index 0000000..6e76cf3
--- /dev/null
@@ -0,0 +1,1209 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#include "arm_disassembler.h"
+
+#include "log.h"
+
+#include <strings.h>
+
+/* textual represenation of the condition field */
+/* ALways (default) is ommitted (empty string) */
+char *arm_condition_strings[] =
+{
+       "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
+};
+
+/* make up for C's missing ROR */
+u32 ror(u32 value, int places) 
+{ 
+       return (value >> places) | (value << (32 - places)); 
+}
+
+int evaluate_pld(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       /* PLD */
+       if ((opcode & 0x0d70f0000) == 0x0550f000)
+       {
+               instruction->type = ARM_PLD;
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tPLD ...TODO...", address, opcode);
+               
+               return ERROR_OK;
+       }
+       else
+       {
+               instruction->type = ARM_UNDEFINED_INSTRUCTION;
+               return ERROR_OK;
+       }
+       
+       ERROR("should never reach this point");
+       return -1;
+}
+
+int evaluate_swi(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       instruction->type = ARM_SWI;
+       
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSWI 0x%6.6x", address, opcode, (opcode & 0xffffff));
+       
+       return ERROR_OK;
+}
+
+int evaluate_blx_imm(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       int offset;
+       u32 immediate;
+       
+       instruction->type = ARM_BLX;
+       immediate = opcode & 0x00ffffff;
+       
+       /* sign extend 24-bit immediate */
+       if (immediate & 0x00800000)
+               offset = 0xff000000 | immediate;
+       else
+               offset = immediate;
+       
+       /* shift two bits left */
+       offset <<= 2;
+       
+       /* odd/event halfword */
+       if (opcode & 0x01000000)
+               offset |= 0x2;
+       
+       instruction->target_address = address + 8 + offset;
+       
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBLX 0x%8.8x", address, opcode, instruction->target_address);
+       
+       return ERROR_OK;
+}
+
+int evaluate_b_bl(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 L;
+       u32 immediate;
+       int offset;
+       
+       immediate = opcode & 0x00ffffff;
+       L = (opcode & 0x01000000) >> 24;
+       
+       /* sign extend 24-bit immediate */
+       if (immediate & 0x00800000)
+               offset = 0xff000000 | immediate;
+       else
+               offset = immediate;
+       
+       /* shift two bits left */
+       offset <<= 2;
+       
+       instruction->target_address = address + 8 + offset;
+
+       if (L)
+               instruction->type = ARM_BL;
+       else
+               instruction->type = ARM_B;
+       
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tB%s%s 0x%8.8x", address, opcode,
+                        (L) ? "L" : "", COND(opcode), instruction->target_address);
+       
+       return ERROR_OK;
+}
+
+/* Coprocessor load/store and double register transfers */
+/* both normal and extended instruction space (condition field b1111) */
+int evaluate_ldc_stc_mcrr_mrrc(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 cp_num = (opcode & 0xf00) >> 8;
+       
+       /* MCRR or MRRC */
+       if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c400000))
+       {
+               u8 cp_opcode, Rd, Rn, CRm;
+               char *mnemonic;
+               
+               cp_opcode = (opcode & 0xf0) >> 4;
+               Rd = (opcode & 0xf000) >> 12;
+               Rn = (opcode & 0xf0000) >> 16;
+               CRm = (opcode & 0xf);
+               
+               /* MCRR */
+               if ((opcode & 0x0ff00000) == 0x0c400000)
+               {
+                       instruction->type = ARM_MCRR;
+                       mnemonic = "MCRR";
+               }
+               
+               /* MRRC */
+               if ((opcode & 0x0ff00000) == 0x0c500000)
+               {
+                       instruction->type = ARM_MRRC;
+                       mnemonic = "MRRC";
+               }
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, %x, r%i, r%i, c%i",
+                                address, opcode, mnemonic, COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm);
+       }
+       else /* LDC or STC */
+       {
+               u8 CRd, Rn, offset;
+               u8 U, N;
+               char *mnemonic;
+               char addressing_mode[32];
+               
+               CRd = (opcode & 0xf000) >> 12;
+               Rn = (opcode & 0xf0000) >> 16;
+               offset = (opcode & 0xff);
+               
+               /* load/store */
+               if (opcode & 0x00100000)
+               {
+                       instruction->type = ARM_LDC;
+                       mnemonic = "LDC";
+               }
+               else
+               {
+                       instruction->type = ARM_STC;
+                       mnemonic = "STC";
+               }
+               
+               U = (opcode & 0x00800000) >> 23;
+               N = (opcode & 0x00400000) >> 22;
+               
+               /* addressing modes */
+               if ((opcode & 0x01200000) == 0x01000000) /* immediate offset */
+                       snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]", Rn, (U) ? "" : "-", offset);
+               else if ((opcode & 0x01200000) == 0x01200000) /* immediate pre-indexed */
+                       snprintf(addressing_mode, 32, "[r%i, #%s0x%2.2x*4]!", Rn, (U) ? "" : "-", offset);
+               else if ((opcode & 0x01200000) == 0x00200000) /* immediate post-indexed */
+                       snprintf(addressing_mode, 32, "[r%i], #%s0x%2.2x*4", Rn, (U) ? "" : "-", offset);
+               else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */
+                       snprintf(addressing_mode, 32, "[r%i], #0x%2.2x", Rn, offset);
+
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s p%i, c%i, %s",
+                                address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? COND(opcode) : "2",
+                                (N) ? "L" : "",
+                                cp_num, CRd, addressing_mode);
+       }
+       
+       return ERROR_OK;
+}
+
+/* Coprocessor data processing instructions */
+/* Coprocessor register transfer instructions */
+/* both normal and extended instruction space (condition field b1111) */
+int evaluate_cdp_mcr_mrc(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       char* cond;
+       char* mnemonic;
+       u8 cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2;
+       
+       cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode);
+       cp_num = (opcode & 0xf00) >> 8;
+       CRd_Rd = (opcode & 0xf000) >> 12;
+       CRn = (opcode & 0xf0000) >> 16;
+       CRm = (opcode & 0xf);
+       opcode_2 = (opcode & 0xe0) >> 5;
+       
+       /* CDP or MRC/MCR */
+       if (opcode & 0x00000010) /* bit 4 set -> MRC/MCR */
+       {
+               if (opcode & 0x00100000) /* bit 20 set -> MRC */
+               {
+                       instruction->type = ARM_MRC;
+                       mnemonic = "MRC";
+               }
+               else /* bit 20 not set -> MCR */
+               {
+                       instruction->type = ARM_MCR;
+                       mnemonic = "MCR";
+               }
+               
+               opcode_1 = (opcode & 0x00e00000) >> 21;
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
+                                address, opcode, mnemonic, cond,
+                                cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
+       }
+       else /* bit 4 not set -> CDP */
+       {
+               instruction->type = ARM_CDP;
+               mnemonic = "CDP";
+               
+               opcode_1 = (opcode & 0x00f00000) >> 20;
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
+                                address, opcode, mnemonic, cond,
+                                cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2);
+       }
+       
+       return ERROR_OK;
+}
+
+/* Load/store instructions */
+int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 I, P, U, B, W, L;
+       u8 Rn, Rd;
+       char *operation; /* "LDR" or "STR" */
+       char *suffix; /* "", "B", "T", "BT" */
+       char offset[32];
+       
+       /* examine flags */
+       I = (opcode & 0x02000000) >> 25;
+       P = (opcode & 0x01000000) >> 24;
+       U = (opcode & 0x00800000) >> 23;
+       B = (opcode & 0x00400000) >> 22;
+       W = (opcode & 0x00200000) >> 21;
+       L = (opcode & 0x00100000) >> 20;
+       
+       /* target register */
+       Rd = (opcode & 0xf000) >> 12;
+       
+       /* base register */
+       Rn = (opcode & 0xf0000) >> 16;
+       
+       /* determine operation */
+       if (L)
+               operation = "LDR";
+       else
+               operation = "STR";
+       
+       /* determine instruction type and suffix */
+       if (B)
+       {
+               if ((P == 0) && (W == 1))
+               {
+                       if (L)
+                               instruction->type = ARM_LDRBT;
+                       else
+                               instruction->type = ARM_STRBT;
+                       suffix = "BT";
+               }
+               else
+               {
+                       if (L)
+                               instruction->type = ARM_LDRB;
+                       else
+                               instruction->type = ARM_STRB;
+                       suffix = "B";
+               }
+       }
+       else
+       {
+               if ((P == 0) && (W == 1))
+               {
+                       if (L)
+                               instruction->type = ARM_LDRT;
+                       else
+                               instruction->type = ARM_STRT;
+                       suffix = "T";
+               }
+               else
+               {
+                       if (L)
+                               instruction->type = ARM_LDR;
+                       else
+                               instruction->type = ARM_STR;
+                       suffix = "";
+               }
+       }
+       
+       if (!I) /* #+-<offset_12> */
+       {
+               u32 offset_12 = (opcode & 0xfff);
+               snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_12);
+       }
+       else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
+       {
+               u8 shift_imm, shift;
+               u8 Rm;
+               
+               shift_imm = (opcode & 0xf80) >> 7;
+               shift = (opcode & 0x60) >> 5;
+               Rm = (opcode & 0xf);
+               
+               if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
+               {
+                       snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
+               }
+               else /* +-<Rm>, <Shift>, #<shift_imm> */
+               {
+                       if (shift == 0x0) /* LSL */
+                       {
+                               snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                       }
+                       else if (shift == 0x1) /* LSR */
+                       {
+                               snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                       }
+                       else if (shift == 0x2) /* ASR */
+                       {
+                               snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                       }
+                       else if (shift == 0x3) /* ROR or RRX */
+                       {
+                               if (shift_imm == 0x0) /* RRX */
+                                       snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm);
+                               else
+                                       snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
+                       }
+               }
+       }
+       
+       if (P == 1)
+       {
+               if (W == 0) /* offset */
+               {
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
+                                        address, opcode, operation, COND(opcode), suffix,
+                                        Rd, Rn, offset);
+               }
+               else /* pre-indexed */
+               {
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
+                                        address, opcode, operation, COND(opcode), suffix,
+                                        Rd, Rn, offset);
+               }
+       }
+       else /* post-indexed */
+       {
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
+                                address, opcode, operation, COND(opcode), suffix,
+                                Rd, Rn, offset);
+       }
+       
+       return ERROR_OK;
+}
+
+/* Miscellaneous load/store instructions */
+int evaluate_misc_load_store(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 P, U, I, W, L, S, H;
+       u8 Rn, Rd;
+       char *operation; /* "LDR" or "STR" */
+       char *suffix; /* "H", "SB", "SH", "D" */
+       char offset[32];
+       
+       /* examine flags */
+       P = (opcode & 0x01000000) >> 24;
+       U = (opcode & 0x00800000) >> 23;
+       I = (opcode & 0x00400000) >> 22;
+       W = (opcode & 0x00200000) >> 21;
+       L = (opcode & 0x00100000) >> 20;
+       S = (opcode & 0x00000040) >> 6;
+       H = (opcode & 0x00000020) >> 5;
+       
+       /* target register */
+       Rd = (opcode & 0xf000) >> 12;
+       
+       /* base register */
+       Rn = (opcode & 0xf0000) >> 16;
+       
+       /* determine instruction type and suffix */
+       if (S) /* signed */
+       {
+               if (L) /* load */
+               {
+                       if (H)
+                       {
+                               operation = "LDR";
+                               instruction->type = ARM_LDRSH;
+                               suffix = "SH";
+                       }
+                       else
+                       {
+                               operation = "LDR";
+                               instruction->type = ARM_LDRSB;
+                               suffix = "SB";
+                       }
+               }
+               else /* there are no signed stores, so this is used to encode double-register load/stores */
+               {
+                       suffix = "D";
+                       if (H)
+                       {
+                               operation = "STR";
+                               instruction->type = ARM_STRD;
+                       }
+                       else
+                       {
+                               operation = "LDR";
+                               instruction->type = ARM_LDRD;
+                       }
+               }
+       }
+       else /* unsigned */
+       {
+               suffix = "H";
+               if (L) /* load */
+               {
+                       operation = "LDR";
+                       instruction->type = ARM_LDRH;
+               }
+               else /* store */
+               {
+                       operation = "STR";
+                       instruction->type = ARM_STRH;
+               }
+       }
+       
+       if (I) /* Immediate offset/index (#+-<offset_8>)*/
+       {
+               u32 offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
+               snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_8);
+       }
+       else /* Register offset/index (+-<Rm>) */
+       {
+               u8 Rm;
+               Rm = (opcode & 0xf);
+               snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
+       }
+       
+       if (P == 1)
+       {
+               if (W == 0) /* offset */
+               {
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
+                                        address, opcode, operation, COND(opcode), suffix,
+                                        Rd, Rn, offset);
+               }
+               else /* pre-indexed */
+               {
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
+                                        address, opcode, operation, COND(opcode), suffix,
+                                        Rd, Rn, offset);
+               }
+       }
+       else /* post-indexed */
+       {
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
+                                address, opcode, operation, COND(opcode), suffix,
+                                Rd, Rn, offset);
+       }
+       
+       return ERROR_OK;
+}
+
+/* Load/store multiples instructions */
+int evaluate_ldm_stm(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 P, U, S, W, L, Rn;
+       u32 register_list;
+       char *addressing_mode;
+       char *mnemonic;
+       char reg_list[69];
+       char *reg_list_p;
+       int i;
+       int first_reg = 1;
+       
+       P = (opcode & 0x01000000) >> 24;
+       U = (opcode & 0x00800000) >> 23;
+       S = (opcode & 0x00400000) >> 22;
+       W = (opcode & 0x00200000) >> 21;
+       L = (opcode & 0x00100000) >> 20;
+       register_list = (opcode & 0xffff);
+       Rn = (opcode & 0xf0000) >> 16;
+       
+       if (L)
+       {
+               instruction->type = ARM_LDM;
+               mnemonic = "LDM";
+       }
+       else
+       {
+               instruction->type = ARM_STM;
+               mnemonic = "STM";
+       }
+       
+       if (P)
+       {
+               if (U)
+                       addressing_mode = "IB";
+               else
+                       addressing_mode = "DB";
+       }
+       else
+       {
+               if (U)
+                       addressing_mode = "IA";
+               else
+                       addressing_mode = "DA";
+       }
+       
+       reg_list_p = reg_list;
+       for (i = 0; i <= 15; i++)
+       {
+               if ((register_list >> i) & 1)
+               {
+                       if (first_reg)
+                       {
+                               first_reg = 0;
+                               reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i);
+                       }
+                       else
+                       {
+                               reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i);
+                       }
+               }
+       }
+       
+       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i%s, {%s}%s",
+                        address, opcode, mnemonic, COND(opcode), addressing_mode,
+                        Rn, (W) ? "!" : "", reg_list, (S) ? "^" : "");
+       
+       return ERROR_OK;
+}
+
+/* Multiplies, extra load/stores */
+int evaluate_mul_and_extra_ld_st(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       /* Multiply (accumulate) (long) and Swap/swap byte */
+       if ((opcode & 0x000000f0) == 0x00000090)
+       {
+               /* Multiply (accumulate) */
+               if ((opcode & 0x0f800000) == 0x00000000)
+               {
+                       u8 Rm, Rs, Rn, Rd, S;
+                       Rm = opcode & 0xf;
+                       Rs = (opcode & 0xf00) >> 8;
+                       Rn = (opcode & 0xf000) >> 12;
+                       Rd = (opcode & 0xf0000) >> 16;
+                       S = (opcode & 0x00100000) >> 20;
+                       
+                       /* examine A bit (accumulate) */
+                       if (opcode & 0x00200000)
+                       {
+                               instruction->type = ARM_MLA;
+                               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMLA%s%s r%i, r%i, r%i, r%i",
+                                               address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs, Rn);
+                       }
+                       else
+                       {
+                               instruction->type = ARM_MUL;
+                               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMUL%s%s r%i, r%i, r%i",
+                                                address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs);
+                       }
+                       
+                       return ERROR_OK;
+               }
+               
+               /* Multiply (accumulate) long */
+               if ((opcode & 0x0f800000) == 0x00800000)
+               {
+                       char* mnemonic;
+                       u8 Rm, Rs, RdHi, RdLow, S;
+                       Rm = opcode & 0xf;
+                       Rs = (opcode & 0xf00) >> 8;
+                       RdHi = (opcode & 0xf000) >> 12;
+                       RdLow = (opcode & 0xf0000) >> 16;
+                       S = (opcode & 0x00100000) >> 20;
+                       
+                       switch ((opcode & 0x00600000) >> 21)
+                       {
+                               case 0x0:
+                                       instruction->type = ARM_UMULL;
+                                       mnemonic = "UMULL";
+                                       break;
+                               case 0x1:
+                                       instruction->type = ARM_UMLAL;
+                                       mnemonic = "UMLAL";
+                                       break;
+                               case 0x2:
+                                       instruction->type = ARM_SMULL;
+                                       mnemonic = "SMULL";
+                                       break;
+                               case 0x3:
+                                       instruction->type = ARM_SMLAL;
+                                       mnemonic = "SMLAL";
+                                       break;
+                       }
+                       
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, r%i, r%i",
+                                               address, opcode, mnemonic, COND(opcode), (S) ? "S" : "",
+                                               RdLow, RdHi, Rm, Rs);
+                       
+                       return ERROR_OK;
+               }
+               
+               /* Swap/swap byte */
+               if ((opcode & 0x0f800000) == 0x01000000)
+               {
+                       u8 Rm, Rd, Rn;
+                       Rm = opcode & 0xf;
+                       Rd = (opcode & 0xf000) >> 12;
+                       Rn = (opcode & 0xf0000) >> 16;
+                       
+                       /* examine B flag */
+                       instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP;
+                       
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, [r%i]",
+                                        address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), Rd, Rm, Rn);
+                       return ERROR_OK;
+               }
+               
+       }
+       
+       return evaluate_misc_load_store(opcode, address, instruction);
+}
+
+int evaluate_mrs_msr(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       int R = (opcode & 0x00400000) >> 22;
+       char *PSR = (R) ? "SPSR" : "CPSR";
+               
+       /* Move register to status register (MSR) */
+       if (opcode & 0x00200000)
+       {
+               instruction->type = ARM_MSR;
+                       
+               /* immediate variant */
+               if (opcode & 0x02000000)
+               {
+                       u8 immediate = (opcode & 0xff);
+                       u8 rotate = (opcode & 0xf00);
+                       
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, 0x%8.8x",
+                                        address, opcode, COND(opcode), PSR,
+                                        (opcode & 0x10000) ? "c" : "",
+                                        (opcode & 0x20000) ? "x" : "",
+                                        (opcode & 0x40000) ? "s" : "",
+                                        (opcode & 0x80000) ? "f" : "",
+                                        ror(immediate, (rotate * 2))
+                                       );
+               }
+               else /* register variant */
+               {
+                       u8 Rm = opcode & 0xf;
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, r%i",
+                                        address, opcode, COND(opcode), PSR,
+                                        (opcode & 0x10000) ? "c" : "",
+                                        (opcode & 0x20000) ? "x" : "",
+                                        (opcode & 0x40000) ? "s" : "",
+                                        (opcode & 0x80000) ? "f" : "",
+                                        Rm
+                                       );
+               }
+               
+       }
+       else /* Move status register to register (MRS) */
+       {
+               u8 Rd;
+               
+               instruction->type = ARM_MRS;
+               Rd = (opcode & 0x0000f000) >> 12;
+                       
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tMRS%s r%i, %s",
+                                address, opcode, COND(opcode), Rd, PSR);
+       }
+       
+       return ERROR_OK;
+}
+
+/* Miscellaneous instructions */
+int evaluate_misc_instr(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       /* MRS/MSR */
+       if ((opcode & 0x000000f0) == 0x00000000)
+       {
+               evaluate_mrs_msr(opcode, address, instruction);
+       }
+       
+       /* BX */
+       if ((opcode & 0x006000f0) == 0x00200010)
+       {
+               u8 Rm;
+               instruction->type = ARM_BX;
+               Rm = opcode & 0xf;
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBX%s r%i",
+                                address, opcode, COND(opcode), Rm);
+       }
+       
+       /* CLZ */
+       if ((opcode & 0x0060000f0) == 0x00300010)
+       {
+               u8 Rm, Rd;
+               instruction->type = ARM_CLZ;
+               Rm = opcode & 0xf;
+               Rd = (opcode & 0xf000) >> 12;
+
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tCLZ%s r%i, r%i",
+                                address, opcode, COND(opcode), Rd, Rm);
+       }
+       
+       /* BLX */
+       if ((opcode & 0x0060000f0) == 0x00200030)
+       {
+               u8 Rm;
+               instruction->type = ARM_BLX;
+               Rm = opcode & 0xf;
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
+                                address, opcode, COND(opcode), Rm);
+       }
+       
+       /* Enhanced DSP add/subtracts */
+       if ((opcode & 0x0000000f0) == 0x00000050)
+       {
+               u8 Rm, Rd, Rn;
+               char *mnemonic;
+               Rm = opcode & 0xf;
+               Rd = (opcode & 0xf000) >> 12;
+               Rn = (opcode & 0xf0000) >> 16;
+               
+               switch ((opcode & 0x00600000) >> 21)
+               {
+                       case 0x0:
+                               instruction->type = ARM_QADD;
+                               mnemonic = "QADD";
+                               break;
+                       case 0x1:
+                               instruction->type = ARM_QSUB;
+                               mnemonic = "QSUB";
+                               break;
+                       case 0x2:
+                               instruction->type = ARM_QDADD;
+                               mnemonic = "QDADD";
+                               break;
+                       case 0x3:
+                               instruction->type = ARM_QDSUB;
+                               mnemonic = "QDSUB";
+                               break;
+               }
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, r%i",
+                                address, opcode, mnemonic, COND(opcode), Rd, Rm, Rn);
+       }
+       
+       /* Software breakpoints */
+       if ((opcode & 0x0000000f0) == 0x00000070)
+       {
+               u32 immediate;
+               instruction->type = ARM_BKPT;
+               immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf);
+               
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tBKPT 0x%4.4x",
+                                address, opcode, immediate);   
+       }
+       
+       /* Enhanced DSP multiplies */
+       if ((opcode & 0x000000090) == 0x00000080)
+       {
+               int x = (opcode & 0x20) >> 5;
+               int y = (opcode & 0x40) >> 6;
+               
+               /* SMLA<x><y> */
+               if ((opcode & 0x00600000) == 0x00000000)
+               {
+                       u8 Rd, Rm, Rs, Rn;
+                       instruction->type = ARM_SMLAxy;
+                       Rd = (opcode & 0xf0000) >> 16;
+                       Rm = (opcode & 0xf);
+                       Rs = (opcode & 0xf00) >> 8;
+                       Rn = (opcode & 0xf000) >> 12;
+                       
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
+                                        address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
+                                        Rd, Rm, Rs, Rn);
+               }
+               
+               /* SMLAL<x><y> */
+               if ((opcode & 0x00600000) == 0x00400000)
+               {
+                       u8 RdLow, RdHi, Rm, Rs;
+                       instruction->type = ARM_SMLAxy;
+                       RdHi = (opcode & 0xf0000) >> 16;
+                       RdLow = (opcode & 0xf000) >> 12;
+                       Rm = (opcode & 0xf);
+                       Rs = (opcode & 0xf00) >> 8;
+                       
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
+                                        address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
+                                        RdLow, RdHi, Rm, Rs);
+               }
+               
+               /* SMLAW<y> */
+               if (((opcode & 0x00600000) == 0x00100000) && (x == 0))
+               {
+                       u8 Rd, Rm, Rs, Rn;
+                       instruction->type = ARM_SMLAWy;
+                       Rd = (opcode & 0xf0000) >> 16;
+                       Rm = (opcode & 0xf);
+                       Rs = (opcode & 0xf00) >> 8;
+                       Rn = (opcode & 0xf000) >> 12;
+
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMLAW%s%s r%i, r%i, r%i, r%i",
+                                        address, opcode, (y) ? "T" : "B", COND(opcode),
+                                        Rd, Rm, Rs, Rn);
+               }
+               
+               /* SMUL<x><y> */
+               if ((opcode & 0x00600000) == 0x00300000)
+               {
+                       u8 Rd, Rm, Rs;
+                       instruction->type = ARM_SMULxy;
+                       Rd = (opcode & 0xf0000) >> 16;
+                       Rm = (opcode & 0xf);
+                       Rs = (opcode & 0xf00) >> 8;
+                       
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s%s r%i, r%i, r%i",
+                                        address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode),
+                                        Rd, Rm, Rs);
+               }
+               
+               /* SMULW<y> */
+               if (((opcode & 0x00600000) == 0x00100000) && (x == 1))
+               {
+                       u8 Rd, Rm, Rs;
+                       instruction->type = ARM_SMULWy;
+                       Rd = (opcode & 0xf0000) >> 16;
+                       Rm = (opcode & 0xf);
+                       Rs = (opcode & 0xf00) >> 8;
+                       
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s r%i, r%i, r%i",
+                                        address, opcode, (y) ? "T" : "B", COND(opcode),
+                                        Rd, Rm, Rs);
+               }
+       }
+       
+       return ERROR_OK;
+}
+
+int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       u8 I, op, S, Rn, Rd;
+       char *mnemonic;
+       char shifter_operand[32];
+       
+       I = (opcode & 0x02000000) >> 25;
+       op = (opcode & 0x01e00000) >> 21;
+       S = (opcode & 0x00100000) >> 20;
+       
+       Rd = (opcode & 0xf000) >> 12;
+       Rn = (opcode & 0xf0000) >> 16;
+       
+       switch (op)
+       {
+               case 0x0:
+                       instruction->type = ARM_AND;
+                       mnemonic = "AND";
+                       break;
+               case 0x1:
+                       instruction->type = ARM_EOR;
+                       mnemonic = "EOR";
+                       break;
+               case 0x2:
+                       instruction->type = ARM_SUB;
+                       mnemonic = "SUB";
+                       break;
+               case 0x3:
+                       instruction->type = ARM_RSB;
+                       mnemonic = "RSB";
+                       break;
+               case 0x4:
+                       instruction->type = ARM_ADD;
+                       mnemonic = "ADD";
+                       break;
+               case 0x5:
+                       instruction->type = ARM_ADC;
+                       mnemonic = "ADC";
+                       break;
+               case 0x6:
+                       instruction->type = ARM_SBC;
+                       mnemonic = "SBC";
+                       break;
+               case 0x7:
+                       instruction->type = ARM_RSC;
+                       mnemonic = "RSC";
+                       break;
+               case 0x8:
+                       instruction->type = ARM_TST;
+                       mnemonic = "TST";
+                       break;
+               case 0x9:
+                       instruction->type = ARM_TEQ;
+                       mnemonic = "TEQ";
+                       break;
+               case 0xa:
+                       instruction->type = ARM_CMP;
+                       mnemonic = "CMP";
+                       break;
+               case 0xb:
+                       instruction->type = ARM_CMN;
+                       mnemonic = "CMN";
+                       break;
+               case 0xc:
+                       instruction->type = ARM_ORR;
+                       mnemonic = "ORR";
+                       break;
+               case 0xd:
+                       instruction->type = ARM_MOV;
+                       mnemonic = "MOV";
+                       break;
+               case 0xe:
+                       instruction->type = ARM_BIC;
+                       mnemonic = "BIC";
+                       break;
+               case 0xf:
+                       instruction->type = ARM_MVN;
+                       mnemonic = "MVN";
+                       break;
+       }
+       
+       if (I) /* immediate shifter operand (#<immediate>)*/
+       {
+               u8 immed_8 = opcode & 0xff;
+               u8 rotate_imm = (opcode & 0xf00) >> 8;
+               u32 immediate;
+               
+               immediate = ror(immed_8, rotate_imm * 2);
+               
+               snprintf(shifter_operand, 32, "#0x%x", immediate);
+       }
+       else /* register-based shifter operand */
+       {
+               u8 shift, Rm;
+               shift = (opcode & 0x60) >> 5;
+               Rm = (opcode & 0xf);
+               
+               if ((opcode & 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
+               {
+                       u8 shift_imm;
+                       shift_imm = (opcode & 0xf80) >> 7;
+
+                       
+                       if ((shift_imm == 0x0) && (shift == 0x0))
+                       {
+                               snprintf(shifter_operand, 32, "r%i", Rm);
+                       }
+                       else
+                       {
+                               if (shift == 0x0) /* LSL */
+                               {
+                                       snprintf(shifter_operand, 32, "r%i, LSL #0x%x", Rm, shift_imm);
+                               }
+                               else if (shift == 0x1) /* LSR */
+                               {
+                                       if (shift_imm == 0x0)
+                                               shift_imm = 0x32;
+                                       snprintf(shifter_operand, 32, "r%i, LSR #0x%x", Rm, shift_imm);
+                               }
+                               else if (shift == 0x2) /* ASR */
+                               {
+                                       if (shift_imm == 0x0)
+                                               shift_imm = 0x32;
+                                       snprintf(shifter_operand, 32, "r%i, ASR #0x%x", Rm, shift_imm);
+                               }
+                               else if (shift == 0x3) /* ROR or RRX */
+                               {
+                                       if (shift_imm == 0x0) /* RRX */
+                                               snprintf(shifter_operand, 32, "r%i, RRX", Rm);
+                                       else
+                                               snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm);
+                               }
+                       }
+               }
+               else /* Register shifts ("<Rm>, <shift> <Rs>") */
+               {
+                       u8 Rs = (opcode & 0xf00) >> 8;
+                       
+                       if (shift == 0x0) /* LSL */
+                       {
+                               snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs);
+                       }
+                       else if (shift == 0x1) /* LSR */
+                       {
+                               snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs);
+                       }
+                       else if (shift == 0x2) /* ASR */
+                       {
+                               snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs);
+                       }
+                       else if (shift == 0x3) /* ROR or RRX */
+                       {
+                               snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs);
+                       }
+               }
+       }
+       
+       if ((op < 0x8) || (op == 0xc) || (op == 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
+       {
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, %s",
+                                address, opcode, mnemonic, COND(opcode),
+                                (S) ? "S" : "", Rd, Rn, shifter_operand);
+       }
+       else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
+       {
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
+                                address, opcode, mnemonic, COND(opcode),
+                                (S) ? "S" : "", Rd, shifter_operand);
+       }
+       else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
+       {
+               snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, %s",
+                                address, opcode, mnemonic, COND(opcode),
+                                Rn, shifter_operand);
+       }
+       
+       return ERROR_OK;
+}
+               
+int evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction)
+{
+       /* clear fields, to avoid confusion */
+       bzero(instruction, sizeof(arm_instruction_t));
+       instruction->opcode = opcode;
+       
+       /* catch opcodes with condition field [31:28] = b1111 */
+       if ((opcode & 0xf0000000) == 0xf0000000)
+       {
+               /* Undefined instruction (or ARMv5E cache preload PLD) */
+               if ((opcode & 0x08000000) == 0x00000000)
+                       return evaluate_pld(opcode, address, instruction);
+               
+               /* Undefined instruction */
+               if ((opcode & 0x0e000000) == 0x08000000)
+               {
+                       instruction->type = ARM_UNDEFINED_INSTRUCTION;
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
+                       return ERROR_OK;
+               }
+               
+               /* Branch and branch with link and change to Thumb */
+               if ((opcode & 0x0e000000) == 0x0a000000)
+                       return evaluate_blx_imm(opcode, address, instruction);
+               
+               /* Extended coprocessor opcode space (ARMv5 and higher )*/
+               /* Coprocessor load/store and double register transfers */
+               if ((opcode & 0x0e000000) == 0x0c000000)
+                       return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
+               
+               /* Coprocessor data processing */
+               if ((opcode & 0x0f000100) == 0x0c000000)
+                       return evaluate_cdp_mcr_mrc(opcode, address, instruction);
+               
+               /* Coprocessor register transfers */
+               if ((opcode & 0x0f000010) == 0x0c000010)
+                       return evaluate_cdp_mcr_mrc(opcode, address, instruction);
+               
+               /* Undefined instruction */
+               if ((opcode & 0x0f000000) == 0x0f000000)
+               {
+                       instruction->type = ARM_UNDEFINED_INSTRUCTION;
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
+                       return ERROR_OK;
+               }
+       }
+       
+       /* catch opcodes with [27:25] = b000 */
+       if ((opcode & 0x0e000000) == 0x00000000)
+       {
+               /* Multiplies, extra load/stores */
+               if ((opcode & 0x00000090) == 0x00000090)
+                       return evaluate_mul_and_extra_ld_st(opcode, address, instruction);
+               
+               /* Miscellaneous instructions */
+               if ((opcode & 0x0f900000) == 0x01000000)
+                       return evaluate_misc_instr(opcode, address, instruction);
+               
+               return evaluate_data_proc(opcode, address, instruction);
+       }
+       
+       /* catch opcodes with [27:25] = b001 */
+       if ((opcode & 0x0e000000) == 0x02000000)
+       {
+               /* Undefined instruction */
+               if ((opcode & 0x0fb00000) == 0x03000000)
+               {
+                       instruction->type = ARM_UNDEFINED_INSTRUCTION;
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
+                       return ERROR_OK;
+               }
+                               
+               /* Move immediate to status register */
+               if ((opcode & 0x0fb00000) == 0x03200000)
+                       return evaluate_mrs_msr(opcode, address, instruction);
+               
+               return evaluate_data_proc(opcode, address, instruction);
+
+       }
+       
+       /* catch opcodes with [27:25] = b010 */
+       if ((opcode & 0x0e000000) == 0x04000000)
+       {
+               /* Load/store immediate offset */
+               return evaluate_load_store(opcode, address, instruction);
+       }
+       
+       /* catch opcodes with [27:25] = b011 */
+       if ((opcode & 0x0e000000) == 0x04000000)
+       {
+               /* Undefined instruction */
+               if ((opcode & 0x00000010) == 0x00000010)
+               {
+                       instruction->type = ARM_UNDEFINED_INSTRUCTION;
+                       snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address, opcode);
+                       return ERROR_OK;
+               }
+               
+               /* Load/store register offset */
+               return evaluate_load_store(opcode, address, instruction);
+
+       }
+       
+       /* catch opcodes with [27:25] = b100 */
+       if ((opcode & 0x0e000000) == 0x08000000)
+       {
+               /* Load/store multiple */
+               return evaluate_ldm_stm(opcode, address, instruction);
+       }
+       
+       /* catch opcodes with [27:25] = b101 */
+       if ((opcode & 0x0e000000) == 0x0a000000)
+       {
+               /* Branch and branch with link */
+               return evaluate_b_bl(opcode, address, instruction);
+       }
+       
+       /* catch opcodes with [27:25] = b110 */
+       if ((opcode & 0x0e000000) == 0x0a000000)
+       {
+               /* Coprocessor load/store and double register transfers */
+               return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
+       }
+       
+       /* catch opcodes with [27:25] = b111 */
+       if ((opcode & 0x0e000000) == 0x0e000000)
+       {
+               /* Software interrupt */
+               if ((opcode & 0x0f000000) == 0x0f000000)
+                       return evaluate_swi(opcode, address, instruction);
+               
+               /* Coprocessor data processing */
+               if ((opcode & 0x0f000010) == 0x0e000000)
+                       return evaluate_cdp_mcr_mrc(opcode, address, instruction);
+               
+               /* Coprocessor register transfers */
+               if ((opcode & 0x0f000010) == 0x0e000010)
+                       return evaluate_cdp_mcr_mrc(opcode, address, instruction);
+       }
+       
+       ERROR("should never reach this point");
+       return -1;
+}
diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h
new file mode 100644 (file)
index 0000000..df84ba0
--- /dev/null
@@ -0,0 +1,138 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifndef ARM_DISASSEMBLER_H
+#define ARM_DISASSEMBLER_H
+
+#include "types.h"
+
+enum arm_instruction_type
+{
+       ARM_UNKNOWN_INSTUCTION,
+       
+       /* Branch instructions */
+       ARM_B,
+       ARM_BL,
+       ARM_BX,
+       ARM_BLX,
+       
+       /* Data processing instructions */
+       ARM_AND,
+       ARM_EOR,
+       ARM_SUB,
+       ARM_RSB,
+       ARM_ADD,
+       ARM_ADC,
+       ARM_SBC,
+       ARM_RSC,
+       ARM_TST,
+       ARM_TEQ,
+       ARM_CMP,
+       ARM_CMN,
+       ARM_ORR,
+       ARM_MOV,
+       ARM_BIC,
+       ARM_MVN,
+       
+       /* Load/store instructions */
+       ARM_LDR,
+       ARM_LDRB,
+       ARM_LDRT,
+       ARM_LDRBT,
+       
+       ARM_LDRH,
+       ARM_LDRSB,
+       ARM_LDRSH,
+       
+       ARM_LDM,
+
+       ARM_STR,
+       ARM_STRB,
+       ARM_STRT,
+       ARM_STRBT,
+       
+       ARM_STRH,
+       
+       ARM_STM,
+       
+       /* Status register access instructions */
+       ARM_MRS,
+       ARM_MSR,
+       
+       /* Multiply instructions */
+       ARM_MUL,
+       ARM_MLA,
+       ARM_SMULL,
+       ARM_SMLAL,
+       ARM_UMULL,
+       ARM_UMLAL,
+       
+       /* Miscellaneous instructions */
+       ARM_CLZ,
+       
+       /* Exception generating instructions */
+       ARM_BKPT,
+       ARM_SWI,
+       
+       /* Coprocessor instructions */
+       ARM_CDP,
+       ARM_LDC,
+       ARM_STC,
+       ARM_MCR,
+       ARM_MRC,
+       
+       /* Semaphore instructions */
+       ARM_SWP,
+       ARM_SWPB,
+       
+       /* Enhanced DSP extensions */
+       ARM_MCRR,
+       ARM_MRRC,
+       ARM_PLD,
+       ARM_QADD,
+       ARM_QDADD,
+       ARM_QSUB,
+       ARM_QDSUB,
+       ARM_SMLAxy,
+       ARM_SMLALxy,
+       ARM_SMLAWy,
+       ARM_SMULxy,
+       ARM_SMULWy,
+       ARM_LDRD,
+       ARM_STRD,
+
+       ARM_UNDEFINED_INSTRUCTION = 0xffffffff,
+};
+
+typedef struct arm_instruction_s
+{
+       enum arm_instruction_type type;
+       char text[128];
+       u32 opcode;
+       
+       /* target */
+       u32 target_address;
+       
+} arm_instruction_t;
+
+extern int evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction);
+
+#define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000)>>28])
+
+#endif /* ARM_DISASSEMBLER_H */
index 51fd4b42732dc8813a8dd4d6de7c28a46b197740..4932e20ae5b570d098658300889b9734fa220034 100644 (file)
@@ -19,6 +19,8 @@
  ***************************************************************************/
 #include "config.h"
 
+#include "arm_disassembler.h"
+
 #include "armv4_5.h"
 
 #include "target.h"
@@ -377,6 +379,47 @@ int handle_armv4_5_core_state_command(struct command_context_s *cmd_ctx, char *c
        return ERROR_OK;
 }
 
+int handle_armv4_5_disassemble_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
+       armv4_5_common_t *armv4_5 = target->arch_info;
+       u32 address;
+       int count;
+       int i;
+       arm_instruction_t cur_instruction;
+       u32 opcode;
+       int thumb;
+       
+       if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
+       {
+               command_print(cmd_ctx, "current target isn't an ARMV4/5 target");
+               return ERROR_OK;
+       }
+       
+       if (argc < 2)
+       {
+               command_print(cmd_ctx, "usage: armv4_5 disassemble <address> <count> ['thumb']");
+               return ERROR_OK;
+       }
+       
+       address = strtoul(args[0], NULL, 0);
+       count = strtoul(args[1], NULL, 0);
+       
+       if (argc >= 3)
+               if (strcmp(args[2], "thumb") == 0)
+                       thumb = 1;
+       
+       for (i = 0; i < count; i++)
+       {
+               target->type->read_memory(target, address, 4, 1, (u8*)&opcode);
+               evaluate_opcode(opcode, address, &cur_instruction);
+               command_print(cmd_ctx, "%s", cur_instruction.text);
+               address += (thumb) ? 2 : 4;
+       }
+       
+       return ERROR_OK;
+}
+
 int armv4_5_register_commands(struct command_context_s *cmd_ctx)
 {
        command_t *armv4_5_cmd;
@@ -386,6 +429,7 @@ int armv4_5_register_commands(struct command_context_s *cmd_ctx)
        register_command(cmd_ctx, armv4_5_cmd, "reg", handle_armv4_5_reg_command, COMMAND_EXEC, "display ARM core registers");
        register_command(cmd_ctx, armv4_5_cmd, "core_state", handle_armv4_5_core_state_command, COMMAND_EXEC, "display/change ARM core state <arm|thumb>");
        
+       register_command(cmd_ctx, armv4_5_cmd, "disassemble", handle_armv4_5_disassemble_command, COMMAND_EXEC, "disassemble instructions <address> <count> ['thumb']");
        return ERROR_OK;
 }
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)