* configure.ac: Raise minimum makeinfo version to 4.6.
[deliverable/binutils-gdb.git] / opcodes / ppc-dis.c
index b2eb427edf1ed9f3ed91fa7276c821c68f316912..861881bb81cbb9c3d15f715e5915017ad4d8b9f3 100644 (file)
@@ -1,23 +1,24 @@
 /* ppc-dis.c -- Disassemble PowerPC instructions
-   Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
 
-This file is part of GDB, GAS, and the GNU binutils.
+   This file is part of the GNU opcodes library.
 
-GDB, GAS, and the GNU binutils are free software; you can redistribute
-them and/or modify them under the terms of the GNU General Public
-License as published by the Free Software Foundation; either version
-2, or (at your option) any later version.
+   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 3, or (at your option)
+   any later version.
 
-GDB, GAS, and the GNU binutils are distributed in the hope that they
-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 file; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the
+   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 #include <stdio.h>
 #include "sysdep.h"
@@ -32,11 +33,6 @@ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, US
 
 static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
 
-struct dis_private {
-  /* Stash the result of parsing disassembler_options here.  */
-  int dialect;
-};
-
 /* Determine which set of machines to disassemble for.  PPC403/601 or
    BookE.  For convenience, also disassemble instructions supported
    by the AltiVec vector unit.  */
@@ -50,6 +46,9 @@ powerpc_dialect (struct disassemble_info *info)
     dialect |= PPC_OPCODE_64;
 
   if (info->disassembler_options
+      && strstr (info->disassembler_options, "ppcps") != NULL)
+    dialect |= PPC_OPCODE_PPCPS;
+  else if (info->disassembler_options
       && strstr (info->disassembler_options, "booke") != NULL)
     dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
   else if ((info->mach == bfd_mach_ppc_e500)
@@ -63,6 +62,13 @@ powerpc_dialect (struct disassemble_info *info)
   else if (info->disassembler_options
           && strstr (info->disassembler_options, "efs") != NULL)
     dialect |= PPC_OPCODE_EFS;
+  else if (info->disassembler_options
+          && strstr (info->disassembler_options, "e300") != NULL)
+    dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON;
+  else if (info->disassembler_options
+          && strstr (info->disassembler_options, "440") != NULL)
+    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32
+      | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI;
   else
     dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
                | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC);
@@ -71,6 +77,18 @@ powerpc_dialect (struct disassemble_info *info)
       && strstr (info->disassembler_options, "power4") != NULL)
     dialect |= PPC_OPCODE_POWER4;
 
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power5") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "cell") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power6") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC;
+
   if (info->disassembler_options
       && strstr (info->disassembler_options, "any") != NULL)
     dialect |= PPC_OPCODE_ANY;
@@ -83,7 +101,7 @@ powerpc_dialect (struct disassemble_info *info)
        dialect |= PPC_OPCODE_64;
     }
 
-  ((struct dis_private *) &info->private_data)->dialect = dialect;
+  info->private_data = (char *) 0 + dialect;
   return dialect;
 }
 
@@ -92,7 +110,7 @@ powerpc_dialect (struct disassemble_info *info)
 int
 print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
 {
-  int dialect = ((struct dis_private *) &info->private_data)->dialect;
+  int dialect = (char *) info->private_data - (char *) 0;
   return print_insn_powerpc (memaddr, info, 1, dialect);
 }
 
@@ -101,7 +119,7 @@ print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
 int
 print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
 {
-  int dialect = ((struct dis_private *) &info->private_data)->dialect;
+  int dialect = (char *) info->private_data - (char *) 0;
   return print_insn_powerpc (memaddr, info, 0, dialect);
 }
 
@@ -113,6 +131,56 @@ print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
   return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
 }
 
+/* Extract the operand value from the PowerPC or POWER instruction.  */
+
+static long
+operand_value_powerpc (const struct powerpc_operand *operand,
+                      unsigned long insn, int dialect)
+{
+  long value;
+  int invalid;
+  /* Extract the value from the instruction.  */
+  if (operand->extract)
+    value = (*operand->extract) (insn, dialect, &invalid);
+  else
+    {
+      value = (insn >> operand->shift) & operand->bitm;
+      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+       {
+         /* BITM is always some number of zeros followed by some
+            number of ones, followed by some numer of zeros.  */
+         unsigned long top = operand->bitm;
+         /* top & -top gives the rightmost 1 bit, so this
+            fills in any trailing zeros.  */
+         top |= (top & -top) - 1;
+         top &= ~(top >> 1);
+         value = (value ^ top) - top;
+       }
+    }
+
+  return value;
+}
+
+/* Determine whether the optional operand(s) should be printed.  */
+
+static int
+skip_optional_operands (const unsigned char *opindex,
+                       unsigned long insn, int dialect)
+{
+  const struct powerpc_operand *operand;
+
+  for (; *opindex != 0; opindex++)
+    {
+      operand = &powerpc_operands[*opindex];
+      if ((operand->flags & PPC_OPERAND_NEXT) != 0
+         || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+             && operand_value_powerpc (operand, insn, dialect) != 0))
+       return 0;
+    }
+
+  return 1;
+}
+
 /* Print a PowerPC or POWER instruction.  */
 
 static int
@@ -158,6 +226,7 @@ print_insn_powerpc (bfd_vma memaddr,
       int invalid;
       int need_comma;
       int need_paren;
+      int skip_optional;
 
       table_op = PPC_OP (opcode->opcode);
       if (op < table_op)
@@ -191,6 +260,7 @@ print_insn_powerpc (bfd_vma memaddr,
       /* Now extract and print the operands.  */
       need_comma = 0;
       need_paren = 0;
+      skip_optional = -1;
       for (opindex = opcode->operands; *opindex != 0; opindex++)
        {
          long value;
@@ -203,23 +273,18 @@ print_insn_powerpc (bfd_vma memaddr,
          if ((operand->flags & PPC_OPERAND_FAKE) != 0)
            continue;
 
-         /* Extract the value from the instruction.  */
-         if (operand->extract)
-           value = (*operand->extract) (insn, dialect, &invalid);
-         else
+         /* If all of the optional operands have the value zero,
+            then don't print any of them.  */
+         if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
            {
-             value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
-             if ((operand->flags & PPC_OPERAND_SIGNED) != 0
-                 && (value & (1 << (operand->bits - 1))) != 0)
-               value -= 1 << operand->bits;
+             if (skip_optional < 0)
+               skip_optional = skip_optional_operands (opindex, insn,
+                                                       dialect);
+             if (skip_optional)
+               continue;
            }
 
-         /* If the operand is optional, and the value is zero, don't
-            print anything.  */
-         if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
-             && (operand->flags & PPC_OPERAND_NEXT) == 0
-             && value == 0)
-           continue;
+         value = operand_value_powerpc (operand, insn, dialect);
 
          if (need_comma)
            {
@@ -244,8 +309,8 @@ print_insn_powerpc (bfd_vma memaddr,
            (*info->fprintf_func) (info->stream, "%ld", value);
          else
            {
-             if (operand->bits == 3)
-               (*info->fprintf_func) (info->stream, "cr%d", value);
+             if (operand->bitm == 7)
+               (*info->fprintf_func) (info->stream, "cr%ld", value);
              else
                {
                  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
@@ -299,9 +364,14 @@ The following PPC specific disassembler options are supported for use with\n\
 the -M switch:\n");
 
   fprintf (stream, "  booke|booke32|booke64    Disassemble the BookE instructions\n");
+  fprintf (stream, "  e300                     Disassemble the e300 instructions\n");
   fprintf (stream, "  e500|e500x2              Disassemble the e500 instructions\n");
+  fprintf (stream, "  440                      Disassemble the 440 instructions\n");
   fprintf (stream, "  efs                      Disassemble the EFS instructions\n");
+  fprintf (stream, "  ppcps                    Disassemble the PowerPC paired singles instructions\n");
   fprintf (stream, "  power4                   Disassemble the Power4 instructions\n");
+  fprintf (stream, "  power5                   Disassemble the Power5 instructions\n");
+  fprintf (stream, "  power6                   Disassemble the Power6 instructions\n");
   fprintf (stream, "  32                       Do not disassemble 64-bit instructions\n");
   fprintf (stream, "  64                       Allow disassembly of 64-bit instructions\n");
 }
This page took 0.035307 seconds and 4 git commands to generate.