* i386-tdep.c: Fix spelling mistakes.
[deliverable/binutils-gdb.git] / opcodes / mips-dis.c
index 1528aadc5f1eb71394795f694e0234a753c9623b..43fcb3ca79a2b5cd957b82a8db30e66399c9a0ec 100644 (file)
@@ -1,6 +1,6 @@
 /* Print mips instructions for GDB, the GNU debugger, or for objdump.
    Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002
+   2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
 
@@ -50,7 +50,7 @@ static int _print_insn_mips
   PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian));
 static int print_insn_mips
   PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *));
-static void print_insn_arg
+static void print_insn_args
   PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *));
 static int print_insn_mips16
   PARAMS ((bfd_vma, struct disassemble_info *));
@@ -62,6 +62,12 @@ static void print_mips16_insn_arg
 \f
 /* FIXME: These should be shared with gdb somehow.  */
 
+struct mips_cp0sel_name {
+       unsigned int cp0reg;
+       unsigned int sel;
+       const char * const name;
+};
+
 /* The mips16 register names.  */
 static const char * const mips16_reg_names[] = {
   "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
@@ -134,6 +140,103 @@ static const char * const mips_cp0_names_mips3264[32] = {
   "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
 };
 
+static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = {
+  { 16, 1, "c0_config1"                },
+  { 16, 2, "c0_config2"                },
+  { 16, 3, "c0_config3"                },
+  { 18, 1, "c0_watchlo,1"      },
+  { 18, 2, "c0_watchlo,2"      },
+  { 18, 3, "c0_watchlo,3"      },
+  { 18, 4, "c0_watchlo,4"      },
+  { 18, 5, "c0_watchlo,5"      },
+  { 18, 6, "c0_watchlo,6"      },
+  { 18, 7, "c0_watchlo,7"      },
+  { 19, 1, "c0_watchhi,1"      },
+  { 19, 2, "c0_watchhi,2"      },
+  { 19, 3, "c0_watchhi,3"      },
+  { 19, 4, "c0_watchhi,4"      },
+  { 19, 5, "c0_watchhi,5"      },
+  { 19, 6, "c0_watchhi,6"      },
+  { 19, 7, "c0_watchhi,7"      },
+  { 25, 1, "c0_perfcnt,1"      },
+  { 25, 2, "c0_perfcnt,2"      },
+  { 25, 3, "c0_perfcnt,3"      },
+  { 25, 4, "c0_perfcnt,4"      },
+  { 25, 5, "c0_perfcnt,5"      },
+  { 25, 6, "c0_perfcnt,6"      },
+  { 25, 7, "c0_perfcnt,7"      },
+  { 27, 1, "c0_cacheerr,1"     },
+  { 27, 2, "c0_cacheerr,2"     },
+  { 27, 3, "c0_cacheerr,3"     },
+  { 28, 1, "c0_datalo"         },
+  { 29, 1, "c0_datahi"         }
+};
+
+static const char * const mips_cp0_names_mips3264r2[32] = {
+  "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
+  "c0_context",   "c0_pagemask",  "c0_wired",     "c0_hwrena",
+  "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
+  "c0_status",    "c0_cause",     "c0_epc",       "c0_prid",
+  "c0_config",    "c0_lladdr",    "c0_watchlo",   "c0_watchhi",
+  "c0_xcontext",  "$21",          "$22",          "c0_debug",
+  "c0_depc",      "c0_perfcnt",   "c0_errctl",    "c0_cacheerr",
+  "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
+};
+
+static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = {
+  {  4, 1, "c0_contextconfig"  },
+  {  5, 1, "c0_pagegrain"      },
+  { 12, 1, "c0_intctl"         },
+  { 12, 2, "c0_srsctl"         },
+  { 12, 3, "c0_srsmap"         },
+  { 15, 1, "c0_ebase"          },
+  { 16, 1, "c0_config1"                },
+  { 16, 2, "c0_config2"                },
+  { 16, 3, "c0_config3"                },
+  { 18, 1, "c0_watchlo,1"      },
+  { 18, 2, "c0_watchlo,2"      },
+  { 18, 3, "c0_watchlo,3"      },
+  { 18, 4, "c0_watchlo,4"      },
+  { 18, 5, "c0_watchlo,5"      },
+  { 18, 6, "c0_watchlo,6"      },
+  { 18, 7, "c0_watchlo,7"      },
+  { 19, 1, "c0_watchhi,1"      },
+  { 19, 2, "c0_watchhi,2"      },
+  { 19, 3, "c0_watchhi,3"      },
+  { 19, 4, "c0_watchhi,4"      },
+  { 19, 5, "c0_watchhi,5"      },
+  { 19, 6, "c0_watchhi,6"      },
+  { 19, 7, "c0_watchhi,7"      },
+  { 23, 1, "c0_tracecontrol"   },
+  { 23, 2, "c0_tracecontrol2"  },
+  { 23, 3, "c0_usertracedata"  },
+  { 23, 4, "c0_tracebpc"       },
+  { 25, 1, "c0_perfcnt,1"      },
+  { 25, 2, "c0_perfcnt,2"      },
+  { 25, 3, "c0_perfcnt,3"      },
+  { 25, 4, "c0_perfcnt,4"      },
+  { 25, 5, "c0_perfcnt,5"      },
+  { 25, 6, "c0_perfcnt,6"      },
+  { 25, 7, "c0_perfcnt,7"      },
+  { 27, 1, "c0_cacheerr,1"     },
+  { 27, 2, "c0_cacheerr,2"     },
+  { 27, 3, "c0_cacheerr,3"     },
+  { 28, 1, "c0_datalo"         },
+  { 28, 2, "c0_taglo1"         },
+  { 28, 3, "c0_datalo1"                },
+  { 28, 4, "c0_taglo2"         },
+  { 28, 5, "c0_datalo2"                },
+  { 28, 6, "c0_taglo3"         },
+  { 28, 7, "c0_datalo3"                },
+  { 29, 1, "c0_datahi"         },
+  { 29, 2, "c0_taghi1"         },
+  { 29, 3, "c0_datahi1"                },
+  { 29, 4, "c0_taghi2"         },
+  { 29, 5, "c0_datahi2"                },
+  { 29, 6, "c0_taghi3"         },
+  { 29, 7, "c0_datahi3"                },
+};
+
 /* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods.  */
 static const char * const mips_cp0_names_sb1[32] = {
   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
@@ -146,6 +249,45 @@ static const char * const mips_cp0_names_sb1[32] = {
   "c0_taglo_i",   "c0_taghi_i",   "c0_errorepc",  "c0_desave",
 };
 
+static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = {
+  { 16, 1, "c0_config1"                },
+  { 18, 1, "c0_watchlo,1"      },
+  { 19, 1, "c0_watchhi,1"      },
+  { 22, 0, "c0_perftrace"      },
+  { 23, 3, "c0_edebug"         },
+  { 25, 1, "c0_perfcnt,1"      },
+  { 25, 2, "c0_perfcnt,2"      },
+  { 25, 3, "c0_perfcnt,3"      },
+  { 25, 4, "c0_perfcnt,4"      },
+  { 25, 5, "c0_perfcnt,5"      },
+  { 25, 6, "c0_perfcnt,6"      },
+  { 25, 7, "c0_perfcnt,7"      },
+  { 26, 1, "c0_buserr_pa"      },
+  { 27, 1, "c0_cacheerr_d"     },
+  { 27, 3, "c0_cacheerr_d_pa"  },
+  { 28, 1, "c0_datalo_i"       },
+  { 28, 2, "c0_taglo_d"                },
+  { 28, 3, "c0_datalo_d"       },
+  { 29, 1, "c0_datahi_i"       },
+  { 29, 2, "c0_taghi_d"                },
+  { 29, 3, "c0_datahi_d"       },
+};
+
+static const char * const mips_hwr_names_numeric[32] = {
+  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
+static const char * const mips_hwr_names_mips3264r2[32] = {
+  "hwr_cpunum",   "hwr_synci_step", "hwr_cc",     "hwr_ccres",
+  "$4",          "$5",            "$6",           "$7",
+  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
+  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
+  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
+};
+
 struct mips_abi_choice {
   const char *name;
   const char * const *gpr_names;
@@ -166,49 +308,58 @@ struct mips_arch_choice {
   int processor;
   int isa;
   const char * const *cp0_names;
+  const struct mips_cp0sel_name *cp0sel_names;
+  unsigned int cp0sel_names_len;
+  const char * const *hwr_names;
 };
 
-struct mips_arch_choice mips_arch_choices[] = {
+const struct mips_arch_choice mips_arch_choices[] = {
   { "numeric", 0, 0, 0, 0,
-    mips_cp0_names_numeric },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+
   { "r3000",   1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r3900",   1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4000",   1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4010",   1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "vr4100",  1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "vr4111",  1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "vr4120",  1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4300",   1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4400",   1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4600",   1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r4650",   1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r5000",   1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "vr5400",  1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "vr5500",  1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r6000",   1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "rm7000",  1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "rm9000",  1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r8000",   1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r10000",  1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r12000",  1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "mips5",   1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+
   /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
      Note that MIPS-3D and MDMX are not applicable to MIPS32.  (See
      _MIPS32 Architecture For Programmers Volume I: Introduction to the
@@ -216,19 +367,39 @@ struct mips_arch_choice mips_arch_choices[] = {
      page 1.  */
   { "mips32",  1, bfd_mach_mipsisa32, CPU_MIPS32,
     ISA_MIPS32 | INSN_MIPS16,
-    mips_cp0_names_mips3264 },
+    mips_cp0_names_mips3264,
+    mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
+    mips_hwr_names_numeric },
+
+  { "mips32r2",        1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
+    ISA_MIPS32R2 | INSN_MIPS16,
+    mips_cp0_names_mips3264r2,
+    mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+    mips_hwr_names_mips3264r2 },
+
   /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs.  */
   { "mips64",  1, bfd_mach_mipsisa64, CPU_MIPS64,
     ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
-    mips_cp0_names_mips3264 },
+    mips_cp0_names_mips3264,
+    mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
+    mips_hwr_names_numeric },
+
+  { "mips64r2",        1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
+    ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
+    mips_cp0_names_mips3264r2,
+    mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
+    mips_hwr_names_mips3264r2 },
+
   { "sb1",     1, bfd_mach_mips_sb1, CPU_SB1,
     ISA_MIPS64 | INSN_MIPS3D | INSN_SB1,
-    mips_cp0_names_sb1 },
+    mips_cp0_names_sb1,
+    mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
+    mips_hwr_names_numeric },
 
   /* This entry, mips16, is here only for ISA/processor selection; do
      not print its name.  */
   { "",                1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
-    NULL },
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
 };
 
 /* ISA and processor type to disassemble for, and register names to use.
@@ -239,6 +410,9 @@ static int mips_isa;
 static const char * const *mips_gpr_names;
 static const char * const *mips_fpr_names;
 static const char * const *mips_cp0_names;
+static const struct mips_cp0sel_name *mips_cp0sel_names;
+static int mips_cp0sel_names_len;
+static const char * const *mips_hwr_names;
 
 static const struct mips_abi_choice *choose_abi_by_name
   PARAMS ((const char *, unsigned int));
@@ -246,6 +420,9 @@ static const struct mips_arch_choice *choose_arch_by_name
   PARAMS ((const char *, unsigned int));
 static const struct mips_arch_choice *choose_arch_by_number
   PARAMS ((unsigned long));
+static const struct mips_cp0sel_name *lookup_mips_cp0sel_name
+  PARAMS ((const struct mips_cp0sel_name *, unsigned int, unsigned int,
+          unsigned int));
 \f
 static const struct mips_abi_choice *
 choose_abi_by_name (name, namelen)
@@ -317,19 +494,22 @@ set_default_mips_dis_options (info)
   const struct mips_arch_choice *chosen_arch;
 
   /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names,
-     and numeric FPR and CP0 register names.  */
+     and numeric FPR, CP0 register, and HWR names.  */
   mips_isa = ISA_MIPS3;
   mips_processor =  CPU_R3000;
   mips_gpr_names = mips_gpr_names_oldabi;
   mips_fpr_names = mips_fpr_names_numeric;
   mips_cp0_names = mips_cp0_names_numeric;
+  mips_cp0sel_names = NULL;
+  mips_cp0sel_names_len = 0;
+  mips_hwr_names = mips_hwr_names_numeric;
 
   /* If an ELF "newabi" binary, use the n32/(n)64 GPR names.  */
-  if (info->flavour == bfd_target_elf_flavour && info->symbols != NULL)
+  if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
     {
       Elf_Internal_Ehdr *header;
 
-      header = elf_elfheader (bfd_asymbol_bfd (*(info->symbols)));
+      header = elf_elfheader (info->section->owner);
       if (is_newabi (header))
        mips_gpr_names = mips_gpr_names_newabi;
     }
@@ -346,8 +526,10 @@ set_default_mips_dis_options (info)
     {
       mips_processor = chosen_arch->processor;
       mips_isa = chosen_arch->isa;
-      if (chosen_arch->cp0_names != NULL)
-       mips_cp0_names = chosen_arch->cp0_names;
+      mips_cp0_names = chosen_arch->cp0_names;
+      mips_cp0sel_names = chosen_arch->cp0sel_names;
+      mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+      mips_hwr_names = chosen_arch->hwr_names;
     }
 #endif
 }
@@ -383,7 +565,7 @@ parse_mips_dis_option (option, len)
       && strlen("gpr-names") == optionlen)
     {
       chosen_abi = choose_abi_by_name (val, vallen);
-      if (chosen_abi != NULL && chosen_abi->gpr_names != NULL)
+      if (chosen_abi != NULL)
        mips_gpr_names = chosen_abi->gpr_names;
       return;
     }
@@ -392,7 +574,7 @@ parse_mips_dis_option (option, len)
       && strlen("fpr-names") == optionlen)
     {
       chosen_abi = choose_abi_by_name (val, vallen);
-      if (chosen_abi != NULL && chosen_abi->fpr_names != NULL)
+      if (chosen_abi != NULL)
        mips_fpr_names = chosen_abi->fpr_names;
       return;
     }
@@ -401,8 +583,21 @@ parse_mips_dis_option (option, len)
       && strlen("cp0-names") == optionlen)
     {
       chosen_arch = choose_arch_by_name (val, vallen);
-      if (chosen_arch != NULL && chosen_arch->cp0_names != NULL)
-       mips_cp0_names = chosen_arch->cp0_names;
+      if (chosen_arch != NULL)
+       {
+         mips_cp0_names = chosen_arch->cp0_names;
+         mips_cp0sel_names = chosen_arch->cp0sel_names;
+         mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+       }
+      return;
+    }
+
+  if (strncmp("hwr-names", option, optionlen) == 0
+      && strlen("hwr-names") == optionlen)
+    {
+      chosen_arch = choose_arch_by_name (val, vallen);
+      if (chosen_arch != NULL)
+       mips_hwr_names = chosen_arch->hwr_names;
       return;
     }
 
@@ -416,16 +611,16 @@ parse_mips_dis_option (option, len)
       chosen_abi = choose_abi_by_name (val, vallen);
       if (chosen_abi != NULL)
        {
-         if (chosen_abi->gpr_names != NULL)
-           mips_gpr_names = chosen_abi->gpr_names;
-         if (chosen_abi->fpr_names != NULL)
-           mips_fpr_names = chosen_abi->fpr_names;
+         mips_gpr_names = chosen_abi->gpr_names;
+         mips_fpr_names = chosen_abi->fpr_names;
        }
       chosen_arch = choose_arch_by_name (val, vallen);
       if (chosen_arch != NULL)
        {
-         if (chosen_arch->cp0_names != NULL)
-           mips_cp0_names = chosen_arch->cp0_names;
+         mips_cp0_names = chosen_arch->cp0_names;
+         mips_cp0sel_names = chosen_arch->cp0sel_names;
+         mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
+         mips_hwr_names = chosen_arch->hwr_names;
        }
       return;
     }
@@ -464,278 +659,374 @@ parse_mips_dis_options (options)
     }
 }
 
+static const struct mips_cp0sel_name *
+lookup_mips_cp0sel_name(names, len, cp0reg, sel)
+       const struct mips_cp0sel_name *names;
+       unsigned int len, cp0reg, sel;
+{
+  unsigned int i;
+
+  for (i = 0; i < len; i++)
+    if (names[i].cp0reg == cp0reg && names[i].sel == sel)
+      return &names[i];
+  return NULL;
+}
 \f
 /* Print insn arguments for 32/64-bit code.  */
 
 static void
-print_insn_arg (d, l, pc, info)
+print_insn_args (d, l, pc, info)
      const char *d;
      register unsigned long int l;
      bfd_vma pc;
      struct disassemble_info *info;
 {
   int op, delta;
+  unsigned int lsb, msb, msbd;
 
-  switch (*d)
-    {
-    case ',':
-    case '(':
-    case ')':
-    case '[':
-    case ']':
-      (*info->fprintf_func) (info->stream, "%c", *d);
-      break;
+  lsb = 0;
 
-    case 's':
-    case 'b':
-    case 'r':
-    case 'v':
-      (*info->fprintf_func) (info->stream, "%s",
-                            mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
-      break;
-
-    case 't':
-    case 'w':
-      (*info->fprintf_func) (info->stream, "%s",
-                            mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
-      break;
-
-    case 'i':
-    case 'u':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
-      break;
-
-    case 'j': /* Same as i, but sign-extended.  */
-    case 'o':
-      delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
-      if (delta & 0x8000)
-       delta |= ~0xffff;
-      (*info->fprintf_func) (info->stream, "%d",
-                            delta);
-      break;
-
-    case 'h':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (unsigned int) ((l >> OP_SH_PREFX)
-                                            & OP_MASK_PREFX));
-      break;
-
-    case 'k':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (unsigned int) ((l >> OP_SH_CACHE)
-                                            & OP_MASK_CACHE));
-      break;
-
-    case 'a':
-      info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
-                     | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
-      (*info->print_address_func) (info->target, info);
-      break;
+  for (; *d != '\0'; d++)
+    {
+      switch (*d)
+       {
+       case ',':
+       case '(':
+       case ')':
+       case '[':
+       case ']':
+         (*info->fprintf_func) (info->stream, "%c", *d);
+         break;
+
+       case '+':
+         /* Extension character; switch for second char.  */
+         d++;
+         switch (*d)
+           {
+           case '\0':
+             /* xgettext:c-format */
+             (*info->fprintf_func) (info->stream,
+                                    _("# internal error, incomplete extension sequence (+)"));
+             return;
+
+           case 'A':
+             lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
+             (*info->fprintf_func) (info->stream, "0x%x", lsb);
+             break;
+       
+           case 'B':
+             msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
+             (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
+             break;
+
+           case 'C':
+           case 'H':
+             msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
+             (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
+             break;
+
+           case 'D':
+             {
+               const struct mips_cp0sel_name *n;
+               unsigned int cp0reg, sel;
+
+               cp0reg = (l >> OP_SH_RD) & OP_MASK_RD;
+               sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
+
+               /* CP0 register including 'sel' code for mtcN (et al.), to be
+                  printed textually if known.  If not known, print both
+                  CP0 register name and sel numerically since CP0 register
+                  with sel 0 may have a name unrelated to register being
+                  printed.  */
+               n = lookup_mips_cp0sel_name(mips_cp0sel_names,
+                                           mips_cp0sel_names_len, cp0reg, sel);
+               if (n != NULL)
+                 (*info->fprintf_func) (info->stream, "%s", n->name);
+               else
+                 (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
+               break;
+             }
 
-    case 'p':
-      /* Sign extend the displacement.  */
-      delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
-      if (delta & 0x8000)
-       delta |= ~0xffff;
-      info->target = (delta << 2) + pc + INSNLEN;
-      (*info->print_address_func) (info->target, info);
-      break;
+           case 'E':
+             lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
+             (*info->fprintf_func) (info->stream, "0x%x", lsb);
+             break;
+       
+           case 'F':
+             msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
+             (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
+             break;
+
+           case 'G':
+             msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32;
+             (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
+             break;
+
+           default:
+             /* xgettext:c-format */
+             (*info->fprintf_func) (info->stream,
+                                    _("# internal error, undefined extension sequence (+%c)"),
+                                    *d);
+             return;
+           }
+         break;
 
-    case 'd':
-      (*info->fprintf_func) (info->stream, "%s",
-                            mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
-      break;
+       case 's':
+       case 'b':
+       case 'r':
+       case 'v':
+         (*info->fprintf_func) (info->stream, "%s",
+                                mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
+         break;
 
-    case 'U':
-      {
-       /* First check for both rd and rt being equal.  */
-       unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
-       if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
+       case 't':
+       case 'w':
          (*info->fprintf_func) (info->stream, "%s",
-                                mips_gpr_names[reg]);
-       else
+                                mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
+         break;
+
+       case 'i':
+       case 'u':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
+         break;
+
+       case 'j': /* Same as i, but sign-extended.  */
+       case 'o':
+         delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
+         if (delta & 0x8000)
+           delta |= ~0xffff;
+         (*info->fprintf_func) (info->stream, "%d",
+                                delta);
+         break;
+
+       case 'h':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (unsigned int) ((l >> OP_SH_PREFX)
+                                                & OP_MASK_PREFX));
+         break;
+
+       case 'k':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (unsigned int) ((l >> OP_SH_CACHE)
+                                                & OP_MASK_CACHE));
+         break;
+
+       case 'a':
+         info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
+                         | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
+         (*info->print_address_func) (info->target, info);
+         break;
+
+       case 'p':
+         /* Sign extend the displacement.  */
+         delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
+         if (delta & 0x8000)
+           delta |= ~0xffff;
+         info->target = (delta << 2) + pc + INSNLEN;
+         (*info->print_address_func) (info->target, info);
+         break;
+
+       case 'd':
+         (*info->fprintf_func) (info->stream, "%s",
+                                mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
+         break;
+
+       case 'U':
          {
-           /* If one is zero use the other.  */
-           if (reg == 0)
-             (*info->fprintf_func) (info->stream, "%s",
-                                    mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
-           else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
+           /* First check for both rd and rt being equal.  */
+           unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
+           if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
              (*info->fprintf_func) (info->stream, "%s",
                                     mips_gpr_names[reg]);
-           else /* Bogus, result depends on processor.  */
-             (*info->fprintf_func) (info->stream, "%s or %s",
-                                    mips_gpr_names[reg],
-                                    mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
+           else
+             {
+               /* If one is zero use the other.  */
+               if (reg == 0)
+                 (*info->fprintf_func) (info->stream, "%s",
+                                        mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
+               else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
+                 (*info->fprintf_func) (info->stream, "%s",
+                                        mips_gpr_names[reg]);
+               else /* Bogus, result depends on processor.  */
+                 (*info->fprintf_func) (info->stream, "%s or %s",
+                                        mips_gpr_names[reg],
+                                        mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
+             }
          }
-      }
-      break;
-
-    case 'z':
-      (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
-      break;
-
-    case '<':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
-      break;
-
-    case 'c':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (l >> OP_SH_CODE) & OP_MASK_CODE);
-      break;
-
-    case 'q':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (l >> OP_SH_CODE2) & OP_MASK_CODE2);
-      break;
-
-    case 'C':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (l >> OP_SH_COPZ) & OP_MASK_COPZ);
-      break;
-
-    case 'B':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (l >> OP_SH_CODE20) & OP_MASK_CODE20);
-      break;
-
-    case 'J':
-      (*info->fprintf_func) (info->stream, "0x%x",
-                            (l >> OP_SH_CODE19) & OP_MASK_CODE19);
-      break;
-
-    case 'S':
-    case 'V':
-      (*info->fprintf_func) (info->stream, "%s",
-                            mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
-      break;
-
-    case 'T':
-    case 'W':
-      (*info->fprintf_func) (info->stream, "%s",
-                            mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
-      break;
-
-    case 'D':
-      (*info->fprintf_func) (info->stream, "%s",
-                            mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
-      break;
-
-    case 'R':
-      (*info->fprintf_func) (info->stream, "%s",
-                            mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
-      break;
-
-    case 'E':
-      /* Coprocessor register for lwcN instructions, et al.
-
-        Note that there is no load/store cp0 instructions, and
-        that FPU (cp1) instructions disassemble this field using
-        'T' format.  Therefore, until we gain understanding of
-        cp2 register names,
-        we can simply print the register numbers.  */
-      (*info->fprintf_func) (info->stream, "$%d",
-                            (l >> OP_SH_RT) & OP_MASK_RT);
-      break;
-
-    case 'G':
-      /* Coprocessor register for mtcN instructions, et al.
-        Note that FPU (cp1) instructions disassemble this field using
-        'S' format.  Therefore, we only need to worry about cp0, cp2,
-        and cp3.  */
-      op = (l >> OP_SH_OP) & OP_MASK_OP;
-      if (op == OP_OP_COP0)
-        (*info->fprintf_func) (info->stream, "%s",
-                              mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
-      else
-        (*info->fprintf_func) (info->stream, "$%d",
-                              (l >> OP_SH_RD) & OP_MASK_RD);
-      break;
-
-    case 'N':
-      (*info->fprintf_func) (info->stream, "$fcc%d",
-                            (l >> OP_SH_BCC) & OP_MASK_BCC);
-      break;
-
-    case 'M':
-      (*info->fprintf_func) (info->stream, "$fcc%d",
-                            (l >> OP_SH_CCC) & OP_MASK_CCC);
-      break;
-
-    case 'P':
-      (*info->fprintf_func) (info->stream, "%d",
-                            (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
-      break;
-
-    case 'e':
-      (*info->fprintf_func) (info->stream, "%d",
-                            (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
-      break;
-
-    case '%':
-      (*info->fprintf_func) (info->stream, "%d",
-                            (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
-      break;
+         break;
+
+       case 'z':
+         (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
+         break;
+
+       case '<':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
+         break;
+
+       case 'c':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (l >> OP_SH_CODE) & OP_MASK_CODE);
+         break;
+
+       case 'q':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (l >> OP_SH_CODE2) & OP_MASK_CODE2);
+         break;
+
+       case 'C':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (l >> OP_SH_COPZ) & OP_MASK_COPZ);
+         break;
+
+       case 'B':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (l >> OP_SH_CODE20) & OP_MASK_CODE20);
+         break;
+
+       case 'J':
+         (*info->fprintf_func) (info->stream, "0x%x",
+                                (l >> OP_SH_CODE19) & OP_MASK_CODE19);
+         break;
+
+       case 'S':
+       case 'V':
+         (*info->fprintf_func) (info->stream, "%s",
+                                mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
+         break;
 
-    case 'H':
-      (*info->fprintf_func) (info->stream, "%d",
-                            (l >> OP_SH_SEL) & OP_MASK_SEL);
-      break;
+       case 'T':
+       case 'W':
+         (*info->fprintf_func) (info->stream, "%s",
+                                mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
+         break;
 
-    case 'O':
-      (*info->fprintf_func) (info->stream, "%d",
-                            (l >> OP_SH_ALN) & OP_MASK_ALN);
-      break;
+       case 'D':
+         (*info->fprintf_func) (info->stream, "%s",
+                                mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
+         break;
 
-    case 'Q':
-      {
-       unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
-       if ((vsel & 0x10) == 0)
-         {
-           int fmt;
-           vsel &= 0x0f;
-           for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
-             if ((vsel & 1) == 0)
-               break;
-           (*info->fprintf_func) (info->stream, "$v%d[%d]",
-                                  (l >> OP_SH_FT) & OP_MASK_FT,
-                                  vsel >> 1);
-         }
-       else if ((vsel & 0x08) == 0)
-         {
-           (*info->fprintf_func) (info->stream, "$v%d",
-                                  (l >> OP_SH_FT) & OP_MASK_FT);
-         }
-       else
+       case 'R':
+         (*info->fprintf_func) (info->stream, "%s",
+                                mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
+         break;
+
+       case 'E':
+         /* Coprocessor register for lwcN instructions, et al.
+
+            Note that there is no load/store cp0 instructions, and
+            that FPU (cp1) instructions disassemble this field using
+            'T' format.  Therefore, until we gain understanding of
+            cp2 register names, we can simply print the register
+            numbers.  */
+         (*info->fprintf_func) (info->stream, "$%d",
+                                (l >> OP_SH_RT) & OP_MASK_RT);
+         break;
+
+       case 'G':
+         /* Coprocessor register for mtcN instructions, et al.  Note
+            that FPU (cp1) instructions disassemble this field using
+            'S' format.  Therefore, we only need to worry about cp0,
+            cp2, and cp3.  */
+         op = (l >> OP_SH_OP) & OP_MASK_OP;
+         if (op == OP_OP_COP0)
+           (*info->fprintf_func) (info->stream, "%s",
+                                  mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
+         else
+           (*info->fprintf_func) (info->stream, "$%d",
+                                  (l >> OP_SH_RD) & OP_MASK_RD);
+         break;
+
+       case 'K':
+         (*info->fprintf_func) (info->stream, "%s",
+                                mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
+         break;
+
+       case 'N':
+         (*info->fprintf_func) (info->stream, "$fcc%d",
+                                (l >> OP_SH_BCC) & OP_MASK_BCC);
+         break;
+
+       case 'M':
+         (*info->fprintf_func) (info->stream, "$fcc%d",
+                                (l >> OP_SH_CCC) & OP_MASK_CCC);
+         break;
+
+       case 'P':
+         (*info->fprintf_func) (info->stream, "%d",
+                                (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
+         break;
+
+       case 'e':
+         (*info->fprintf_func) (info->stream, "%d",
+                                (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
+         break;
+
+       case '%':
+         (*info->fprintf_func) (info->stream, "%d",
+                                (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
+         break;
+
+       case 'H':
+         (*info->fprintf_func) (info->stream, "%d",
+                                (l >> OP_SH_SEL) & OP_MASK_SEL);
+         break;
+
+       case 'O':
+         (*info->fprintf_func) (info->stream, "%d",
+                                (l >> OP_SH_ALN) & OP_MASK_ALN);
+         break;
+
+       case 'Q':
          {
-           (*info->fprintf_func) (info->stream, "0x%x",
-                                  (l >> OP_SH_FT) & OP_MASK_FT);
+           unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
+           if ((vsel & 0x10) == 0)
+             {
+               int fmt;
+               vsel &= 0x0f;
+               for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
+                 if ((vsel & 1) == 0)
+                   break;
+               (*info->fprintf_func) (info->stream, "$v%d[%d]",
+                                      (l >> OP_SH_FT) & OP_MASK_FT,
+                                      vsel >> 1);
+             }
+           else if ((vsel & 0x08) == 0)
+             {
+               (*info->fprintf_func) (info->stream, "$v%d",
+                                      (l >> OP_SH_FT) & OP_MASK_FT);
+             }
+           else
+             {
+               (*info->fprintf_func) (info->stream, "0x%x",
+                                      (l >> OP_SH_FT) & OP_MASK_FT);
+             }
          }
-      }
-      break;
-
-    case 'X':
-      (*info->fprintf_func) (info->stream, "$v%d",
-                            (l >> OP_SH_FD) & OP_MASK_FD);
-      break;
-
-    case 'Y':
-      (*info->fprintf_func) (info->stream, "$v%d",
-                            (l >> OP_SH_FS) & OP_MASK_FS);
-      break;
-
-    case 'Z':
-      (*info->fprintf_func) (info->stream, "$v%d",
-                            (l >> OP_SH_FT) & OP_MASK_FT);
-      break;
-
-    default:
-      /* xgettext:c-format */
-      (*info->fprintf_func) (info->stream,
-                            _("# internal error, undefined modifier(%c)"),
-                            *d);
-      break;
+         break;
+
+       case 'X':
+         (*info->fprintf_func) (info->stream, "$v%d",
+                                (l >> OP_SH_FD) & OP_MASK_FD);
+         break;
+
+       case 'Y':
+         (*info->fprintf_func) (info->stream, "$v%d",
+                                (l >> OP_SH_FS) & OP_MASK_FS);
+         break;
+
+       case 'Z':
+         (*info->fprintf_func) (info->stream, "$v%d",
+                                (l >> OP_SH_FT) & OP_MASK_FT);
+         break;
+
+       default:
+         /* xgettext:c-format */
+         (*info->fprintf_func) (info->stream,
+                                _("# internal error, undefined modifier(%c)"),
+                                *d);
+         return;
+       }
     }
 }
 \f
@@ -844,8 +1135,7 @@ print_insn_mips (memaddr, word, info)
              if (d != NULL && *d != '\0')
                {
                  (*info->fprintf_func) (info->stream, "\t");
-                 for (; *d != '\0'; d++)
-                   print_insn_arg (d, word, memaddr, info);
+                 print_insn_args (d, word, memaddr, info);
                }
 
              return INSNLEN;
@@ -1494,7 +1784,7 @@ void
 print_mips_disassembler_options (stream)
      FILE *stream;
 {
-  int i;
+  unsigned int i;
 
   fprintf (stream, _("\n\
 The following MIPS specific disassembler options are supported for use\n\
@@ -1513,25 +1803,30 @@ with the -M switch (multiple options should be separated by commas):\n"));
                            specified architecture.\n\
                            Default: based on binary being disassembled.\n"));
 
+  fprintf (stream, _("\n\
+  hwr-names=ARCH           Print HWR names according to specified \n\
+                          architecture.\n\
+                           Default: based on binary being disassembled.\n"));
+
   fprintf (stream, _("\n\
   reg-names=ABI            Print GPR and FPR names according to\n\
                            specified ABI.\n"));
 
   fprintf (stream, _("\n\
-  reg-names=ARCH           Print CP0 register names according to\n\
+  reg-names=ARCH           Print CP0 register and HWR names according to\n\
                            specified architecture.\n"));
 
   fprintf (stream, _("\n\
   For the options above, the following values are supported for \"ABI\":\n\
    "));
-  for (i = 0; mips_abi_choices[i].name != NULL; i++)
+  for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
     fprintf (stream, " %s", mips_abi_choices[i].name);
   fprintf (stream, _("\n"));
 
   fprintf (stream, _("\n\
   For the options above, The following values are supported for \"ARCH\":\n\
    "));
-  for (i = 0; mips_arch_choices[i].name != NULL; i++)
+  for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
     if (*mips_arch_choices[i].name != '\0')
       fprintf (stream, " %s", mips_arch_choices[i].name);
   fprintf (stream, _("\n"));
This page took 0.037023 seconds and 4 git commands to generate.