160484Sobrien/* ppc-dis.c -- Disassemble PowerPC instructions
2218822Sdim   Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3130561Sobrien   Free Software Foundation, Inc.
460484Sobrien   Written by Ian Lance Taylor, Cygnus Support
560484Sobrien
660484SobrienThis file is part of GDB, GAS, and the GNU binutils.
760484Sobrien
860484SobrienGDB, GAS, and the GNU binutils are free software; you can redistribute
960484Sobrienthem and/or modify them under the terms of the GNU General Public
1060484SobrienLicense as published by the Free Software Foundation; either version
1160484Sobrien2, or (at your option) any later version.
1260484Sobrien
1360484SobrienGDB, GAS, and the GNU binutils are distributed in the hope that they
1460484Sobrienwill be useful, but WITHOUT ANY WARRANTY; without even the implied
1560484Sobrienwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1660484Sobrienthe GNU General Public License for more details.
1760484Sobrien
1860484SobrienYou should have received a copy of the GNU General Public License
1960484Sobrienalong with this file; see the file COPYING.  If not, write to the Free
20218822SdimSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2160484Sobrien
2260484Sobrien#include <stdio.h>
2360484Sobrien#include "sysdep.h"
2460484Sobrien#include "dis-asm.h"
2560484Sobrien#include "opcode/ppc.h"
2660484Sobrien
2760484Sobrien/* This file provides several disassembler functions, all of which use
2860484Sobrien   the disassembler interface defined in dis-asm.h.  Several functions
2960484Sobrien   are provided because this file handles disassembly for the PowerPC
3060484Sobrien   in both big and little endian mode and also for the POWER (RS/6000)
3160484Sobrien   chip.  */
3260484Sobrien
33130561Sobrienstatic int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
3460484Sobrien
3589857Sobrien/* Determine which set of machines to disassemble for.  PPC403/601 or
3692828Sobrien   BookE.  For convenience, also disassemble instructions supported
3792828Sobrien   by the AltiVec vector unit.  */
3889857Sobrien
39130561Sobrienstatic int
40130561Sobrienpowerpc_dialect (struct disassemble_info *info)
4189857Sobrien{
42218822Sdim  int dialect = PPC_OPCODE_PPC;
4389857Sobrien
4489857Sobrien  if (BFD_DEFAULT_TARGET_SIZE == 64)
4589857Sobrien    dialect |= PPC_OPCODE_64;
4689857Sobrien
4789857Sobrien  if (info->disassembler_options
48130561Sobrien      && strstr (info->disassembler_options, "booke") != NULL)
4989857Sobrien    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
50130561Sobrien  else if ((info->mach == bfd_mach_ppc_e500)
51130561Sobrien	   || (info->disassembler_options
52130561Sobrien	       && strstr (info->disassembler_options, "e500") != NULL))
53218822Sdim    dialect |= (PPC_OPCODE_BOOKE
54218822Sdim		| PPC_OPCODE_SPE | PPC_OPCODE_ISEL
55218822Sdim		| PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
56218822Sdim		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
57218822Sdim		| PPC_OPCODE_RFMCI);
58130561Sobrien  else if (info->disassembler_options
59130561Sobrien	   && strstr (info->disassembler_options, "efs") != NULL)
60218822Sdim    dialect |= PPC_OPCODE_EFS;
61218822Sdim  else if (info->disassembler_options
62218822Sdim	   && strstr (info->disassembler_options, "e300") != NULL)
63218822Sdim    dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON;
64218822Sdim  else if (info->disassembler_options
65218822Sdim	   && strstr (info->disassembler_options, "440") != NULL)
66218822Sdim    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32
67218822Sdim      | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI;
68130561Sobrien  else
69130561Sobrien    dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
70218822Sdim		| PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC);
7189857Sobrien
7292828Sobrien  if (info->disassembler_options
73130561Sobrien      && strstr (info->disassembler_options, "power4") != NULL)
7492828Sobrien    dialect |= PPC_OPCODE_POWER4;
7592828Sobrien
76130561Sobrien  if (info->disassembler_options
77218822Sdim      && strstr (info->disassembler_options, "power5") != NULL)
78218822Sdim    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5;
79218822Sdim
80218822Sdim  if (info->disassembler_options
81218822Sdim      && strstr (info->disassembler_options, "cell") != NULL)
82218822Sdim    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC;
83218822Sdim
84218822Sdim  if (info->disassembler_options
85218822Sdim      && strstr (info->disassembler_options, "power6") != NULL)
86218822Sdim    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC;
87218822Sdim
88218822Sdim  if (info->disassembler_options
89130561Sobrien      && strstr (info->disassembler_options, "any") != NULL)
90130561Sobrien    dialect |= PPC_OPCODE_ANY;
91130561Sobrien
9289857Sobrien  if (info->disassembler_options)
9389857Sobrien    {
9489857Sobrien      if (strstr (info->disassembler_options, "32") != NULL)
9589857Sobrien	dialect &= ~PPC_OPCODE_64;
9689857Sobrien      else if (strstr (info->disassembler_options, "64") != NULL)
9789857Sobrien	dialect |= PPC_OPCODE_64;
9889857Sobrien    }
9989857Sobrien
100218822Sdim  info->private_data = (char *) 0 + dialect;
10189857Sobrien  return dialect;
10289857Sobrien}
10389857Sobrien
10489857Sobrien/* Print a big endian PowerPC instruction.  */
10589857Sobrien
10689857Sobrienint
107130561Sobrienprint_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
10860484Sobrien{
109218822Sdim  int dialect = (char *) info->private_data - (char *) 0;
110130561Sobrien  return print_insn_powerpc (memaddr, info, 1, dialect);
11160484Sobrien}
11260484Sobrien
11389857Sobrien/* Print a little endian PowerPC instruction.  */
11460484Sobrien
11560484Sobrienint
116130561Sobrienprint_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
11760484Sobrien{
118218822Sdim  int dialect = (char *) info->private_data - (char *) 0;
119130561Sobrien  return print_insn_powerpc (memaddr, info, 0, dialect);
12060484Sobrien}
12160484Sobrien
12260484Sobrien/* Print a POWER (RS/6000) instruction.  */
12360484Sobrien
12460484Sobrienint
125130561Sobrienprint_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
12660484Sobrien{
12760484Sobrien  return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
12860484Sobrien}
12960484Sobrien
130218822Sdim/* Extract the operand value from the PowerPC or POWER instruction.  */
131218822Sdim
132218822Sdimstatic long
133218822Sdimoperand_value_powerpc (const struct powerpc_operand *operand,
134218822Sdim		       unsigned long insn, int dialect)
135218822Sdim{
136218822Sdim  long value;
137218822Sdim  int invalid;
138218822Sdim  /* Extract the value from the instruction.  */
139218822Sdim  if (operand->extract)
140218822Sdim    value = (*operand->extract) (insn, dialect, &invalid);
141218822Sdim  else
142218822Sdim    {
143218822Sdim      value = (insn >> operand->shift) & operand->bitm;
144218822Sdim      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
145218822Sdim	{
146218822Sdim	  /* BITM is always some number of zeros followed by some
147218822Sdim	     number of ones, followed by some numer of zeros.  */
148218822Sdim	  unsigned long top = operand->bitm;
149218822Sdim	  /* top & -top gives the rightmost 1 bit, so this
150218822Sdim	     fills in any trailing zeros.  */
151218822Sdim	  top |= (top & -top) - 1;
152218822Sdim	  top &= ~(top >> 1);
153218822Sdim	  value = (value ^ top) - top;
154218822Sdim	}
155218822Sdim    }
156218822Sdim
157218822Sdim  return value;
158218822Sdim}
159218822Sdim
160218822Sdim/* Determine whether the optional operand(s) should be printed.  */
161218822Sdim
162218822Sdimstatic int
163218822Sdimskip_optional_operands (const unsigned char *opindex,
164218822Sdim			unsigned long insn, int dialect)
165218822Sdim{
166218822Sdim  const struct powerpc_operand *operand;
167218822Sdim
168218822Sdim  for (; *opindex != 0; opindex++)
169218822Sdim    {
170218822Sdim      operand = &powerpc_operands[*opindex];
171218822Sdim      if ((operand->flags & PPC_OPERAND_NEXT) != 0
172218822Sdim	  || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
173218822Sdim	      && operand_value_powerpc (operand, insn, dialect) != 0))
174218822Sdim	return 0;
175218822Sdim    }
176218822Sdim
177218822Sdim  return 1;
178218822Sdim}
179218822Sdim
18060484Sobrien/* Print a PowerPC or POWER instruction.  */
18160484Sobrien
18260484Sobrienstatic int
183130561Sobrienprint_insn_powerpc (bfd_vma memaddr,
184130561Sobrien		    struct disassemble_info *info,
185130561Sobrien		    int bigendian,
186130561Sobrien		    int dialect)
18760484Sobrien{
18860484Sobrien  bfd_byte buffer[4];
18960484Sobrien  int status;
19060484Sobrien  unsigned long insn;
19160484Sobrien  const struct powerpc_opcode *opcode;
19260484Sobrien  const struct powerpc_opcode *opcode_end;
19360484Sobrien  unsigned long op;
19460484Sobrien
195130561Sobrien  if (dialect == 0)
196130561Sobrien    dialect = powerpc_dialect (info);
197130561Sobrien
19860484Sobrien  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
19960484Sobrien  if (status != 0)
20060484Sobrien    {
20160484Sobrien      (*info->memory_error_func) (status, memaddr, info);
20260484Sobrien      return -1;
20360484Sobrien    }
20460484Sobrien
20560484Sobrien  if (bigendian)
20660484Sobrien    insn = bfd_getb32 (buffer);
20760484Sobrien  else
20860484Sobrien    insn = bfd_getl32 (buffer);
20960484Sobrien
21060484Sobrien  /* Get the major opcode of the instruction.  */
21160484Sobrien  op = PPC_OP (insn);
21260484Sobrien
21360484Sobrien  /* Find the first match in the opcode table.  We could speed this up
21460484Sobrien     a bit by doing a binary search on the major opcode.  */
21560484Sobrien  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
216130561Sobrien again:
21760484Sobrien  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
21860484Sobrien    {
21960484Sobrien      unsigned long table_op;
22060484Sobrien      const unsigned char *opindex;
22160484Sobrien      const struct powerpc_operand *operand;
22260484Sobrien      int invalid;
22360484Sobrien      int need_comma;
22460484Sobrien      int need_paren;
225218822Sdim      int skip_optional;
22660484Sobrien
22760484Sobrien      table_op = PPC_OP (opcode->opcode);
22860484Sobrien      if (op < table_op)
22960484Sobrien	break;
23060484Sobrien      if (op > table_op)
23160484Sobrien	continue;
23260484Sobrien
23360484Sobrien      if ((insn & opcode->mask) != opcode->opcode
23460484Sobrien	  || (opcode->flags & dialect) == 0)
23560484Sobrien	continue;
23660484Sobrien
23760484Sobrien      /* Make two passes over the operands.  First see if any of them
23860484Sobrien	 have extraction functions, and, if they do, make sure the
23960484Sobrien	 instruction is valid.  */
24060484Sobrien      invalid = 0;
24160484Sobrien      for (opindex = opcode->operands; *opindex != 0; opindex++)
24260484Sobrien	{
24360484Sobrien	  operand = powerpc_operands + *opindex;
24460484Sobrien	  if (operand->extract)
24589857Sobrien	    (*operand->extract) (insn, dialect, &invalid);
24660484Sobrien	}
24760484Sobrien      if (invalid)
24860484Sobrien	continue;
24960484Sobrien
25060484Sobrien      /* The instruction is valid.  */
25160484Sobrien      if (opcode->operands[0] != 0)
252130561Sobrien	(*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
253130561Sobrien      else
254130561Sobrien	(*info->fprintf_func) (info->stream, "%s", opcode->name);
25560484Sobrien
25660484Sobrien      /* Now extract and print the operands.  */
25760484Sobrien      need_comma = 0;
25860484Sobrien      need_paren = 0;
259218822Sdim      skip_optional = -1;
26060484Sobrien      for (opindex = opcode->operands; *opindex != 0; opindex++)
26160484Sobrien	{
26260484Sobrien	  long value;
26360484Sobrien
26460484Sobrien	  operand = powerpc_operands + *opindex;
26560484Sobrien
26660484Sobrien	  /* Operands that are marked FAKE are simply ignored.  We
26760484Sobrien	     already made sure that the extract function considered
26860484Sobrien	     the instruction to be valid.  */
26960484Sobrien	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
27060484Sobrien	    continue;
27160484Sobrien
272218822Sdim	  /* If all of the optional operands have the value zero,
273218822Sdim	     then don't print any of them.  */
274218822Sdim	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
27560484Sobrien	    {
276218822Sdim	      if (skip_optional < 0)
277218822Sdim		skip_optional = skip_optional_operands (opindex, insn,
278218822Sdim							dialect);
279218822Sdim	      if (skip_optional)
280218822Sdim		continue;
28160484Sobrien	    }
28260484Sobrien
283218822Sdim	  value = operand_value_powerpc (operand, insn, dialect);
28460484Sobrien
28560484Sobrien	  if (need_comma)
28660484Sobrien	    {
28760484Sobrien	      (*info->fprintf_func) (info->stream, ",");
28860484Sobrien	      need_comma = 0;
28960484Sobrien	    }
29060484Sobrien
29160484Sobrien	  /* Print the operand as directed by the flags.  */
292130561Sobrien	  if ((operand->flags & PPC_OPERAND_GPR) != 0
293130561Sobrien	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
29460484Sobrien	    (*info->fprintf_func) (info->stream, "r%ld", value);
29560484Sobrien	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
29660484Sobrien	    (*info->fprintf_func) (info->stream, "f%ld", value);
29777298Sobrien	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
29877298Sobrien	    (*info->fprintf_func) (info->stream, "v%ld", value);
29960484Sobrien	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
30060484Sobrien	    (*info->print_address_func) (memaddr + value, info);
30160484Sobrien	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
30260484Sobrien	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
30360484Sobrien	  else if ((operand->flags & PPC_OPERAND_CR) == 0
30460484Sobrien		   || (dialect & PPC_OPCODE_PPC) == 0)
30560484Sobrien	    (*info->fprintf_func) (info->stream, "%ld", value);
30660484Sobrien	  else
30760484Sobrien	    {
308218822Sdim	      if (operand->bitm == 7)
309218822Sdim		(*info->fprintf_func) (info->stream, "cr%ld", value);
31060484Sobrien	      else
31160484Sobrien		{
31260484Sobrien		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
31360484Sobrien		  int cr;
31460484Sobrien		  int cc;
31560484Sobrien
31660484Sobrien		  cr = value >> 2;
31760484Sobrien		  if (cr != 0)
318130561Sobrien		    (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
31960484Sobrien		  cc = value & 3;
320130561Sobrien		  (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
32160484Sobrien		}
32260484Sobrien	    }
32360484Sobrien
32460484Sobrien	  if (need_paren)
32560484Sobrien	    {
32660484Sobrien	      (*info->fprintf_func) (info->stream, ")");
32760484Sobrien	      need_paren = 0;
32860484Sobrien	    }
32960484Sobrien
33060484Sobrien	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
33160484Sobrien	    need_comma = 1;
33260484Sobrien	  else
33360484Sobrien	    {
33460484Sobrien	      (*info->fprintf_func) (info->stream, "(");
33560484Sobrien	      need_paren = 1;
33660484Sobrien	    }
33760484Sobrien	}
33860484Sobrien
33960484Sobrien      /* We have found and printed an instruction; return.  */
34060484Sobrien      return 4;
34160484Sobrien    }
34260484Sobrien
343130561Sobrien  if ((dialect & PPC_OPCODE_ANY) != 0)
344130561Sobrien    {
345130561Sobrien      dialect = ~PPC_OPCODE_ANY;
346130561Sobrien      goto again;
347130561Sobrien    }
348130561Sobrien
34960484Sobrien  /* We could not find a match.  */
35060484Sobrien  (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
35160484Sobrien
35260484Sobrien  return 4;
35360484Sobrien}
354104834Sobrien
355104834Sobrienvoid
356130561Sobrienprint_ppc_disassembler_options (FILE *stream)
357104834Sobrien{
358104834Sobrien  fprintf (stream, "\n\
359104834SobrienThe following PPC specific disassembler options are supported for use with\n\
360104834Sobrienthe -M switch:\n");
361130561Sobrien
362104834Sobrien  fprintf (stream, "  booke|booke32|booke64    Disassemble the BookE instructions\n");
363218822Sdim  fprintf (stream, "  e300                     Disassemble the e300 instructions\n");
364130561Sobrien  fprintf (stream, "  e500|e500x2              Disassemble the e500 instructions\n");
365218822Sdim  fprintf (stream, "  440                      Disassemble the 440 instructions\n");
366130561Sobrien  fprintf (stream, "  efs                      Disassemble the EFS instructions\n");
367104834Sobrien  fprintf (stream, "  power4                   Disassemble the Power4 instructions\n");
368218822Sdim  fprintf (stream, "  power5                   Disassemble the Power5 instructions\n");
369218822Sdim  fprintf (stream, "  power6                   Disassemble the Power6 instructions\n");
370104834Sobrien  fprintf (stream, "  32                       Do not disassemble 64-bit instructions\n");
371104834Sobrien  fprintf (stream, "  64                       Allow disassembly of 64-bit instructions\n");
372104834Sobrien}
373