ppc-dis.c revision 89857
160484Sobrien/* ppc-dis.c -- Disassemble PowerPC instructions
278828Sobrien   Copyright 1994, 1995, 2000 Free Software Foundation, Inc.
360484Sobrien   Written by Ian Lance Taylor, Cygnus Support
460484Sobrien
560484SobrienThis file is part of GDB, GAS, and the GNU binutils.
660484Sobrien
760484SobrienGDB, GAS, and the GNU binutils are free software; you can redistribute
860484Sobrienthem and/or modify them under the terms of the GNU General Public
960484SobrienLicense as published by the Free Software Foundation; either version
1060484Sobrien2, or (at your option) any later version.
1160484Sobrien
1260484SobrienGDB, GAS, and the GNU binutils are distributed in the hope that they
1360484Sobrienwill be useful, but WITHOUT ANY WARRANTY; without even the implied
1460484Sobrienwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
1560484Sobrienthe GNU General Public License for more details.
1660484Sobrien
1760484SobrienYou should have received a copy of the GNU General Public License
1860484Sobrienalong with this file; see the file COPYING.  If not, write to the Free
1960484SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2060484Sobrien
2160484Sobrien#include <stdio.h>
2260484Sobrien#include "sysdep.h"
2360484Sobrien#include "dis-asm.h"
2460484Sobrien#include "opcode/ppc.h"
2560484Sobrien
2660484Sobrien/* This file provides several disassembler functions, all of which use
2760484Sobrien   the disassembler interface defined in dis-asm.h.  Several functions
2860484Sobrien   are provided because this file handles disassembly for the PowerPC
2960484Sobrien   in both big and little endian mode and also for the POWER (RS/6000)
3060484Sobrien   chip.  */
3160484Sobrien
3260484Sobrienstatic int print_insn_powerpc PARAMS ((bfd_vma, struct disassemble_info *,
3360484Sobrien				       int bigendian, int dialect));
3460484Sobrien
3589857Sobrienstatic int powerpc_dialect PARAMS ((struct disassemble_info *));
3660484Sobrien
3789857Sobrien/* Determine which set of machines to disassemble for.  PPC403/601 or
3889857Sobrien   Motorola BookE.  For convenience, also disassemble instructions
3989857Sobrien   supported by the AltiVec vector unit.  */
4089857Sobrien
4160484Sobrienint
4289857Sobrienpowerpc_dialect(info)
4389857Sobrien     struct disassemble_info *info;
4489857Sobrien{
4589857Sobrien  int dialect = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC;
4689857Sobrien
4789857Sobrien  if (BFD_DEFAULT_TARGET_SIZE == 64)
4889857Sobrien    dialect |= PPC_OPCODE_64;
4989857Sobrien
5089857Sobrien  if (info->disassembler_options
5189857Sobrien      && (strcmp (info->disassembler_options, "booke") == 0
5289857Sobrien	  || strcmp (info->disassembler_options, "booke32") == 0
5389857Sobrien	  || strcmp (info->disassembler_options, "booke64") == 0))
5489857Sobrien    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
5589857Sobrien  else
5689857Sobrien    dialect |= PPC_OPCODE_403 | PPC_OPCODE_601;
5789857Sobrien
5889857Sobrien  if (info->disassembler_options)
5989857Sobrien    {
6089857Sobrien      if (strstr (info->disassembler_options, "32") != NULL)
6189857Sobrien	dialect &= ~PPC_OPCODE_64;
6289857Sobrien      else if (strstr (info->disassembler_options, "64") != NULL)
6389857Sobrien	dialect |= PPC_OPCODE_64;
6489857Sobrien    }
6589857Sobrien
6689857Sobrien  return dialect;
6789857Sobrien}
6889857Sobrien
6989857Sobrien/* Print a big endian PowerPC instruction.  */
7089857Sobrien
7189857Sobrienint
7260484Sobrienprint_insn_big_powerpc (memaddr, info)
7360484Sobrien     bfd_vma memaddr;
7460484Sobrien     struct disassemble_info *info;
7560484Sobrien{
7689857Sobrien  return print_insn_powerpc (memaddr, info, 1, powerpc_dialect(info));
7760484Sobrien}
7860484Sobrien
7989857Sobrien/* Print a little endian PowerPC instruction.  */
8060484Sobrien
8160484Sobrienint
8260484Sobrienprint_insn_little_powerpc (memaddr, info)
8360484Sobrien     bfd_vma memaddr;
8460484Sobrien     struct disassemble_info *info;
8560484Sobrien{
8689857Sobrien  return print_insn_powerpc (memaddr, info, 0, powerpc_dialect(info));
8760484Sobrien}
8860484Sobrien
8960484Sobrien/* Print a POWER (RS/6000) instruction.  */
9060484Sobrien
9160484Sobrienint
9260484Sobrienprint_insn_rs6000 (memaddr, info)
9360484Sobrien     bfd_vma memaddr;
9460484Sobrien     struct disassemble_info *info;
9560484Sobrien{
9660484Sobrien  return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
9760484Sobrien}
9860484Sobrien
9960484Sobrien/* Print a PowerPC or POWER instruction.  */
10060484Sobrien
10160484Sobrienstatic int
10260484Sobrienprint_insn_powerpc (memaddr, info, bigendian, dialect)
10360484Sobrien     bfd_vma memaddr;
10460484Sobrien     struct disassemble_info *info;
10560484Sobrien     int bigendian;
10660484Sobrien     int dialect;
10760484Sobrien{
10860484Sobrien  bfd_byte buffer[4];
10960484Sobrien  int status;
11060484Sobrien  unsigned long insn;
11160484Sobrien  const struct powerpc_opcode *opcode;
11260484Sobrien  const struct powerpc_opcode *opcode_end;
11360484Sobrien  unsigned long op;
11460484Sobrien
11560484Sobrien  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
11660484Sobrien  if (status != 0)
11760484Sobrien    {
11860484Sobrien      (*info->memory_error_func) (status, memaddr, info);
11960484Sobrien      return -1;
12060484Sobrien    }
12160484Sobrien
12260484Sobrien  if (bigendian)
12360484Sobrien    insn = bfd_getb32 (buffer);
12460484Sobrien  else
12560484Sobrien    insn = bfd_getl32 (buffer);
12660484Sobrien
12760484Sobrien  /* Get the major opcode of the instruction.  */
12860484Sobrien  op = PPC_OP (insn);
12960484Sobrien
13060484Sobrien  /* Find the first match in the opcode table.  We could speed this up
13160484Sobrien     a bit by doing a binary search on the major opcode.  */
13260484Sobrien  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
13360484Sobrien  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
13460484Sobrien    {
13560484Sobrien      unsigned long table_op;
13660484Sobrien      const unsigned char *opindex;
13760484Sobrien      const struct powerpc_operand *operand;
13860484Sobrien      int invalid;
13960484Sobrien      int need_comma;
14060484Sobrien      int need_paren;
14160484Sobrien
14260484Sobrien      table_op = PPC_OP (opcode->opcode);
14360484Sobrien      if (op < table_op)
14460484Sobrien	break;
14560484Sobrien      if (op > table_op)
14660484Sobrien	continue;
14760484Sobrien
14860484Sobrien      if ((insn & opcode->mask) != opcode->opcode
14960484Sobrien	  || (opcode->flags & dialect) == 0)
15060484Sobrien	continue;
15160484Sobrien
15260484Sobrien      /* Make two passes over the operands.  First see if any of them
15360484Sobrien	 have extraction functions, and, if they do, make sure the
15460484Sobrien	 instruction is valid.  */
15560484Sobrien      invalid = 0;
15660484Sobrien      for (opindex = opcode->operands; *opindex != 0; opindex++)
15760484Sobrien	{
15860484Sobrien	  operand = powerpc_operands + *opindex;
15960484Sobrien	  if (operand->extract)
16089857Sobrien	    (*operand->extract) (insn, dialect, &invalid);
16160484Sobrien	}
16260484Sobrien      if (invalid)
16360484Sobrien	continue;
16460484Sobrien
16560484Sobrien      /* The instruction is valid.  */
16660484Sobrien      (*info->fprintf_func) (info->stream, "%s", opcode->name);
16760484Sobrien      if (opcode->operands[0] != 0)
16860484Sobrien	(*info->fprintf_func) (info->stream, "\t");
16960484Sobrien
17060484Sobrien      /* Now extract and print the operands.  */
17160484Sobrien      need_comma = 0;
17260484Sobrien      need_paren = 0;
17360484Sobrien      for (opindex = opcode->operands; *opindex != 0; opindex++)
17460484Sobrien	{
17560484Sobrien	  long value;
17660484Sobrien
17760484Sobrien	  operand = powerpc_operands + *opindex;
17860484Sobrien
17960484Sobrien	  /* Operands that are marked FAKE are simply ignored.  We
18060484Sobrien	     already made sure that the extract function considered
18160484Sobrien	     the instruction to be valid.  */
18260484Sobrien	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
18360484Sobrien	    continue;
18460484Sobrien
18560484Sobrien	  /* Extract the value from the instruction.  */
18660484Sobrien	  if (operand->extract)
18789857Sobrien	    value = (*operand->extract) (insn, dialect, (int *) NULL);
18860484Sobrien	  else
18960484Sobrien	    {
19060484Sobrien	      value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
19160484Sobrien	      if ((operand->flags & PPC_OPERAND_SIGNED) != 0
19260484Sobrien		  && (value & (1 << (operand->bits - 1))) != 0)
19360484Sobrien		value -= 1 << operand->bits;
19460484Sobrien	    }
19560484Sobrien
19660484Sobrien	  /* If the operand is optional, and the value is zero, don't
19760484Sobrien	     print anything.  */
19860484Sobrien	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
19960484Sobrien	      && (operand->flags & PPC_OPERAND_NEXT) == 0
20060484Sobrien	      && value == 0)
20160484Sobrien	    continue;
20260484Sobrien
20360484Sobrien	  if (need_comma)
20460484Sobrien	    {
20560484Sobrien	      (*info->fprintf_func) (info->stream, ",");
20660484Sobrien	      need_comma = 0;
20760484Sobrien	    }
20860484Sobrien
20960484Sobrien	  /* Print the operand as directed by the flags.  */
21060484Sobrien	  if ((operand->flags & PPC_OPERAND_GPR) != 0)
21160484Sobrien	    (*info->fprintf_func) (info->stream, "r%ld", value);
21260484Sobrien	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
21360484Sobrien	    (*info->fprintf_func) (info->stream, "f%ld", value);
21477298Sobrien	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
21577298Sobrien	    (*info->fprintf_func) (info->stream, "v%ld", value);
21660484Sobrien	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
21760484Sobrien	    (*info->print_address_func) (memaddr + value, info);
21860484Sobrien	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
21960484Sobrien	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
22060484Sobrien	  else if ((operand->flags & PPC_OPERAND_CR) == 0
22160484Sobrien		   || (dialect & PPC_OPCODE_PPC) == 0)
22260484Sobrien	    (*info->fprintf_func) (info->stream, "%ld", value);
22360484Sobrien	  else
22460484Sobrien	    {
22560484Sobrien	      if (operand->bits == 3)
22660484Sobrien		(*info->fprintf_func) (info->stream, "cr%d", value);
22760484Sobrien	      else
22860484Sobrien		{
22960484Sobrien		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
23060484Sobrien		  int cr;
23160484Sobrien		  int cc;
23260484Sobrien
23360484Sobrien		  cr = value >> 2;
23460484Sobrien		  if (cr != 0)
23560484Sobrien		    (*info->fprintf_func) (info->stream, "4*cr%d", cr);
23660484Sobrien		  cc = value & 3;
23760484Sobrien		  if (cc != 0)
23860484Sobrien		    {
23960484Sobrien		      if (cr != 0)
24060484Sobrien			(*info->fprintf_func) (info->stream, "+");
24160484Sobrien		      (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
24260484Sobrien		    }
24360484Sobrien		}
24460484Sobrien	    }
24560484Sobrien
24660484Sobrien	  if (need_paren)
24760484Sobrien	    {
24860484Sobrien	      (*info->fprintf_func) (info->stream, ")");
24960484Sobrien	      need_paren = 0;
25060484Sobrien	    }
25160484Sobrien
25260484Sobrien	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
25360484Sobrien	    need_comma = 1;
25460484Sobrien	  else
25560484Sobrien	    {
25660484Sobrien	      (*info->fprintf_func) (info->stream, "(");
25760484Sobrien	      need_paren = 1;
25860484Sobrien	    }
25960484Sobrien	}
26060484Sobrien
26160484Sobrien      /* We have found and printed an instruction; return.  */
26260484Sobrien      return 4;
26360484Sobrien    }
26460484Sobrien
26560484Sobrien  /* We could not find a match.  */
26660484Sobrien  (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
26760484Sobrien
26860484Sobrien  return 4;
26960484Sobrien}
270