Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* ppc-dis.c -- Disassemble PowerPC instructions |
08d96e0b | 2 | Copyright (C) 1994-2016 Free Software Foundation, Inc. |
1da177e4 LT |
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 | |
897f112b | 19 | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
1da177e4 | 20 | |
5b102782 BS |
21 | #include <asm/cputable.h> |
22 | #include <asm/cpu_has_feature.h> | |
23 | #include "nonstdio.h" | |
24 | #include "ansidecl.h" | |
25 | #include "ppc.h" | |
e0426047 | 26 | #include "dis-asm.h" |
1da177e4 | 27 | |
cc7639ce BS |
28 | /* This file provides several disassembler functions, all of which use |
29 | the disassembler interface defined in dis-asm.h. Several functions | |
30 | are provided because this file handles disassembly for the PowerPC | |
31 | in both big and little endian mode and also for the POWER (RS/6000) | |
32 | chip. */ | |
cc7639ce BS |
33 | |
34 | /* Extract the operand value from the PowerPC or POWER instruction. */ | |
35 | ||
36 | static long | |
37 | operand_value_powerpc (const struct powerpc_operand *operand, | |
08d96e0b | 38 | unsigned long insn, ppc_cpu_t dialect) |
cc7639ce BS |
39 | { |
40 | long value; | |
41 | int invalid; | |
42 | /* Extract the value from the instruction. */ | |
43 | if (operand->extract) | |
44 | value = (*operand->extract) (insn, dialect, &invalid); | |
45 | else | |
46 | { | |
08d96e0b BS |
47 | if (operand->shift >= 0) |
48 | value = (insn >> operand->shift) & operand->bitm; | |
49 | else | |
50 | value = (insn << -operand->shift) & operand->bitm; | |
cc7639ce BS |
51 | if ((operand->flags & PPC_OPERAND_SIGNED) != 0) |
52 | { | |
53 | /* BITM is always some number of zeros followed by some | |
08d96e0b | 54 | number of ones, followed by some number of zeros. */ |
cc7639ce BS |
55 | unsigned long top = operand->bitm; |
56 | /* top & -top gives the rightmost 1 bit, so this | |
57 | fills in any trailing zeros. */ | |
58 | top |= (top & -top) - 1; | |
59 | top &= ~(top >> 1); | |
60 | value = (value ^ top) - top; | |
61 | } | |
62 | } | |
63 | ||
64 | return value; | |
65 | } | |
66 | ||
67 | /* Determine whether the optional operand(s) should be printed. */ | |
68 | ||
69 | static int | |
70 | skip_optional_operands (const unsigned char *opindex, | |
08d96e0b | 71 | unsigned long insn, ppc_cpu_t dialect) |
cc7639ce BS |
72 | { |
73 | const struct powerpc_operand *operand; | |
74 | ||
75 | for (; *opindex != 0; opindex++) | |
76 | { | |
77 | operand = &powerpc_operands[*opindex]; | |
78 | if ((operand->flags & PPC_OPERAND_NEXT) != 0 | |
79 | || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 | |
08d96e0b BS |
80 | && operand_value_powerpc (operand, insn, dialect) != |
81 | ppc_optional_operand_value (operand))) | |
cc7639ce BS |
82 | return 0; |
83 | } | |
84 | ||
85 | return 1; | |
86 | } | |
87 | ||
08d96e0b BS |
88 | /* Find a match for INSN in the opcode table, given machine DIALECT. |
89 | A DIALECT of -1 is special, matching all machine opcode variations. */ | |
90 | ||
91 | static const struct powerpc_opcode * | |
92 | lookup_powerpc (unsigned long insn, ppc_cpu_t dialect) | |
93 | { | |
94 | const struct powerpc_opcode *opcode; | |
95 | const struct powerpc_opcode *opcode_end; | |
08d96e0b | 96 | |
5b102782 | 97 | opcode_end = powerpc_opcodes + powerpc_num_opcodes; |
08d96e0b | 98 | /* Find the first match in the opcode table for this major opcode. */ |
5b102782 | 99 | for (opcode = powerpc_opcodes; opcode < opcode_end; ++opcode) |
08d96e0b BS |
100 | { |
101 | const unsigned char *opindex; | |
102 | const struct powerpc_operand *operand; | |
103 | int invalid; | |
104 | ||
105 | if ((insn & opcode->mask) != opcode->opcode | |
106 | || (dialect != (ppc_cpu_t) -1 | |
107 | && ((opcode->flags & dialect) == 0 | |
108 | || (opcode->deprecated & dialect) != 0))) | |
109 | continue; | |
110 | ||
111 | /* Check validity of operands. */ | |
112 | invalid = 0; | |
113 | for (opindex = opcode->operands; *opindex != 0; opindex++) | |
114 | { | |
115 | operand = powerpc_operands + *opindex; | |
116 | if (operand->extract) | |
117 | (*operand->extract) (insn, dialect, &invalid); | |
118 | } | |
119 | if (invalid) | |
120 | continue; | |
121 | ||
122 | return opcode; | |
123 | } | |
124 | ||
125 | return NULL; | |
126 | } | |
127 | ||
5b102782 | 128 | /* Print a PowerPC or POWER instruction. */ |
08d96e0b | 129 | |
5b102782 | 130 | int print_insn_powerpc (unsigned long insn, unsigned long memaddr) |
08d96e0b BS |
131 | { |
132 | const struct powerpc_opcode *opcode; | |
5b102782 BS |
133 | bool insn_is_short; |
134 | ppc_cpu_t dialect; | |
08d96e0b | 135 | |
5b102782 BS |
136 | dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON |
137 | | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC; | |
08d96e0b | 138 | |
5b102782 BS |
139 | if (cpu_has_feature(CPU_FTRS_POWER5)) |
140 | dialect |= PPC_OPCODE_POWER5; | |
08d96e0b | 141 | |
5b102782 BS |
142 | if (cpu_has_feature(CPU_FTRS_CELL)) |
143 | dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC); | |
08d96e0b | 144 | |
5b102782 BS |
145 | if (cpu_has_feature(CPU_FTRS_POWER6)) |
146 | dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC); | |
cc7639ce | 147 | |
5b102782 BS |
148 | if (cpu_has_feature(CPU_FTRS_POWER7)) |
149 | dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | |
150 | | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX); | |
897f112b | 151 | |
5b102782 BS |
152 | if (cpu_has_feature(CPU_FTRS_POWER8)) |
153 | dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | |
154 | | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM | |
155 | | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX); | |
897f112b | 156 | |
5b102782 BS |
157 | if (cpu_has_feature(CPU_FTRS_POWER9)) |
158 | dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | |
159 | | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM | |
160 | | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | |
e7140639 | 161 | | PPC_OPCODE_VSX | PPC_OPCODE_VSX3); |
897f112b | 162 | |
08d96e0b BS |
163 | /* Get the major opcode of the insn. */ |
164 | opcode = NULL; | |
5b102782 BS |
165 | insn_is_short = false; |
166 | ||
08d96e0b BS |
167 | if (opcode == NULL) |
168 | opcode = lookup_powerpc (insn, dialect); | |
169 | if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) | |
170 | opcode = lookup_powerpc (insn, (ppc_cpu_t) -1); | |
1da177e4 | 171 | |
08d96e0b | 172 | if (opcode != NULL) |
1da177e4 | 173 | { |
1da177e4 LT |
174 | const unsigned char *opindex; |
175 | const struct powerpc_operand *operand; | |
1da177e4 LT |
176 | int need_comma; |
177 | int need_paren; | |
cc7639ce | 178 | int skip_optional; |
1da177e4 | 179 | |
1da177e4 | 180 | if (opcode->operands[0] != 0) |
5b102782 | 181 | printf("%-7s ", opcode->name); |
cc7639ce | 182 | else |
5b102782 | 183 | printf("%s", opcode->name); |
1da177e4 | 184 | |
08d96e0b BS |
185 | if (insn_is_short) |
186 | /* The operands will be fetched out of the 16-bit instruction. */ | |
187 | insn >>= 16; | |
188 | ||
1da177e4 LT |
189 | /* Now extract and print the operands. */ |
190 | need_comma = 0; | |
191 | need_paren = 0; | |
cc7639ce | 192 | skip_optional = -1; |
1da177e4 LT |
193 | for (opindex = opcode->operands; *opindex != 0; opindex++) |
194 | { | |
195 | long value; | |
196 | ||
197 | operand = powerpc_operands + *opindex; | |
198 | ||
199 | /* Operands that are marked FAKE are simply ignored. We | |
200 | already made sure that the extract function considered | |
201 | the instruction to be valid. */ | |
202 | if ((operand->flags & PPC_OPERAND_FAKE) != 0) | |
203 | continue; | |
204 | ||
cc7639ce BS |
205 | /* If all of the optional operands have the value zero, |
206 | then don't print any of them. */ | |
207 | if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) | |
1da177e4 | 208 | { |
cc7639ce BS |
209 | if (skip_optional < 0) |
210 | skip_optional = skip_optional_operands (opindex, insn, | |
211 | dialect); | |
212 | if (skip_optional) | |
213 | continue; | |
1da177e4 LT |
214 | } |
215 | ||
cc7639ce | 216 | value = operand_value_powerpc (operand, insn, dialect); |
1da177e4 LT |
217 | |
218 | if (need_comma) | |
219 | { | |
5b102782 | 220 | printf(","); |
1da177e4 LT |
221 | need_comma = 0; |
222 | } | |
223 | ||
224 | /* Print the operand as directed by the flags. */ | |
897f112b ME |
225 | if ((operand->flags & PPC_OPERAND_GPR) != 0 |
226 | || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0)) | |
5b102782 | 227 | printf("r%ld", value); |
1da177e4 | 228 | else if ((operand->flags & PPC_OPERAND_FPR) != 0) |
5b102782 | 229 | printf("f%ld", value); |
1da177e4 | 230 | else if ((operand->flags & PPC_OPERAND_VR) != 0) |
5b102782 | 231 | printf("v%ld", value); |
08d96e0b | 232 | else if ((operand->flags & PPC_OPERAND_VSR) != 0) |
5b102782 | 233 | printf("vs%ld", value); |
1da177e4 | 234 | else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) |
5b102782 | 235 | print_address(memaddr + value); |
1da177e4 | 236 | else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) |
5b102782 | 237 | print_address(value & 0xffffffff); |
08d96e0b | 238 | else if ((operand->flags & PPC_OPERAND_FSL) != 0) |
5b102782 | 239 | printf("fsl%ld", value); |
08d96e0b | 240 | else if ((operand->flags & PPC_OPERAND_FCR) != 0) |
5b102782 | 241 | printf("fcr%ld", value); |
08d96e0b | 242 | else if ((operand->flags & PPC_OPERAND_UDI) != 0) |
5b102782 | 243 | printf("%ld", value); |
08d96e0b BS |
244 | else if ((operand->flags & PPC_OPERAND_CR_REG) != 0 |
245 | && (((dialect & PPC_OPCODE_PPC) != 0) | |
246 | || ((dialect & PPC_OPCODE_VLE) != 0))) | |
5b102782 | 247 | printf("cr%ld", value); |
08d96e0b BS |
248 | else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0) |
249 | && (((dialect & PPC_OPCODE_PPC) != 0) | |
250 | || ((dialect & PPC_OPCODE_VLE) != 0))) | |
1da177e4 | 251 | { |
08d96e0b BS |
252 | static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; |
253 | int cr; | |
254 | int cc; | |
255 | ||
256 | cr = value >> 2; | |
257 | if (cr != 0) | |
5b102782 | 258 | printf("4*cr%d+", cr); |
08d96e0b | 259 | cc = value & 3; |
5b102782 | 260 | printf("%s", cbnames[cc]); |
1da177e4 | 261 | } |
08d96e0b | 262 | else |
5b102782 | 263 | printf("%d", (int) value); |
1da177e4 LT |
264 | |
265 | if (need_paren) | |
266 | { | |
5b102782 | 267 | printf(")"); |
1da177e4 LT |
268 | need_paren = 0; |
269 | } | |
270 | ||
271 | if ((operand->flags & PPC_OPERAND_PARENS) == 0) | |
272 | need_comma = 1; | |
273 | else | |
274 | { | |
5b102782 | 275 | printf("("); |
1da177e4 LT |
276 | need_paren = 1; |
277 | } | |
278 | } | |
279 | ||
08d96e0b BS |
280 | /* We have found and printed an instruction. |
281 | If it was a short VLE instruction we have more to do. */ | |
282 | if (insn_is_short) | |
283 | { | |
284 | memaddr += 2; | |
285 | return 2; | |
286 | } | |
287 | else | |
288 | /* Otherwise, return. */ | |
289 | return 4; | |
1da177e4 LT |
290 | } |
291 | ||
292 | /* We could not find a match. */ | |
5b102782 | 293 | printf(".long 0x%lx", insn); |
1da177e4 LT |
294 | |
295 | return 4; | |
296 | } |