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