ppc-dis.c revision 104834
1/* ppc-dis.c -- Disassemble PowerPC instructions
2   Copyright 1994, 1995, 2000, 2001, 2002 Free Software Foundation, Inc.
3   Written by Ian Lance Taylor, Cygnus Support
4
5This file is part of GDB, GAS, and the GNU binutils.
6
7GDB, GAS, and the GNU binutils are free software; you can redistribute
8them and/or modify them under the terms of the GNU General Public
9License as published by the Free Software Foundation; either version
102, or (at your option) any later version.
11
12GDB, GAS, and the GNU binutils are distributed in the hope that they
13will be useful, but WITHOUT ANY WARRANTY; without even the implied
14warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15the GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this file; see the file COPYING.  If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21#include <stdio.h>
22#include "sysdep.h"
23#include "dis-asm.h"
24#include "opcode/ppc.h"
25
26/* This file provides several disassembler functions, all of which use
27   the disassembler interface defined in dis-asm.h.  Several functions
28   are provided because this file handles disassembly for the PowerPC
29   in both big and little endian mode and also for the POWER (RS/6000)
30   chip.  */
31
32static int print_insn_powerpc PARAMS ((bfd_vma, struct disassemble_info *,
33				       int bigendian, int dialect));
34
35static int powerpc_dialect PARAMS ((struct disassemble_info *));
36
37/* Determine which set of machines to disassemble for.  PPC403/601 or
38   BookE.  For convenience, also disassemble instructions supported
39   by the AltiVec vector unit.  */
40
41int
42powerpc_dialect(info)
43     struct disassemble_info *info;
44{
45  int dialect = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC;
46
47  if (BFD_DEFAULT_TARGET_SIZE == 64)
48    dialect |= PPC_OPCODE_64;
49
50  if (info->disassembler_options
51      && (strcmp (info->disassembler_options, "booke") == 0
52	  || strcmp (info->disassembler_options, "booke32") == 0
53	  || strcmp (info->disassembler_options, "booke64") == 0))
54    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
55  else
56    dialect |= PPC_OPCODE_403 | PPC_OPCODE_601;
57
58  if (info->disassembler_options
59      && strcmp (info->disassembler_options, "power4") == 0)
60    dialect |= PPC_OPCODE_POWER4;
61
62  if (info->disassembler_options)
63    {
64      if (strstr (info->disassembler_options, "32") != NULL)
65	dialect &= ~PPC_OPCODE_64;
66      else if (strstr (info->disassembler_options, "64") != NULL)
67	dialect |= PPC_OPCODE_64;
68    }
69
70  return dialect;
71}
72
73/* Print a big endian PowerPC instruction.  */
74
75int
76print_insn_big_powerpc (memaddr, info)
77     bfd_vma memaddr;
78     struct disassemble_info *info;
79{
80  return print_insn_powerpc (memaddr, info, 1, powerpc_dialect(info));
81}
82
83/* Print a little endian PowerPC instruction.  */
84
85int
86print_insn_little_powerpc (memaddr, info)
87     bfd_vma memaddr;
88     struct disassemble_info *info;
89{
90  return print_insn_powerpc (memaddr, info, 0, powerpc_dialect(info));
91}
92
93/* Print a POWER (RS/6000) instruction.  */
94
95int
96print_insn_rs6000 (memaddr, info)
97     bfd_vma memaddr;
98     struct disassemble_info *info;
99{
100  return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
101}
102
103/* Print a PowerPC or POWER instruction.  */
104
105static int
106print_insn_powerpc (memaddr, info, bigendian, dialect)
107     bfd_vma memaddr;
108     struct disassemble_info *info;
109     int bigendian;
110     int dialect;
111{
112  bfd_byte buffer[4];
113  int status;
114  unsigned long insn;
115  const struct powerpc_opcode *opcode;
116  const struct powerpc_opcode *opcode_end;
117  unsigned long op;
118
119  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
120  if (status != 0)
121    {
122      (*info->memory_error_func) (status, memaddr, info);
123      return -1;
124    }
125
126  if (bigendian)
127    insn = bfd_getb32 (buffer);
128  else
129    insn = bfd_getl32 (buffer);
130
131  /* Get the major opcode of the instruction.  */
132  op = PPC_OP (insn);
133
134  /* Find the first match in the opcode table.  We could speed this up
135     a bit by doing a binary search on the major opcode.  */
136  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
137  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
138    {
139      unsigned long table_op;
140      const unsigned char *opindex;
141      const struct powerpc_operand *operand;
142      int invalid;
143      int need_comma;
144      int need_paren;
145
146      table_op = PPC_OP (opcode->opcode);
147      if (op < table_op)
148	break;
149      if (op > table_op)
150	continue;
151
152      if ((insn & opcode->mask) != opcode->opcode
153	  || (opcode->flags & dialect) == 0)
154	continue;
155
156      /* Make two passes over the operands.  First see if any of them
157	 have extraction functions, and, if they do, make sure the
158	 instruction is valid.  */
159      invalid = 0;
160      for (opindex = opcode->operands; *opindex != 0; opindex++)
161	{
162	  operand = powerpc_operands + *opindex;
163	  if (operand->extract)
164	    (*operand->extract) (insn, dialect, &invalid);
165	}
166      if (invalid)
167	continue;
168
169      /* The instruction is valid.  */
170      (*info->fprintf_func) (info->stream, "%s", opcode->name);
171      if (opcode->operands[0] != 0)
172	(*info->fprintf_func) (info->stream, "\t");
173
174      /* Now extract and print the operands.  */
175      need_comma = 0;
176      need_paren = 0;
177      for (opindex = opcode->operands; *opindex != 0; opindex++)
178	{
179	  long value;
180
181	  operand = powerpc_operands + *opindex;
182
183	  /* Operands that are marked FAKE are simply ignored.  We
184	     already made sure that the extract function considered
185	     the instruction to be valid.  */
186	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
187	    continue;
188
189	  /* Extract the value from the instruction.  */
190	  if (operand->extract)
191	    value = (*operand->extract) (insn, dialect, (int *) NULL);
192	  else
193	    {
194	      value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
195	      if ((operand->flags & PPC_OPERAND_SIGNED) != 0
196		  && (value & (1 << (operand->bits - 1))) != 0)
197		value -= 1 << operand->bits;
198	    }
199
200	  /* If the operand is optional, and the value is zero, don't
201	     print anything.  */
202	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
203	      && (operand->flags & PPC_OPERAND_NEXT) == 0
204	      && value == 0)
205	    continue;
206
207	  if (need_comma)
208	    {
209	      (*info->fprintf_func) (info->stream, ",");
210	      need_comma = 0;
211	    }
212
213	  /* Print the operand as directed by the flags.  */
214	  if ((operand->flags & PPC_OPERAND_GPR) != 0)
215	    (*info->fprintf_func) (info->stream, "r%ld", value);
216	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
217	    (*info->fprintf_func) (info->stream, "f%ld", value);
218	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
219	    (*info->fprintf_func) (info->stream, "v%ld", value);
220	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
221	    (*info->print_address_func) (memaddr + value, info);
222	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
223	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
224	  else if ((operand->flags & PPC_OPERAND_CR) == 0
225		   || (dialect & PPC_OPCODE_PPC) == 0)
226	    (*info->fprintf_func) (info->stream, "%ld", value);
227	  else
228	    {
229	      if (operand->bits == 3)
230		(*info->fprintf_func) (info->stream, "cr%d", value);
231	      else
232		{
233		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
234		  int cr;
235		  int cc;
236
237		  cr = value >> 2;
238		  if (cr != 0)
239		    (*info->fprintf_func) (info->stream, "4*cr%d", cr);
240		  cc = value & 3;
241		  if (cc != 0)
242		    {
243		      if (cr != 0)
244			(*info->fprintf_func) (info->stream, "+");
245		      (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
246		    }
247		}
248	    }
249
250	  if (need_paren)
251	    {
252	      (*info->fprintf_func) (info->stream, ")");
253	      need_paren = 0;
254	    }
255
256	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
257	    need_comma = 1;
258	  else
259	    {
260	      (*info->fprintf_func) (info->stream, "(");
261	      need_paren = 1;
262	    }
263	}
264
265      /* We have found and printed an instruction; return.  */
266      return 4;
267    }
268
269  /* We could not find a match.  */
270  (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
271
272  return 4;
273}
274
275void
276print_ppc_disassembler_options (FILE * stream)
277{
278  fprintf (stream, "\n\
279The following PPC specific disassembler options are supported for use with\n\
280the -M switch:\n");
281
282  fprintf (stream, "  booke|booke32|booke64    Disassemble the BookE instructions\n");
283  fprintf (stream, "  power4                   Disassemble the Power4 instructions\n");
284  fprintf (stream, "  32                       Do not disassemble 64-bit instructions\n");
285  fprintf (stream, "  64                       Allow disassembly of 64-bit instructions\n");
286}
287