13d8817e4Smiod /* ppc-dis.c -- Disassemble PowerPC instructions
23d8817e4Smiod Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005
33d8817e4Smiod Free Software Foundation, Inc.
43d8817e4Smiod Written by Ian Lance Taylor, Cygnus Support
53d8817e4Smiod
63d8817e4Smiod This file is part of GDB, GAS, and the GNU binutils.
73d8817e4Smiod
83d8817e4Smiod GDB, GAS, and the GNU binutils are free software; you can redistribute
93d8817e4Smiod them and/or modify them under the terms of the GNU General Public
103d8817e4Smiod License as published by the Free Software Foundation; either version
113d8817e4Smiod 2, or (at your option) any later version.
123d8817e4Smiod
133d8817e4Smiod GDB, GAS, and the GNU binutils are distributed in the hope that they
143d8817e4Smiod will be useful, but WITHOUT ANY WARRANTY; without even the implied
153d8817e4Smiod warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
163d8817e4Smiod the GNU General Public License for more details.
173d8817e4Smiod
183d8817e4Smiod You should have received a copy of the GNU General Public License
193d8817e4Smiod along with this file; see the file COPYING. If not, write to the Free
203d8817e4Smiod Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
213d8817e4Smiod
223d8817e4Smiod #include <stdio.h>
233d8817e4Smiod #include "sysdep.h"
243d8817e4Smiod #include "dis-asm.h"
253d8817e4Smiod #include "opcode/ppc.h"
263d8817e4Smiod
273d8817e4Smiod /* This file provides several disassembler functions, all of which use
283d8817e4Smiod the disassembler interface defined in dis-asm.h. Several functions
293d8817e4Smiod are provided because this file handles disassembly for the PowerPC
303d8817e4Smiod in both big and little endian mode and also for the POWER (RS/6000)
313d8817e4Smiod chip. */
323d8817e4Smiod
333d8817e4Smiod static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
343d8817e4Smiod
353d8817e4Smiod /* Determine which set of machines to disassemble for. PPC403/601 or
363d8817e4Smiod BookE. For convenience, also disassemble instructions supported
373d8817e4Smiod by the AltiVec vector unit. */
383d8817e4Smiod
393d8817e4Smiod static int
powerpc_dialect(struct disassemble_info * info)403d8817e4Smiod powerpc_dialect (struct disassemble_info *info)
413d8817e4Smiod {
423d8817e4Smiod int dialect = PPC_OPCODE_PPC;
433d8817e4Smiod
443d8817e4Smiod if (BFD_DEFAULT_TARGET_SIZE == 64)
453d8817e4Smiod dialect |= PPC_OPCODE_64;
463d8817e4Smiod
473d8817e4Smiod if (info->disassembler_options
483d8817e4Smiod && strstr (info->disassembler_options, "booke") != NULL)
493d8817e4Smiod dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
503d8817e4Smiod else if ((info->mach == bfd_mach_ppc_e500)
513d8817e4Smiod || (info->disassembler_options
523d8817e4Smiod && strstr (info->disassembler_options, "e500") != NULL))
533d8817e4Smiod dialect |= (PPC_OPCODE_BOOKE
543d8817e4Smiod | PPC_OPCODE_SPE | PPC_OPCODE_ISEL
553d8817e4Smiod | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
563d8817e4Smiod | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
573d8817e4Smiod | PPC_OPCODE_RFMCI);
583d8817e4Smiod else if (info->disassembler_options
593d8817e4Smiod && strstr (info->disassembler_options, "efs") != NULL)
603d8817e4Smiod dialect |= PPC_OPCODE_EFS;
613d8817e4Smiod else if (info->disassembler_options
623d8817e4Smiod && strstr (info->disassembler_options, "e300") != NULL)
633d8817e4Smiod dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON;
643d8817e4Smiod else
653d8817e4Smiod dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
663d8817e4Smiod | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC);
673d8817e4Smiod
683d8817e4Smiod if (info->disassembler_options
693d8817e4Smiod && strstr (info->disassembler_options, "power4") != NULL)
703d8817e4Smiod dialect |= PPC_OPCODE_POWER4;
713d8817e4Smiod
723d8817e4Smiod if (info->disassembler_options
733d8817e4Smiod && strstr (info->disassembler_options, "power5") != NULL)
743d8817e4Smiod dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5;
753d8817e4Smiod
763d8817e4Smiod if (info->disassembler_options
773d8817e4Smiod && strstr (info->disassembler_options, "any") != NULL)
783d8817e4Smiod dialect |= PPC_OPCODE_ANY;
793d8817e4Smiod
803d8817e4Smiod if (info->disassembler_options)
813d8817e4Smiod {
823d8817e4Smiod if (strstr (info->disassembler_options, "32") != NULL)
833d8817e4Smiod dialect &= ~PPC_OPCODE_64;
843d8817e4Smiod else if (strstr (info->disassembler_options, "64") != NULL)
853d8817e4Smiod dialect |= PPC_OPCODE_64;
863d8817e4Smiod }
873d8817e4Smiod
88*3223761eSmpi info->private_data = (void *)(long) dialect;
893d8817e4Smiod return dialect;
903d8817e4Smiod }
913d8817e4Smiod
923d8817e4Smiod /* Print a big endian PowerPC instruction. */
933d8817e4Smiod
943d8817e4Smiod int
print_insn_big_powerpc(bfd_vma memaddr,struct disassemble_info * info)953d8817e4Smiod print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
963d8817e4Smiod {
973474c532Skettenis int dialect = (long) info->private_data;
983d8817e4Smiod return print_insn_powerpc (memaddr, info, 1, dialect);
993d8817e4Smiod }
1003d8817e4Smiod
1013d8817e4Smiod /* Print a little endian PowerPC instruction. */
1023d8817e4Smiod
1033d8817e4Smiod int
print_insn_little_powerpc(bfd_vma memaddr,struct disassemble_info * info)1043d8817e4Smiod print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
1053d8817e4Smiod {
1063474c532Skettenis int dialect = (long) info->private_data;
1073d8817e4Smiod return print_insn_powerpc (memaddr, info, 0, dialect);
1083d8817e4Smiod }
1093d8817e4Smiod
1103d8817e4Smiod /* Print a POWER (RS/6000) instruction. */
1113d8817e4Smiod
1123d8817e4Smiod int
print_insn_rs6000(bfd_vma memaddr,struct disassemble_info * info)1133d8817e4Smiod print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
1143d8817e4Smiod {
1153d8817e4Smiod return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
1163d8817e4Smiod }
1173d8817e4Smiod
1183d8817e4Smiod /* Print a PowerPC or POWER instruction. */
1193d8817e4Smiod
1203d8817e4Smiod static int
print_insn_powerpc(bfd_vma memaddr,struct disassemble_info * info,int bigendian,int dialect)1213d8817e4Smiod print_insn_powerpc (bfd_vma memaddr,
1223d8817e4Smiod struct disassemble_info *info,
1233d8817e4Smiod int bigendian,
1243d8817e4Smiod int dialect)
1253d8817e4Smiod {
1263d8817e4Smiod bfd_byte buffer[4];
1273d8817e4Smiod int status;
1283d8817e4Smiod unsigned long insn;
1293d8817e4Smiod const struct powerpc_opcode *opcode;
1303d8817e4Smiod const struct powerpc_opcode *opcode_end;
1313d8817e4Smiod unsigned long op;
1323d8817e4Smiod
1333d8817e4Smiod if (dialect == 0)
1343d8817e4Smiod dialect = powerpc_dialect (info);
1353d8817e4Smiod
1363d8817e4Smiod status = (*info->read_memory_func) (memaddr, buffer, 4, info);
1373d8817e4Smiod if (status != 0)
1383d8817e4Smiod {
1393d8817e4Smiod (*info->memory_error_func) (status, memaddr, info);
1403d8817e4Smiod return -1;
1413d8817e4Smiod }
1423d8817e4Smiod
1433d8817e4Smiod if (bigendian)
1443d8817e4Smiod insn = bfd_getb32 (buffer);
1453d8817e4Smiod else
1463d8817e4Smiod insn = bfd_getl32 (buffer);
1473d8817e4Smiod
1483d8817e4Smiod /* Get the major opcode of the instruction. */
1493d8817e4Smiod op = PPC_OP (insn);
1503d8817e4Smiod
1513d8817e4Smiod /* Find the first match in the opcode table. We could speed this up
1523d8817e4Smiod a bit by doing a binary search on the major opcode. */
1533d8817e4Smiod opcode_end = powerpc_opcodes + powerpc_num_opcodes;
1543d8817e4Smiod again:
1553d8817e4Smiod for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
1563d8817e4Smiod {
1573d8817e4Smiod unsigned long table_op;
1583d8817e4Smiod const unsigned char *opindex;
1593d8817e4Smiod const struct powerpc_operand *operand;
1603d8817e4Smiod int invalid;
1613d8817e4Smiod int need_comma;
1623d8817e4Smiod int need_paren;
1633d8817e4Smiod
1643d8817e4Smiod table_op = PPC_OP (opcode->opcode);
1653d8817e4Smiod if (op < table_op)
1663d8817e4Smiod break;
1673d8817e4Smiod if (op > table_op)
1683d8817e4Smiod continue;
1693d8817e4Smiod
1703d8817e4Smiod if ((insn & opcode->mask) != opcode->opcode
1713d8817e4Smiod || (opcode->flags & dialect) == 0)
1723d8817e4Smiod continue;
1733d8817e4Smiod
1743d8817e4Smiod /* Make two passes over the operands. First see if any of them
1753d8817e4Smiod have extraction functions, and, if they do, make sure the
1763d8817e4Smiod instruction is valid. */
1773d8817e4Smiod invalid = 0;
1783d8817e4Smiod for (opindex = opcode->operands; *opindex != 0; opindex++)
1793d8817e4Smiod {
1803d8817e4Smiod operand = powerpc_operands + *opindex;
1813d8817e4Smiod if (operand->extract)
1823d8817e4Smiod (*operand->extract) (insn, dialect, &invalid);
1833d8817e4Smiod }
1843d8817e4Smiod if (invalid)
1853d8817e4Smiod continue;
1863d8817e4Smiod
1873d8817e4Smiod /* The instruction is valid. */
1883d8817e4Smiod if (opcode->operands[0] != 0)
1893d8817e4Smiod (*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
1903d8817e4Smiod else
1913d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", opcode->name);
1923d8817e4Smiod
1933d8817e4Smiod /* Now extract and print the operands. */
1943d8817e4Smiod need_comma = 0;
1953d8817e4Smiod need_paren = 0;
1963d8817e4Smiod for (opindex = opcode->operands; *opindex != 0; opindex++)
1973d8817e4Smiod {
1983d8817e4Smiod long value;
1993d8817e4Smiod
2003d8817e4Smiod operand = powerpc_operands + *opindex;
2013d8817e4Smiod
2023d8817e4Smiod /* Operands that are marked FAKE are simply ignored. We
2033d8817e4Smiod already made sure that the extract function considered
2043d8817e4Smiod the instruction to be valid. */
2053d8817e4Smiod if ((operand->flags & PPC_OPERAND_FAKE) != 0)
2063d8817e4Smiod continue;
2073d8817e4Smiod
2083d8817e4Smiod /* Extract the value from the instruction. */
2093d8817e4Smiod if (operand->extract)
2103d8817e4Smiod value = (*operand->extract) (insn, dialect, &invalid);
2113d8817e4Smiod else
2123d8817e4Smiod {
2133d8817e4Smiod value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
2143d8817e4Smiod if ((operand->flags & PPC_OPERAND_SIGNED) != 0
2153d8817e4Smiod && (value & (1 << (operand->bits - 1))) != 0)
2163d8817e4Smiod value -= 1 << operand->bits;
2173d8817e4Smiod }
2183d8817e4Smiod
2193d8817e4Smiod /* If the operand is optional, and the value is zero, don't
2203d8817e4Smiod print anything. */
2213d8817e4Smiod if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
2223d8817e4Smiod && (operand->flags & PPC_OPERAND_NEXT) == 0
2233d8817e4Smiod && value == 0)
2243d8817e4Smiod continue;
2253d8817e4Smiod
2263d8817e4Smiod if (need_comma)
2273d8817e4Smiod {
2283d8817e4Smiod (*info->fprintf_func) (info->stream, ",");
2293d8817e4Smiod need_comma = 0;
2303d8817e4Smiod }
2313d8817e4Smiod
2323d8817e4Smiod /* Print the operand as directed by the flags. */
2333d8817e4Smiod if ((operand->flags & PPC_OPERAND_GPR) != 0
2343d8817e4Smiod || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
2353d8817e4Smiod (*info->fprintf_func) (info->stream, "r%ld", value);
2363d8817e4Smiod else if ((operand->flags & PPC_OPERAND_FPR) != 0)
2373d8817e4Smiod (*info->fprintf_func) (info->stream, "f%ld", value);
2383d8817e4Smiod else if ((operand->flags & PPC_OPERAND_VR) != 0)
2393d8817e4Smiod (*info->fprintf_func) (info->stream, "v%ld", value);
2403d8817e4Smiod else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
2413d8817e4Smiod (*info->print_address_func) (memaddr + value, info);
2423d8817e4Smiod else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
2433d8817e4Smiod (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
2443d8817e4Smiod else if ((operand->flags & PPC_OPERAND_CR) == 0
2453d8817e4Smiod || (dialect & PPC_OPCODE_PPC) == 0)
2463d8817e4Smiod (*info->fprintf_func) (info->stream, "%ld", value);
2473d8817e4Smiod else
2483d8817e4Smiod {
2493d8817e4Smiod if (operand->bits == 3)
2503d8817e4Smiod (*info->fprintf_func) (info->stream, "cr%ld", value);
2513d8817e4Smiod else
2523d8817e4Smiod {
2533d8817e4Smiod static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
2543d8817e4Smiod int cr;
2553d8817e4Smiod int cc;
2563d8817e4Smiod
2573d8817e4Smiod cr = value >> 2;
2583d8817e4Smiod if (cr != 0)
2593d8817e4Smiod (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
2603d8817e4Smiod cc = value & 3;
2613d8817e4Smiod (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
2623d8817e4Smiod }
2633d8817e4Smiod }
2643d8817e4Smiod
2653d8817e4Smiod if (need_paren)
2663d8817e4Smiod {
2673d8817e4Smiod (*info->fprintf_func) (info->stream, ")");
2683d8817e4Smiod need_paren = 0;
2693d8817e4Smiod }
2703d8817e4Smiod
2713d8817e4Smiod if ((operand->flags & PPC_OPERAND_PARENS) == 0)
2723d8817e4Smiod need_comma = 1;
2733d8817e4Smiod else
2743d8817e4Smiod {
2753d8817e4Smiod (*info->fprintf_func) (info->stream, "(");
2763d8817e4Smiod need_paren = 1;
2773d8817e4Smiod }
2783d8817e4Smiod }
2793d8817e4Smiod
2803d8817e4Smiod /* We have found and printed an instruction; return. */
2813d8817e4Smiod return 4;
2823d8817e4Smiod }
2833d8817e4Smiod
2843d8817e4Smiod if ((dialect & PPC_OPCODE_ANY) != 0)
2853d8817e4Smiod {
2863d8817e4Smiod dialect = ~PPC_OPCODE_ANY;
2873d8817e4Smiod goto again;
2883d8817e4Smiod }
2893d8817e4Smiod
2903d8817e4Smiod /* We could not find a match. */
2913d8817e4Smiod (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
2923d8817e4Smiod
2933d8817e4Smiod return 4;
2943d8817e4Smiod }
2953d8817e4Smiod
2963d8817e4Smiod void
print_ppc_disassembler_options(FILE * stream)2973d8817e4Smiod print_ppc_disassembler_options (FILE *stream)
2983d8817e4Smiod {
2993d8817e4Smiod fprintf (stream, "\n\
3003d8817e4Smiod The following PPC specific disassembler options are supported for use with\n\
3013d8817e4Smiod the -M switch:\n");
3023d8817e4Smiod
3033d8817e4Smiod fprintf (stream, " booke|booke32|booke64 Disassemble the BookE instructions\n");
3043d8817e4Smiod fprintf (stream, " e300 Disassemble the e300 instructions\n");
3053d8817e4Smiod fprintf (stream, " e500|e500x2 Disassemble the e500 instructions\n");
3063d8817e4Smiod fprintf (stream, " efs Disassemble the EFS instructions\n");
3073d8817e4Smiod fprintf (stream, " power4 Disassemble the Power4 instructions\n");
3083d8817e4Smiod fprintf (stream, " power5 Disassemble the Power5 instructions\n");
3093d8817e4Smiod fprintf (stream, " 32 Do not disassemble 64-bit instructions\n");
3103d8817e4Smiod fprintf (stream, " 64 Allow disassembly of 64-bit instructions\n");
3113d8817e4Smiod }
312