Change source files over to GPLv3.
[deliverable/binutils-gdb.git] / opcodes / mips-dis.c
index 21f20fb50358a1f1f95ebfbd5c74c618ec621c8f..3f09294a9b92bb99c34fa1047a6da80017300600 100644 (file)
@@ -1,20 +1,20 @@
 /* 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, 2003, 2005
+   2000, 2001, 2002, 2003, 2005, 2007
    Free Software Foundation, Inc.
    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
 
-   This file is part of GDB, GAS, and the GNU binutils.
+   This file is part of the GNU opcodes library.
 
-   This program is free software; you can redistribute it and/or modify
+   This library 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.
+   the Free Software Foundation; either version 3, 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.
+   It 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
@@ -51,12 +51,15 @@ struct mips_cp0sel_name
   const char * const name;
 };
 
-/* The mips16 register names.  */
-static const char * const mips16_reg_names[] =
+/* The mips16 registers.  */
+static const unsigned int mips16_to_32_reg_map[] =
 {
-  "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
+  16, 17, 2, 3, 4, 5, 6, 7
 };
 
+#define mips16_reg_names(rn)   mips_gpr_names[mips16_to_32_reg_map[rn]]
+
+
 static const char * const mips_gpr_names_numeric[32] =
 {
   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
@@ -181,7 +184,28 @@ static const char * const mips_cp0_names_mips3264r2[32] =
 static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] =
 {
   {  4, 1, "c0_contextconfig"  },
+  {  0, 1, "c0_mvpcontrol"     },
+  {  0, 2, "c0_mvpconf0"       },
+  {  0, 3, "c0_mvpconf1"       },
+  {  1, 1, "c0_vpecontrol"     },
+  {  1, 2, "c0_vpeconf0"       },
+  {  1, 3, "c0_vpeconf1"       },
+  {  1, 4, "c0_yqmask"         },
+  {  1, 5, "c0_vpeschedule"    },
+  {  1, 6, "c0_vpeschefback"   },
+  {  2, 1, "c0_tcstatus"       },
+  {  2, 2, "c0_tcbind"         },
+  {  2, 3, "c0_tcrestart"      },
+  {  2, 4, "c0_tchalt"         },
+  {  2, 5, "c0_tccontext"      },
+  {  2, 6, "c0_tcschedule"     },
+  {  2, 7, "c0_tcschefback"    },
   {  5, 1, "c0_pagegrain"      },
+  {  6, 1, "c0_srsconf0"       },
+  {  6, 2, "c0_srsconf1"       },
+  {  6, 3, "c0_srsconf2"       },
+  {  6, 4, "c0_srsconf3"       },
+  {  6, 5, "c0_srsconf4"       },
   { 12, 1, "c0_intctl"         },
   { 12, 2, "c0_srsctl"         },
   { 12, 3, "c0_srsmap"         },
@@ -370,26 +394,28 @@ const struct mips_arch_choice mips_arch_choices[] =
      MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
      page 1.  */
   { "mips32",  1, bfd_mach_mipsisa32, CPU_MIPS32,
-    ISA_MIPS32 | INSN_MIPS16 | INSN_DSP,
+    ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS,
     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 | INSN_DSP | INSN_MT,
+    (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2
+     | INSN_MIPS3D | INSN_MT),
     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 | INSN_DSP,
+    ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
     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 | INSN_DSP,
+    (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2
+     | INSN_DSP64 | INSN_MT | INSN_MDMX),
     mips_cp0_names_mips3264r2,
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_hwr_names_mips3264r2 },
@@ -549,7 +575,7 @@ parse_mips_dis_option (const char *option, unsigned int len)
   const struct mips_arch_choice *chosen_arch;
 
   /* Try to match options that are simple flags */
-  if (strncmp (option, "no-aliases", 10) == 0)
+  if (CONST_STRNEQ (option, "no-aliases"))
     {
       no_aliases = 1;
       return;
@@ -688,7 +714,8 @@ static void
 print_insn_args (const char *d,
                 register unsigned long int l,
                 bfd_vma pc,
-                struct disassemble_info *info)
+                struct disassemble_info *info,
+                const struct mips_opcode *opp)
 {
   int op, delta;
   unsigned int lsb, msb, msbd;
@@ -728,6 +755,26 @@ print_insn_args (const char *d,
              (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
              break;
 
+           case '1':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI1) & OP_MASK_UDI1);
+             break;
+             
+           case '2':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI2) & OP_MASK_UDI2);
+             break;
+             
+           case '3':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI3) & OP_MASK_UDI3);
+             break;
+      
+           case '4':
+             (*info->fprintf_func) (info->stream, "0x%lx",
+                                    (l >> OP_SH_UDI4) & OP_MASK_UDI4);
+             break;
+             
            case 'C':
            case 'H':
              msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
@@ -808,6 +855,11 @@ print_insn_args (const char *d,
            }
          break;
 
+       case '2':
+         (*info->fprintf_func) (info->stream, "0x%lx",
+                                (l >> OP_SH_BP) & OP_MASK_BP);
+         break;
+
        case '3':
          (*info->fprintf_func) (info->stream, "0x%lx",
                                 (l >> OP_SH_SA3) & OP_MASK_SA3);
@@ -939,6 +991,10 @@ print_insn_args (const char *d,
        case 'a':
          info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
                          | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
+         /* For gdb disassembler, force odd address on jalx.  */
+         if (info->flavour == bfd_target_unknown_flavour
+             && strcmp (opp->name, "jalx") == 0)
+           info->target |= 1;
          (*info->print_address_func) (info->target, info);
          break;
 
@@ -1069,7 +1125,9 @@ print_insn_args (const char *d,
          break;
 
        case 'N':
-         (*info->fprintf_func) (info->stream, "$fcc%ld",
+         (*info->fprintf_func) (info->stream,
+                                ((opp->pinfo & (FP_D | FP_S)) != 0
+                                 ? "$fcc%ld" : "$cc%ld"),
                                 (l >> OP_SH_BCC) & OP_MASK_BCC);
          break;
 
@@ -1247,7 +1305,7 @@ print_insn_mips (bfd_vma memaddr,
              if (d != NULL && *d != '\0')
                {
                  (*info->fprintf_func) (info->stream, "\t");
-                 print_insn_args (d, word, memaddr, info);
+                 print_insn_args (d, word, memaddr, info, op);
                }
 
              return INSNLEN;
@@ -1283,27 +1341,27 @@ print_mips16_insn_arg (char type,
     case 'y':
     case 'w':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_RY)
-                                              & MIPS16OP_MASK_RY)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_RY)
+                                              & MIPS16OP_MASK_RY)));
       break;
 
     case 'x':
     case 'v':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_RX)
-                                              & MIPS16OP_MASK_RX)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_RX)
+                                              & MIPS16OP_MASK_RX)));
       break;
 
     case 'z':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_RZ)
-                                              & MIPS16OP_MASK_RZ)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_RZ)
+                                              & MIPS16OP_MASK_RZ)));
       break;
 
     case 'Z':
       (*info->fprintf_func) (info->stream, "%s",
-                            mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
-                                              & MIPS16OP_MASK_MOVE32Z)]);
+                            mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z)
+                                              & MIPS16OP_MASK_MOVE32Z)));
       break;
 
     case '0':
@@ -1585,15 +1643,26 @@ print_mips16_insn_arg (char type,
                  }
              }
            info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
+           if (pcrel && branch
+               && info->flavour == bfd_target_unknown_flavour)
+             /* For gdb disassembler, maintain odd address.  */
+             info->target |= 1;
            (*info->print_address_func) (info->target, info);
          }
       }
       break;
 
     case 'a':
-      if (! use_extend)
-       extend = 0;
-      l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
+      {
+       int jalx = l & 0x400;
+
+       if (! use_extend)
+         extend = 0;
+       l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
+       if (!jalx && info->flavour == bfd_target_unknown_flavour)
+         /* For gdb disassembler, maintain odd address.  */
+         l |= 1;
+      }
       info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
       (*info->print_address_func) (info->target, info);
       info->insn_type = dis_jsr;
@@ -1656,6 +1725,92 @@ print_mips16_insn_arg (char type,
       }
       break;
 
+    case 'm':
+    case 'M':
+      /* MIPS16e save/restore.  */
+      {
+      int need_comma = 0;
+      int amask, args, statics;
+      int nsreg, smask;
+      int framesz;
+      int i, j;
+
+      l = l & 0x7f;
+      if (use_extend)
+        l |= extend << 16;
+
+      amask = (l >> 16) & 0xf;
+      if (amask == MIPS16_ALL_ARGS)
+        {
+          args = 4;
+          statics = 0;
+        }
+      else if (amask == MIPS16_ALL_STATICS)
+        {
+          args = 0;
+          statics = 4;
+        }
+      else
+        {
+          args = amask >> 2;
+          statics = amask & 3;
+        }
+
+      if (args > 0) {
+          (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
+          if (args > 1)
+            (*info->fprintf_func) (info->stream, "-%s",
+                                   mips_gpr_names[4 + args - 1]);
+          need_comma = 1;
+      }
+
+      framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
+      if (framesz == 0 && !use_extend)
+        framesz = 128;
+
+      (*info->fprintf_func) (info->stream, "%s%d", 
+                             need_comma ? "," : "",
+                             framesz);
+
+      if (l & 0x40)                   /* $ra */
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]);
+
+      nsreg = (l >> 24) & 0x7;
+      smask = 0;
+      if (l & 0x20)                   /* $s0 */
+        smask |= 1 << 0;
+      if (l & 0x10)                   /* $s1 */
+        smask |= 1 << 1;
+      if (nsreg > 0)                  /* $s2-$s8 */
+        smask |= ((1 << nsreg) - 1) << 2;
+
+      /* Find first set static reg bit.  */
+      for (i = 0; i < 9; i++)
+        {
+          if (smask & (1 << i))
+            {
+              (*info->fprintf_func) (info->stream, ",%s",
+                                     mips_gpr_names[i == 8 ? 30 : (16 + i)]);
+              /* Skip over string of set bits.  */
+              for (j = i; smask & (2 << j); j++)
+                continue;
+              if (j > i)
+                (*info->fprintf_func) (info->stream, "-%s",
+                                       mips_gpr_names[j == 8 ? 30 : (16 + j)]);
+              i = j + 1;
+            }
+        }
+
+      /* Statics $ax - $a3.  */
+      if (statics == 1)
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
+      else if (statics > 0) 
+        (*info->fprintf_func) (info->stream, ",%s-%s", 
+                               mips_gpr_names[7 - statics + 1],
+                               mips_gpr_names[7]);
+      }
+      break;
+
     default:
       /* xgettext:c-format */
       (*info->fprintf_func)
This page took 0.041855 seconds and 4 git commands to generate.