1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <asm/cputable.h>
22#include <asm/cpu_has_feature.h>
23#include "nonstdio.h"
24#include "ansidecl.h"
25#include "ppc.h"
26#include "dis-asm.h"
27
28
29
30
31
32
33
34
35
36static long
37operand_value_powerpc (const struct powerpc_operand *operand,
38 unsigned long insn, ppc_cpu_t dialect)
39{
40 long value;
41 int invalid;
42
43 if (operand->extract)
44 value = (*operand->extract) (insn, dialect, &invalid);
45 else
46 {
47 if (operand->shift >= 0)
48 value = (insn >> operand->shift) & operand->bitm;
49 else
50 value = (insn << -operand->shift) & operand->bitm;
51 if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
52 {
53
54
55 unsigned long top = operand->bitm;
56
57
58 top |= (top & -top) - 1;
59 top &= ~(top >> 1);
60 value = (value ^ top) - top;
61 }
62 }
63
64 return value;
65}
66
67
68
69static int
70skip_optional_operands (const unsigned char *opindex,
71 unsigned long insn, ppc_cpu_t dialect)
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
80 && operand_value_powerpc (operand, insn, dialect) !=
81 ppc_optional_operand_value (operand)))
82 return 0;
83 }
84
85 return 1;
86}
87
88
89
90
91static const struct powerpc_opcode *
92lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
93{
94 const struct powerpc_opcode *opcode;
95 const struct powerpc_opcode *opcode_end;
96 unsigned long op;
97
98
99 op = PPC_OP (insn);
100
101 opcode_end = powerpc_opcodes + powerpc_num_opcodes;
102
103 for (opcode = powerpc_opcodes; opcode < opcode_end; ++opcode)
104 {
105 const unsigned char *opindex;
106 const struct powerpc_operand *operand;
107 int invalid;
108
109 if ((insn & opcode->mask) != opcode->opcode
110 || (dialect != (ppc_cpu_t) -1
111 && ((opcode->flags & dialect) == 0
112 || (opcode->deprecated & dialect) != 0)))
113 continue;
114
115
116 invalid = 0;
117 for (opindex = opcode->operands; *opindex != 0; opindex++)
118 {
119 operand = powerpc_operands + *opindex;
120 if (operand->extract)
121 (*operand->extract) (insn, dialect, &invalid);
122 }
123 if (invalid)
124 continue;
125
126 return opcode;
127 }
128
129 return NULL;
130}
131
132
133
134int print_insn_powerpc (unsigned long insn, unsigned long memaddr)
135{
136 const struct powerpc_opcode *opcode;
137 bool insn_is_short;
138 ppc_cpu_t dialect;
139
140 dialect = PPC_OPCODE_PPC | PPC_OPCODE_COMMON
141 | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_ALTIVEC;
142
143 if (cpu_has_feature(CPU_FTRS_POWER5))
144 dialect |= PPC_OPCODE_POWER5;
145
146 if (cpu_has_feature(CPU_FTRS_CELL))
147 dialect |= (PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC);
148
149 if (cpu_has_feature(CPU_FTRS_POWER6))
150 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC);
151
152 if (cpu_has_feature(CPU_FTRS_POWER7))
153 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
154 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX);
155
156 if (cpu_has_feature(CPU_FTRS_POWER8))
157 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
158 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
159 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX);
160
161 if (cpu_has_feature(CPU_FTRS_POWER9))
162 dialect |= (PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
163 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_HTM
164 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
165 | PPC_OPCODE_VSX | PPC_OPCODE_VSX3),
166
167
168 opcode = NULL;
169 insn_is_short = false;
170
171 if (opcode == NULL)
172 opcode = lookup_powerpc (insn, dialect);
173 if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
174 opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
175
176 if (opcode != NULL)
177 {
178 const unsigned char *opindex;
179 const struct powerpc_operand *operand;
180 int need_comma;
181 int need_paren;
182 int skip_optional;
183
184 if (opcode->operands[0] != 0)
185 printf("%-7s ", opcode->name);
186 else
187 printf("%s", opcode->name);
188
189 if (insn_is_short)
190
191 insn >>= 16;
192
193
194 need_comma = 0;
195 need_paren = 0;
196 skip_optional = -1;
197 for (opindex = opcode->operands; *opindex != 0; opindex++)
198 {
199 long value;
200
201 operand = powerpc_operands + *opindex;
202
203
204
205
206 if ((operand->flags & PPC_OPERAND_FAKE) != 0)
207 continue;
208
209
210
211 if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
212 {
213 if (skip_optional < 0)
214 skip_optional = skip_optional_operands (opindex, insn,
215 dialect);
216 if (skip_optional)
217 continue;
218 }
219
220 value = operand_value_powerpc (operand, insn, dialect);
221
222 if (need_comma)
223 {
224 printf(",");
225 need_comma = 0;
226 }
227
228
229 if ((operand->flags & PPC_OPERAND_GPR) != 0
230 || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
231 printf("r%ld", value);
232 else if ((operand->flags & PPC_OPERAND_FPR) != 0)
233 printf("f%ld", value);
234 else if ((operand->flags & PPC_OPERAND_VR) != 0)
235 printf("v%ld", value);
236 else if ((operand->flags & PPC_OPERAND_VSR) != 0)
237 printf("vs%ld", value);
238 else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
239 print_address(memaddr + value);
240 else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
241 print_address(value & 0xffffffff);
242 else if ((operand->flags & PPC_OPERAND_FSL) != 0)
243 printf("fsl%ld", value);
244 else if ((operand->flags & PPC_OPERAND_FCR) != 0)
245 printf("fcr%ld", value);
246 else if ((operand->flags & PPC_OPERAND_UDI) != 0)
247 printf("%ld", value);
248 else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
249 && (((dialect & PPC_OPCODE_PPC) != 0)
250 || ((dialect & PPC_OPCODE_VLE) != 0)))
251 printf("cr%ld", value);
252 else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
253 && (((dialect & PPC_OPCODE_PPC) != 0)
254 || ((dialect & PPC_OPCODE_VLE) != 0)))
255 {
256 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
257 int cr;
258 int cc;
259
260 cr = value >> 2;
261 if (cr != 0)
262 printf("4*cr%d+", cr);
263 cc = value & 3;
264 printf("%s", cbnames[cc]);
265 }
266 else
267 printf("%d", (int) value);
268
269 if (need_paren)
270 {
271 printf(")");
272 need_paren = 0;
273 }
274
275 if ((operand->flags & PPC_OPERAND_PARENS) == 0)
276 need_comma = 1;
277 else
278 {
279 printf("(");
280 need_paren = 1;
281 }
282 }
283
284
285
286 if (insn_is_short)
287 {
288 memaddr += 2;
289 return 2;
290 }
291 else
292
293 return 4;
294 }
295
296
297 printf(".long 0x%lx", insn);
298
299 return 4;
300}
301