summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/opcodes/ppc-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/opcodes/ppc-dis.c')
-rw-r--r--contrib/binutils/opcodes/ppc-dis.c145
1 files changed, 99 insertions, 46 deletions
diff --git a/contrib/binutils/opcodes/ppc-dis.c b/contrib/binutils/opcodes/ppc-dis.c
index 9dc586d..2545a36 100644
--- a/contrib/binutils/opcodes/ppc-dis.c
+++ b/contrib/binutils/opcodes/ppc-dis.c
@@ -1,6 +1,5 @@
-/* $FreeBSD$ */
/* ppc-dis.c -- Disassemble PowerPC instructions
- Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004
+ Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support
@@ -18,7 +17,7 @@ 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
#include <stdio.h>
#include "sysdep.h"
@@ -33,11 +32,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
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. */
@@ -45,8 +39,7 @@ struct dis_private {
static int
powerpc_dialect (struct disassemble_info *info)
{
- int dialect = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC;
- void *pd = &info->private_data;
+ int dialect = PPC_OPCODE_PPC;
if (BFD_DEFAULT_TARGET_SIZE == 64)
dialect |= PPC_OPCODE_64;
@@ -57,31 +50,42 @@ powerpc_dialect (struct disassemble_info *info)
else if ((info->mach == bfd_mach_ppc_e500)
|| (info->disassembler_options
&& strstr (info->disassembler_options, "e500") != NULL))
- {
- dialect |= PPC_OPCODE_BOOKE
- | PPC_OPCODE_SPE | PPC_OPCODE_ISEL
- | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
- | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
- | PPC_OPCODE_RFMCI;
- /* efs* and AltiVec conflict. */
- dialect &= ~PPC_OPCODE_ALTIVEC;
- }
+ dialect |= (PPC_OPCODE_BOOKE
+ | PPC_OPCODE_SPE | PPC_OPCODE_ISEL
+ | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
+ | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
+ | PPC_OPCODE_RFMCI);
else if (info->disassembler_options
&& strstr (info->disassembler_options, "efs") != NULL)
- {
- dialect |= PPC_OPCODE_EFS;
- /* efs* and AltiVec conflict. */
- dialect &= ~PPC_OPCODE_ALTIVEC;
- }
+ 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_COMMON | PPC_OPCODE_ALTIVEC);
if (info->disassembler_options
&& 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;
@@ -93,7 +97,7 @@ powerpc_dialect (struct disassemble_info *info)
dialect |= PPC_OPCODE_64;
}
- ((struct dis_private *) pd)->dialect = dialect;
+ info->private_data = (char *) 0 + dialect;
return dialect;
}
@@ -102,8 +106,7 @@ powerpc_dialect (struct disassemble_info *info)
int
print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
{
- void *pd = &info->private_data;
- int dialect = ((struct dis_private *) pd)->dialect;
+ int dialect = (char *) info->private_data - (char *) 0;
return print_insn_powerpc (memaddr, info, 1, dialect);
}
@@ -112,8 +115,7 @@ print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
int
print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
{
- void *pd = &info->private_data;
- int dialect = ((struct dis_private *) pd)->dialect;
+ int dialect = (char *) info->private_data - (char *) 0;
return print_insn_powerpc (memaddr, info, 0, dialect);
}
@@ -125,6 +127,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
@@ -170,6 +222,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)
@@ -203,6 +256,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;
@@ -215,23 +269,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)
{
@@ -256,8 +305,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" };
@@ -311,9 +360,13 @@ 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, " 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");
}
OpenPOWER on IntegriCloud