* win32-nat.c (safe_symbol_file_add_stub): Properly initialize linked list
[deliverable/binutils-gdb.git] / opcodes / ppc-dis.c
CommitLineData
252b5132 1/* ppc-dis.c -- Disassemble PowerPC instructions
060d22b0 2 Copyright 1994, 1995, 2000 Free Software Foundation, Inc.
252b5132
RH
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>
252b5132
RH
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
35/* Print a big endian PowerPC instruction. For convenience, also
786e2c0f
C
36 disassemble instructions supported by the Motorola PowerPC 601
37 and the Altivec vector unit. */
252b5132
RH
38
39int
40print_insn_big_powerpc (memaddr, info)
41 bfd_vma memaddr;
42 struct disassemble_info *info;
43{
44 return print_insn_powerpc (memaddr, info, 1,
786e2c0f
C
45 PPC_OPCODE_PPC | PPC_OPCODE_601 |
46 PPC_OPCODE_ALTIVEC);
252b5132
RH
47}
48
49/* Print a little endian PowerPC instruction. For convenience, also
786e2c0f
C
50 disassemble instructions supported by the Motorola PowerPC 601
51 and the Altivec vector unit. */
252b5132
RH
52
53int
54print_insn_little_powerpc (memaddr, info)
55 bfd_vma memaddr;
56 struct disassemble_info *info;
57{
58 return print_insn_powerpc (memaddr, info, 0,
786e2c0f
C
59 PPC_OPCODE_PPC | PPC_OPCODE_601 |
60 PPC_OPCODE_ALTIVEC);
252b5132
RH
61}
62
63/* Print a POWER (RS/6000) instruction. */
64
65int
66print_insn_rs6000 (memaddr, info)
67 bfd_vma memaddr;
68 struct disassemble_info *info;
69{
70 return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
71}
72
73/* Print a PowerPC or POWER instruction. */
74
75static int
76print_insn_powerpc (memaddr, info, bigendian, dialect)
77 bfd_vma memaddr;
78 struct disassemble_info *info;
79 int bigendian;
80 int dialect;
81{
82 bfd_byte buffer[4];
83 int status;
84 unsigned long insn;
85 const struct powerpc_opcode *opcode;
86 const struct powerpc_opcode *opcode_end;
87 unsigned long op;
88
89 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
90 if (status != 0)
91 {
92 (*info->memory_error_func) (status, memaddr, info);
93 return -1;
94 }
95
96 if (bigendian)
97 insn = bfd_getb32 (buffer);
98 else
99 insn = bfd_getl32 (buffer);
100
101 /* Get the major opcode of the instruction. */
102 op = PPC_OP (insn);
103
104 /* Find the first match in the opcode table. We could speed this up
105 a bit by doing a binary search on the major opcode. */
106 opcode_end = powerpc_opcodes + powerpc_num_opcodes;
107 for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
108 {
109 unsigned long table_op;
110 const unsigned char *opindex;
111 const struct powerpc_operand *operand;
112 int invalid;
113 int need_comma;
114 int need_paren;
115
116 table_op = PPC_OP (opcode->opcode);
117 if (op < table_op)
118 break;
119 if (op > table_op)
120 continue;
121
122 if ((insn & opcode->mask) != opcode->opcode
123 || (opcode->flags & dialect) == 0)
124 continue;
125
126 /* Make two passes over the operands. First see if any of them
127 have extraction functions, and, if they do, make sure the
128 instruction is valid. */
129 invalid = 0;
130 for (opindex = opcode->operands; *opindex != 0; opindex++)
131 {
132 operand = powerpc_operands + *opindex;
133 if (operand->extract)
134 (*operand->extract) (insn, &invalid);
135 }
136 if (invalid)
137 continue;
138
139 /* The instruction is valid. */
140 (*info->fprintf_func) (info->stream, "%s", opcode->name);
141 if (opcode->operands[0] != 0)
142 (*info->fprintf_func) (info->stream, "\t");
143
144 /* Now extract and print the operands. */
145 need_comma = 0;
146 need_paren = 0;
147 for (opindex = opcode->operands; *opindex != 0; opindex++)
148 {
149 long value;
150
151 operand = powerpc_operands + *opindex;
152
153 /* Operands that are marked FAKE are simply ignored. We
154 already made sure that the extract function considered
155 the instruction to be valid. */
156 if ((operand->flags & PPC_OPERAND_FAKE) != 0)
157 continue;
158
159 /* Extract the value from the instruction. */
160 if (operand->extract)
161 value = (*operand->extract) (insn, (int *) NULL);
162 else
163 {
164 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
165 if ((operand->flags & PPC_OPERAND_SIGNED) != 0
166 && (value & (1 << (operand->bits - 1))) != 0)
167 value -= 1 << operand->bits;
168 }
169
170 /* If the operand is optional, and the value is zero, don't
171 print anything. */
172 if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
173 && (operand->flags & PPC_OPERAND_NEXT) == 0
174 && value == 0)
175 continue;
176
177 if (need_comma)
178 {
179 (*info->fprintf_func) (info->stream, ",");
180 need_comma = 0;
181 }
182
183 /* Print the operand as directed by the flags. */
184 if ((operand->flags & PPC_OPERAND_GPR) != 0)
185 (*info->fprintf_func) (info->stream, "r%ld", value);
186 else if ((operand->flags & PPC_OPERAND_FPR) != 0)
187 (*info->fprintf_func) (info->stream, "f%ld", value);
786e2c0f
C
188 else if ((operand->flags & PPC_OPERAND_VR) != 0)
189 (*info->fprintf_func) (info->stream, "v%ld", value);
252b5132
RH
190 else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
191 (*info->print_address_func) (memaddr + value, info);
192 else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
193 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
194 else if ((operand->flags & PPC_OPERAND_CR) == 0
195 || (dialect & PPC_OPCODE_PPC) == 0)
196 (*info->fprintf_func) (info->stream, "%ld", value);
197 else
198 {
199 if (operand->bits == 3)
200 (*info->fprintf_func) (info->stream, "cr%d", value);
201 else
202 {
203 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
204 int cr;
205 int cc;
206
207 cr = value >> 2;
208 if (cr != 0)
209 (*info->fprintf_func) (info->stream, "4*cr%d", cr);
210 cc = value & 3;
211 if (cc != 0)
212 {
213 if (cr != 0)
214 (*info->fprintf_func) (info->stream, "+");
215 (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
216 }
217 }
218 }
219
220 if (need_paren)
221 {
222 (*info->fprintf_func) (info->stream, ")");
223 need_paren = 0;
224 }
225
226 if ((operand->flags & PPC_OPERAND_PARENS) == 0)
227 need_comma = 1;
228 else
229 {
230 (*info->fprintf_func) (info->stream, "(");
231 need_paren = 1;
232 }
233 }
234
235 /* We have found and printed an instruction; return. */
236 return 4;
237 }
238
239 /* We could not find a match. */
240 (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
241
242 return 4;
243}
This page took 0.120428 seconds and 4 git commands to generate.