/* ppc-dis.c -- Disassemble PowerPC instructions
- Copyright 1994 Free Software Foundation, Inc.
+ Copyright 1994, 1995, 2000, 2001, 2002 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support
This file is part of GDB, GAS, and the GNU binutils.
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <stdio.h>
-#include "ansidecl.h"
#include "sysdep.h"
#include "dis-asm.h"
#include "opcode/ppc.h"
static int print_insn_powerpc PARAMS ((bfd_vma, struct disassemble_info *,
int bigendian, int dialect));
+static int powerpc_dialect PARAMS ((struct disassemble_info *));
+
+/* Determine which set of machines to disassemble for. PPC403/601 or
+ BookE. For convenience, also disassemble instructions supported
+ by the AltiVec vector unit. */
+
+int
+powerpc_dialect(info)
+ struct disassemble_info *info;
+{
+ int dialect = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC;
+
+ if (BFD_DEFAULT_TARGET_SIZE == 64)
+ dialect |= PPC_OPCODE_64;
+
+ if (info->disassembler_options
+ && (strcmp (info->disassembler_options, "booke") == 0
+ || strcmp (info->disassembler_options, "booke32") == 0
+ || strcmp (info->disassembler_options, "booke64") == 0))
+ dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
+ else
+ if ((info->mach == bfd_mach_ppc_e500)
+ || (info->disassembler_options
+ && ( strcmp (info->disassembler_options, "e500") == 0
+ || strcmp (info->disassembler_options, "e500x2") == 0)))
+ {
+ 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;
+ }
+ else
+ if (info->disassembler_options
+ && (strcmp (info->disassembler_options, "efs") == 0))
+ {
+ dialect |= PPC_OPCODE_EFS;
+ /* efs* and AltiVec conflict. */
+ dialect &= ~PPC_OPCODE_ALTIVEC;
+ }
+ else
+ dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
+ | PPC_OPCODE_COMMON);
+
+ if (info->disassembler_options
+ && strcmp (info->disassembler_options, "power4") == 0)
+ dialect |= PPC_OPCODE_POWER4;
+
+ if (info->disassembler_options)
+ {
+ if (strstr (info->disassembler_options, "32") != NULL)
+ dialect &= ~PPC_OPCODE_64;
+ else if (strstr (info->disassembler_options, "64") != NULL)
+ dialect |= PPC_OPCODE_64;
+ }
+
+ return dialect;
+}
+
/* Print a big endian PowerPC instruction. */
int
bfd_vma memaddr;
struct disassemble_info *info;
{
- return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_PPC);
+ return print_insn_powerpc (memaddr, info, 1, powerpc_dialect(info));
}
/* Print a little endian PowerPC instruction. */
bfd_vma memaddr;
struct disassemble_info *info;
{
- return print_insn_powerpc (memaddr, info, 0, PPC_OPCODE_PPC);
+ return print_insn_powerpc (memaddr, info, 0, powerpc_dialect(info));
}
/* Print a POWER (RS/6000) instruction. */
|| (opcode->flags & dialect) == 0)
continue;
+ if ((dialect & PPC_OPCODE_EFS) && (opcode->flags & PPC_OPCODE_ALTIVEC))
+ continue;
+
/* Make two passes over the operands. First see if any of them
have extraction functions, and, if they do, make sure the
instruction is valid. */
{
operand = powerpc_operands + *opindex;
if (operand->extract)
- (*operand->extract) (insn, &invalid);
+ (*operand->extract) (insn, dialect, &invalid);
}
if (invalid)
continue;
/* Extract the value from the instruction. */
if (operand->extract)
- value = (*operand->extract) (insn, (int *) NULL);
+ value = (*operand->extract) (insn, dialect, (int *) NULL);
else
{
value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
- if (operand->signedp
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0
&& (value & (1 << (operand->bits - 1))) != 0)
value -= 1 << operand->bits;
}
(*info->fprintf_func) (info->stream, "r%ld", value);
else if ((operand->flags & PPC_OPERAND_FPR) != 0)
(*info->fprintf_func) (info->stream, "f%ld", value);
+ else if ((operand->flags & PPC_OPERAND_VR) != 0)
+ (*info->fprintf_func) (info->stream, "v%ld", value);
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
(*info->print_address_func) (memaddr + value, info);
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
cr = value >> 2;
if (cr != 0)
- (*info->fprintf_func) (info->stream, "4*cr%d", cr);
+ (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
cc = value & 3;
- if (cc != 0)
- {
- if (cr != 0)
- (*info->fprintf_func) (info->stream, "+");
- (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
- }
+ (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
}
}
}
/* We could not find a match. */
- (*info->fprintf_func) (info->stream, "0x%lx", insn);
+ (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
return 4;
}
+
+void
+print_ppc_disassembler_options (FILE * stream)
+{
+ fprintf (stream, "\n\
+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, " e500|e500x2 Disassemble the e500 instructions\n");
+ fprintf (stream, " efs Disassemble the EFS instructions\n");
+ fprintf (stream, " power4 Disassemble the Power4 instructions\n");
+ fprintf (stream, " 32 Do not disassemble 64-bit instructions\n");
+ fprintf (stream, " 64 Allow disassembly of 64-bit instructions\n");
+}