daily update
[deliverable/binutils-gdb.git] / 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 }
This page took 0.037544 seconds and 4 git commands to generate.