123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- /* ppc-dis.c -- Disassemble PowerPC instructions
- Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
- Written by Ian Lance Taylor, Cygnus Support
- This file is part of GDB, GAS, and the GNU binutils.
- GDB, GAS, and the GNU binutils are free software; you can redistribute
- them and/or modify them under the terms of the GNU General Public
- License as published by the Free Software Foundation; either version
- 2, or (at your option) any later version.
- GDB, GAS, and the GNU binutils are distributed in the hope that they
- will be useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this file; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
- #include <asm/cputable.h>
- #include <asm/cpu_has_feature.h>
- #include "nonstdio.h"
- #include "ansidecl.h"
- #include "ppc.h"
- #include "dis-asm.h"
- /* Print a PowerPC or POWER instruction. */
- int
- print_insn_powerpc (unsigned long insn, unsigned long memaddr)
- {
- const struct powerpc_opcode *opcode;
- const struct powerpc_opcode *opcode_end;
- unsigned long op;
- int dialect;
- dialect = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON
- | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
- if (cpu_has_feature(CPU_FTRS_POWER5))
- dialect |= PPC_OPCODE_POWER5;
- if (cpu_has_feature(CPU_FTRS_CELL))
- dialect |= PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC;
- if (cpu_has_feature(CPU_FTRS_POWER6))
- dialect |= PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC;
- /* Get the major opcode of the instruction. */
- op = PPC_OP (insn);
- /* Find the first match in the opcode table. We could speed this up
- a bit by doing a binary search on the major opcode. */
- opcode_end = powerpc_opcodes + powerpc_num_opcodes;
- again:
- for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
- {
- unsigned long table_op;
- const unsigned char *opindex;
- const struct powerpc_operand *operand;
- int invalid;
- int need_comma;
- int need_paren;
- table_op = PPC_OP (opcode->opcode);
- if (op < table_op)
- break;
- if (op > table_op)
- continue;
- if ((insn & opcode->mask) != opcode->opcode
- || (opcode->flags & dialect) == 0)
- continue;
- /* Make two passes over the operands. First see if any of them
- have extraction functions, and, if they do, make sure the
- instruction is valid. */
- invalid = 0;
- for (opindex = opcode->operands; *opindex != 0; opindex++)
- {
- operand = powerpc_operands + *opindex;
- if (operand->extract)
- (*operand->extract) (insn, dialect, &invalid);
- }
- if (invalid)
- continue;
- /* The instruction is valid. */
- printf("%s", opcode->name);
- if (opcode->operands[0] != 0)
- printf("\t");
- /* Now extract and print the operands. */
- need_comma = 0;
- need_paren = 0;
- for (opindex = opcode->operands; *opindex != 0; opindex++)
- {
- long value;
- operand = powerpc_operands + *opindex;
- /* Operands that are marked FAKE are simply ignored. We
- already made sure that the extract function considered
- the instruction to be valid. */
- if ((operand->flags & PPC_OPERAND_FAKE) != 0)
- continue;
- /* Extract the value from the instruction. */
- if (operand->extract)
- value = (*operand->extract) (insn, dialect, &invalid);
- else
- {
- value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
- if ((operand->flags & PPC_OPERAND_SIGNED) != 0
- && (value & (1 << (operand->bits - 1))) != 0)
- value -= 1 << operand->bits;
- }
- /* If the operand is optional, and the value is zero, don't
- print anything. */
- if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
- && (operand->flags & PPC_OPERAND_NEXT) == 0
- && value == 0)
- continue;
- if (need_comma)
- {
- printf(",");
- need_comma = 0;
- }
- /* Print the operand as directed by the flags. */
- if ((operand->flags & PPC_OPERAND_GPR) != 0
- || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
- printf("r%ld", value);
- else if ((operand->flags & PPC_OPERAND_FPR) != 0)
- printf("f%ld", value);
- else if ((operand->flags & PPC_OPERAND_VR) != 0)
- printf("v%ld", value);
- else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
- print_address (memaddr + value);
- else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
- print_address (value & 0xffffffff);
- else if ((operand->flags & PPC_OPERAND_CR) == 0
- || (dialect & PPC_OPCODE_PPC) == 0)
- printf("%ld", value);
- else
- {
- if (operand->bits == 3)
- printf("cr%ld", value);
- else
- {
- static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
- int cr;
- int cc;
- cr = value >> 2;
- if (cr != 0)
- printf("4*cr%d+", cr);
- cc = value & 3;
- printf("%s", cbnames[cc]);
- }
- }
- if (need_paren)
- {
- printf(")");
- need_paren = 0;
- }
- if ((operand->flags & PPC_OPERAND_PARENS) == 0)
- need_comma = 1;
- else
- {
- printf("(");
- need_paren = 1;
- }
- }
- /* We have found and printed an instruction; return. */
- return 4;
- }
- if ((dialect & PPC_OPCODE_ANY) != 0)
- {
- dialect = ~PPC_OPCODE_ANY;
- goto again;
- }
- /* We could not find a match. */
- printf(".long 0x%lx", insn);
- return 4;
- }
|