Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / binutils / opcodes / ppc-dis.c
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
5 This file is part of GDB, GAS, and the GNU binutils.
6
7 GDB, GAS, and the GNU binutils are free software; you can redistribute
8 them and/or modify them under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either version
10 2, or (at your option) any later version.
11
12 GDB, GAS, and the GNU binutils are distributed in the hope that they
13 will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15 the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING.  If not, write to the Free
19 Software 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
32 static int print_insn_powerpc PARAMS ((bfd_vma, struct disassemble_info *,
33                                        int bigendian, int dialect));
34
35 static 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
41 int
42 powerpc_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
75 int
76 print_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
85 int
86 print_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
95 int
96 print_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
105 static int
106 print_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 }