2004-03-23 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / opcodes / arm-dis.c
index 62a2a39ab62df8ef659ad71d8ffc58c31166eac9..e918dafa28bba2afe9835ec06138fccad61114cb 100644 (file)
@@ -1,24 +1,24 @@
 /* Instruction printing code for the ARM
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
    Modification by James G. Smith (jsmith@cygnus.co.uk)
 
-This file is part of libopcodes.
+   This file is part of libopcodes.
 
-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 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.
+   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.  */
+   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 "sysdep.h"
 #include "dis-asm.h"
@@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "coff/internal.h"
 #include "libcoff.h"
 #include "opintl.h"
+#include "safe-ctype.h"
 
 /* FIXME: This shouldn't be done here.  */
 #include "elf-bfd.h"
@@ -70,7 +71,21 @@ static arm_regname regnames[] =
   { "atpcs", "Select register names used in the ATPCS",
     { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7",  "v8",  "IP",  "SP",  "LR",  "PC" }},
   { "special-atpcs", "Select special register names used in the ATPCS",
-    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL",  "FP",  "IP",  "SP",  "LR",  "PC" }}
+    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL",  "FP",  "IP",  "SP",  "LR",  "PC" }},
+  { "iwmmxt_regnames", "Select register names used on the Intel Wireless MMX technology coprocessor",
+    { "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15"}},
+  { "iwmmxt_Cregnames", "Select control register names used on the Intel Wireless MMX technology coprocessor",
+    {"wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved"}}
+};
+
+static char * iwmmxt_wwnames[] =
+{"b", "h", "w", "d"};
+
+static char * iwmmxt_wwssnames[] =
+{"b", "bus", "b", "bss",
+ "h", "hus", "h", "hss",
+ "w", "wus", "w", "wss",
+ "d", "dus", "d", "dss"
 };
 
 /* Default to GCC register name set.  */
@@ -98,11 +113,15 @@ static void parse_disassembler_options
   PARAMS ((char *));
 static int  print_insn
   PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean));
-int get_arm_regname_num_options (void);
-int set_arm_regname_option (int option);
-int get_arm_regnames (int option, const char **setname,
-                     const char **setdescription,
-                     const char ***register_names);
+static int set_iwmmxt_regnames
+  PARAMS ((void));
+
+int get_arm_regname_num_options
+  PARAMS ((void));
+int set_arm_regname_option
+  PARAMS ((int));
+int get_arm_regnames
+  PARAMS ((int, const char **, const char **, const char ***));
 \f
 /* Functions.  */
 int
@@ -167,6 +186,24 @@ arm_decode_shift (given, func, stream)
     }
 }
 
+static int
+set_iwmmxt_regnames ()
+{
+  const char * setname;
+  const char * setdesc;
+  const char ** regnames;
+  int iwmmxt_regnames = 0;
+  int num_regnames = get_arm_regname_num_options ();
+
+  get_arm_regnames (iwmmxt_regnames, &setname,
+                   &setdesc, &regnames);
+  while ((strcmp ("iwmmxt_regnames", setname))
+        && (iwmmxt_regnames < num_regnames))
+    get_arm_regnames (++iwmmxt_regnames, &setname, &setdesc, &regnames);
+
+  return iwmmxt_regnames;
+}
+                         
 /* Print one instruction from PC on INFO->STREAM.
    Return the size of the instruction (always 4 on ARM). */
 
@@ -179,9 +216,15 @@ print_insn_arm (pc, info, given)
   const struct arm_opcode *insn;
   void *stream = info->stream;
   fprintf_ftype func   = info->fprintf_func;
+  static int iwmmxt_regnames = 0;
 
   for (insn = arm_opcodes; insn->assembler; insn++)
     {
+      if (insn->value == FIRST_IWMMXT_INSN
+         && info->mach != bfd_mach_arm_XScale
+         && info->mach != bfd_mach_arm_iWMMXt)
+       insn = insn + IWMMXT_INSN_COUNT;
+
       if ((given & insn->mask) == insn->value)
        {
          char * c;
@@ -243,7 +286,7 @@ print_insn_arm (pc, info, given)
                                {
                                  int offset = given & 0xfff;
                                  if (offset)
-                                   func (stream, ", %s#%d",
+                                   func (stream, ", #%s%d",
                                          (((given & 0x00800000) == 0)
                                           ? "-" : ""), offset);
                                }
@@ -264,7 +307,7 @@ print_insn_arm (pc, info, given)
                                {
                                  int offset = given & 0xfff;
                                  if (offset)
-                                   func (stream, "], %s#%d",
+                                   func (stream, "], #%s%d",
                                          (((given & 0x00800000) == 0)
                                           ? "-" : ""), offset);
                                  else
@@ -307,7 +350,7 @@ print_insn_arm (pc, info, given)
                                   /* Immediate.  */
                                   int offset = ((given & 0xf00) >> 4) | (given & 0xf);
                                  if (offset)
-                                   func (stream, ", %s#%d",
+                                   func (stream, ", #%s%d",
                                          (((given & 0x00800000) == 0)
                                           ? "-" : ""), offset);
                                }
@@ -331,7 +374,7 @@ print_insn_arm (pc, info, given)
                                   /* Immediate.  */
                                   int offset = ((given & 0xf00) >> 4) | (given & 0xf);
                                  if (offset)
-                                   func (stream, "], %s#%d",
+                                   func (stream, "], #%s%d",
                                          (((given & 0x00800000) == 0)
                                           ? "-" : ""), offset);
                                  else
@@ -402,11 +445,13 @@ print_insn_arm (pc, info, given)
 
                    case 'A':
                      func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
-                     if ((given & 0x01000000) != 0)
+
+                     if ((given & (1 << 24)) != 0)
                        {
                          int offset = given & 0xff;
+
                          if (offset)
-                           func (stream, ", %s#%d]%s",
+                           func (stream, ", #%s%d]%s",
                                  ((given & 0x00800000) == 0 ? "-" : ""),
                                  offset * 4,
                                  ((given & 0x00200000) != 0 ? "!" : ""));
@@ -416,12 +461,18 @@ print_insn_arm (pc, info, given)
                      else
                        {
                          int offset = given & 0xff;
-                         if (offset)
-                           func (stream, "], %s#%d",
-                                 ((given & 0x00800000) == 0 ? "-" : ""),
-                                 offset * 4);
+
+                         func (stream, "]");
+
+                         if (given & (1 << 21))
+                           {
+                             if (offset)
+                               func (stream, ", #%s%d",
+                                     ((given & 0x00800000) == 0 ? "-" : ""),
+                                     offset * 4);
+                           }
                          else
-                           func (stream, "]");
+                           func (stream, ", {%d}", offset);
                        }
                      break;
 
@@ -588,6 +639,16 @@ print_insn_arm (pc, info, given)
                                  func (stream, "%d", reg);
                                }
                                break;
+                             case 'W':
+                               {
+                                 long reg;
+                                 
+                                 reg = given >> bitstart;
+                                 reg &= (2 << (bitend - bitstart)) - 1;
+                                 
+                                 func (stream, "%d", reg + 1);
+                               }
+                               break;
                              case 'x':
                                {
                                  long reg;
@@ -629,6 +690,63 @@ print_insn_arm (pc, info, given)
                                    func (stream, "f%d", reg);
                                }
                                break;
+
+                             case 'w':
+                               {
+                                 long reg;
+
+                                 if (bitstart != bitend)
+                                   {
+                                     reg = given >> bitstart;
+                                     reg &= (2 << (bitend - bitstart)) - 1;
+                                     if (bitend - bitstart == 1)
+                                       func (stream, "%s", iwmmxt_wwnames[reg]);
+                                     else
+                                       func (stream, "%s", iwmmxt_wwssnames[reg]);
+                                   }
+                                 else
+                                   {
+                                     reg = (((given >> 8)  & 0x1) |
+                                            ((given >> 22) & 0x1));
+                                     func (stream, "%s", iwmmxt_wwnames[reg]);
+                                   }
+                               }
+                               break;
+
+                             case 'g':
+                               {
+                                 long reg;
+                                 int current_regnames;
+
+                                 if (! iwmmxt_regnames)
+                                   iwmmxt_regnames = set_iwmmxt_regnames ();
+                                 current_regnames = set_arm_regname_option
+                                   (iwmmxt_regnames);
+
+                                 reg = given >> bitstart;
+                                 reg &= (2 << (bitend - bitstart)) - 1;
+                                 func (stream, "%s", arm_regnames[reg]);
+                                 set_arm_regname_option (current_regnames);
+                               }
+                               break;
+
+                             case 'G':
+                               {
+                                 long reg;
+                                 int current_regnames;
+
+                                 if (! iwmmxt_regnames)
+                                   iwmmxt_regnames = set_iwmmxt_regnames ();
+                                 current_regnames = set_arm_regname_option
+                                   (iwmmxt_regnames + 1);
+
+                                 reg = given >> bitstart;
+                                 reg &= (2 << (bitend - bitstart)) - 1;
+                                 func (stream, "%s", arm_regnames[reg]);
+                                 set_arm_regname_option (current_regnames);
+                               }
+                               break;
+
                              default:
                                abort ();
                              }
@@ -734,6 +852,54 @@ print_insn_arm (pc, info, given)
                          }
                        break;
 
+                     case 'L':
+                       switch (given & 0x00400100)
+                         {
+                         case 0x00000000: func (stream, "b"); break;
+                         case 0x00400000: func (stream, "h"); break;
+                         case 0x00000100: func (stream, "w"); break;
+                         case 0x00400100: func (stream, "d"); break;
+                         default:
+                           break;
+                         }
+                       break;
+
+                     case 'Z':
+                       {
+                         int value;
+                         /* given (20, 23) | given (0, 3) */
+                         value = ((given >> 16) & 0xf0) | (given & 0xf);
+                         func (stream, "%d", value);
+                       }
+                       break;
+
+                     case 'l':
+                       /* This is like the 'A' operator, except that if
+                          the width field "M" is zero, then the offset is
+                          *not* multiplied by four.  */
+                       {
+                         int offset = given & 0xff;
+                         int multiplier = (given & 0x00000100) ? 4 : 1;
+
+                         func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
+
+                         if (offset)
+                           {
+                             if ((given & 0x01000000) != 0)
+                               func (stream, ", #%s%d]%s",
+                                     ((given & 0x00800000) == 0 ? "-" : ""),
+                                     offset * multiplier,
+                                     ((given & 0x00200000) != 0 ? "!" : ""));
+                             else
+                               func (stream, "], #%s%d",
+                                     ((given & 0x00800000) == 0 ? "-" : ""),
+                                     offset * multiplier);
+                           }
+                         else
+                           func (stream, "]");
+                       }
+                       break;
+
                      default:
                        abort ();
                      }
@@ -989,6 +1155,23 @@ print_insn_thumb (pc, info, given)
   abort ();
 }
 
+/* Disallow mapping symbols ($a, $b, $d, $t etc) from
+   being displayed in symbol relative addresses.  */
+
+bfd_boolean
+arm_symbol_is_valid (asymbol * sym,
+                    struct disassemble_info * info ATTRIBUTE_UNUSED)
+{
+  const char * name;
+  
+  if (sym == NULL)
+    return FALSE;
+
+  name = bfd_asymbol_name (sym);
+
+  return (name && *name != '$');
+}
+
 /* Parse an individual disassembler option.  */
 
 void
@@ -1005,51 +1188,48 @@ parse_arm_disassembler_option (option)
       option += 10;
 
       for (i = NUM_ARM_REGNAMES; i--;)
-       if (streq (option, regnames[i].name))
+       if (strneq (option, regnames[i].name, strlen (regnames[i].name)))
          {
            regname_selected = i;
            break;
          }
 
       if (i < 0)
+       /* XXX - should break 'option' at following delimiter.  */
        fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
     }
-  else if (streq (option, "force-thumb"))
+  else if (strneq (option, "force-thumb", 11))
     force_thumb = 1;
-  else if (streq (option, "no-force-thumb"))
+  else if (strneq (option, "no-force-thumb", 14))
     force_thumb = 0;
   else
+    /* XXX - should break 'option' at following delimiter.  */
     fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
 
   return;
 }
 
-/* Parse the string of disassembler options, spliting it at whitespaces.  */
+/* Parse the string of disassembler options, spliting it at whitespaces
+   or commas.  (Whitespace separators supported for backwards compatibility).  */
 
 static void
 parse_disassembler_options (options)
      char * options;
 {
-  char * space;
-
   if (options == NULL)
     return;
 
-  do
+  while (*options)
     {
-      space = strchr (options, ' ');
-
-      if (space)
-       {
-         * space = '\0';
-         parse_arm_disassembler_option (options);
-         * space = ' ';
-         options = space + 1;
-       }
-      else
-       parse_arm_disassembler_option (options);
+      parse_arm_disassembler_option (options);
+
+      /* Skip forward to next seperator.  */
+      while ((*options) && (! ISSPACE (*options)) && (*options != ','))
+       ++ options;
+      /* Skip forward past seperators.  */
+      while (ISSPACE (*options) || (*options == ','))
+       ++ options;      
     }
-  while (space);
 }
 
 /* NOTE: There are no checks in these routines that
This page took 0.040602 seconds and 4 git commands to generate.