11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ppc-dis.c -- Disassemble PowerPC instructions
2897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman   Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006
3897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman   Free Software Foundation, Inc.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Written by Ian Lance Taylor, Cygnus Support
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThis file is part of GDB, GAS, and the GNU binutils.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsGDB, GAS, and the GNU binutils are free software; you can redistribute
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthem and/or modify them under the terms of the GNU General Public
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsLicense as published by the Free Software Foundation; either version
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds2, or (at your option) any later version.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsGDB, GAS, and the GNU binutils are distributed in the hope that they
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswill be useful, but WITHOUT ANY WARRANTY; without even the implied
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthe GNU General Public License for more details.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsYou should have received a copy of the GNU General Public License
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsalong with this file; see the file COPYING.  If not, write to the Free
20897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael EllermanSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman#include <asm/cputable.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "nonstdio.h"
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ansidecl.h"
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ppc.h"
26e0426047cb684842700f0098f74842a38260dbaeMichael Ellerman#include "dis-asm.h"
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Print a PowerPC or POWER instruction.  */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
314c4c8723684b1b2cd0dfdf5e0685f35642bde253Michael Ellermanprint_insn_powerpc (unsigned long insn, unsigned long memaddr)
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  const struct powerpc_opcode *opcode;
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  const struct powerpc_opcode *opcode_end;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  unsigned long op;
364c4c8723684b1b2cd0dfdf5e0685f35642bde253Michael Ellerman  int dialect;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
384c4c8723684b1b2cd0dfdf5e0685f35642bde253Michael Ellerman  dialect = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman  if (cpu_has_feature(CPU_FTRS_POWER5))
42897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman    dialect |= PPC_OPCODE_POWER5;
43897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman
44897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman  if (cpu_has_feature(CPU_FTRS_CELL))
45897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman    dialect |= PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC;
46897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman
47897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman  if (cpu_has_feature(CPU_FTRS_POWER6))
48897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman    dialect |= PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC;
49897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  /* Get the major opcode of the instruction.  */
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  op = PPC_OP (insn);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  /* Find the first match in the opcode table.  We could speed this up
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     a bit by doing a binary search on the major opcode.  */
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds again:
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    {
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      unsigned long table_op;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      const unsigned char *opindex;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      const struct powerpc_operand *operand;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      int invalid;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      int need_comma;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      int need_paren;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      table_op = PPC_OP (opcode->opcode);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      if (op < table_op)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	break;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      if (op > table_op)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	continue;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      if ((insn & opcode->mask) != opcode->opcode
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  || (opcode->flags & dialect) == 0)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	continue;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      /* Make two passes over the operands.  First see if any of them
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 have extraction functions, and, if they do, make sure the
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 instruction is valid.  */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      invalid = 0;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      for (opindex = opcode->operands; *opindex != 0; opindex++)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  operand = powerpc_operands + *opindex;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  if (operand->extract)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (*operand->extract) (insn, dialect, &invalid);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      if (invalid)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	continue;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      /* The instruction is valid.  */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      printf("%s", opcode->name);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      if (opcode->operands[0] != 0)
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printf("\t");
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      /* Now extract and print the operands.  */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      need_comma = 0;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      need_paren = 0;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      for (opindex = opcode->operands; *opindex != 0; opindex++)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  long value;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  operand = powerpc_operands + *opindex;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  /* Operands that are marked FAKE are simply ignored.  We
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     already made sure that the extract function considered
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     the instruction to be valid.  */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    continue;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  /* Extract the value from the instruction.  */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  if (operand->extract)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    value = (*operand->extract) (insn, dialect, &invalid);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    {
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      if ((operand->flags & PPC_OPERAND_SIGNED) != 0
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  && (value & (1 << (operand->bits - 1))) != 0)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value -= 1 << operand->bits;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  /* If the operand is optional, and the value is zero, don't
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     print anything.  */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      && (operand->flags & PPC_OPERAND_NEXT) == 0
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      && value == 0)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    continue;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  if (need_comma)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    {
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      printf(",");
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      need_comma = 0;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  /* Print the operand as directed by the flags.  */
134897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman	  if ((operand->flags & PPC_OPERAND_GPR) != 0
135897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printf("r%ld", value);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printf("f%ld", value);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printf("v%ld", value);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    print_address (memaddr + value);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    print_address (value & 0xffffffff);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else if ((operand->flags & PPC_OPERAND_CR) == 0
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   || (dialect & PPC_OPCODE_PPC) == 0)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    printf("%ld", value);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    {
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      if (operand->bits == 3)
151897f112bb42ed9e220ce441e7e52aba3a144a7d6Michael Ellerman		printf("cr%ld", value);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      else
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  int cr;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  int cc;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  cr = value >> 2;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  if (cr != 0)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    printf("4*cr%d+", cr);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  cc = value & 3;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  printf("%s", cbnames[cc]);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  if (need_paren)
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    {
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      printf(")");
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      need_paren = 0;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    need_comma = 1;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  else
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    {
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      printf("(");
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      need_paren = 1;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    }
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      /* We have found and printed an instruction; return.  */
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      return 4;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  if ((dialect & PPC_OPCODE_ANY) != 0)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    {
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      dialect = ~PPC_OPCODE_ANY;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      goto again;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  /* We could not find a match.  */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  printf(".long 0x%lx", insn);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  return 4;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
196