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