]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/powerpc/xmon/ppc-dis.c
powerpc/xmon: Apply binutils changes to upgrade disassembly
[karo-tx-linux.git] / arch / powerpc / xmon / ppc-dis.c
1 /* ppc-dis.c -- Disassemble PowerPC instructions
2    Copyright (C) 1994-2016 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21 #include "sysdep.h"
22 #include <stdio.h>
23 #include "dis-asm.h"
24 #include "elf-bfd.h"
25 #include "elf/ppc.h"
26 #include "opintl.h"
27 #include "opcode/ppc.h"
28
29 /* This file provides several disassembler functions, all of which use
30    the disassembler interface defined in dis-asm.h.  Several functions
31    are provided because this file handles disassembly for the PowerPC
32    in both big and little endian mode and also for the POWER (RS/6000)
33    chip.  */
34 static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int,
35                                ppc_cpu_t);
36
37 struct dis_private
38 {
39   /* Stash the result of parsing disassembler_options here.  */
40   ppc_cpu_t dialect;
41 } private;
42
43 #define POWERPC_DIALECT(INFO) \
44   (((struct dis_private *) ((INFO)->private_data))->dialect)
45
46 struct ppc_mopt {
47   const char *opt;
48   ppc_cpu_t cpu;
49   ppc_cpu_t sticky;
50 };
51
52 struct ppc_mopt ppc_opts[] = {
53   { "403",     PPC_OPCODE_PPC | PPC_OPCODE_403,
54     0 },
55   { "405",     PPC_OPCODE_PPC | PPC_OPCODE_403 | PPC_OPCODE_405,
56     0 },
57   { "440",     (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440
58                 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI),
59     0 },
60   { "464",     (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440
61                 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI),
62     0 },
63   { "476",     (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_440
64                 | PPC_OPCODE_476 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5),
65     0 },
66   { "601",     PPC_OPCODE_PPC | PPC_OPCODE_601,
67     0 },
68   { "603",     PPC_OPCODE_PPC,
69     0 },
70   { "604",     PPC_OPCODE_PPC,
71     0 },
72   { "620",     PPC_OPCODE_PPC | PPC_OPCODE_64,
73     0 },
74   { "7400",    PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC,
75     0 },
76   { "7410",    PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC,
77     0 },
78   { "7450",    PPC_OPCODE_PPC | PPC_OPCODE_7450 | PPC_OPCODE_ALTIVEC,
79     0 },
80   { "7455",    PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC,
81     0 },
82   { "750cl",   PPC_OPCODE_PPC | PPC_OPCODE_750 | PPC_OPCODE_PPCPS
83     , 0 },
84   { "821",     PPC_OPCODE_PPC | PPC_OPCODE_860,
85     0 },
86   { "850",     PPC_OPCODE_PPC | PPC_OPCODE_860,
87     0 },
88   { "860",     PPC_OPCODE_PPC | PPC_OPCODE_860,
89     0 },
90   { "a2",      (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_POWER4
91                 | PPC_OPCODE_POWER5 | PPC_OPCODE_CACHELCK | PPC_OPCODE_64
92                 | PPC_OPCODE_A2),
93     0 },
94   { "altivec", PPC_OPCODE_PPC,
95     PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 },
96   { "any",     0,
97     PPC_OPCODE_ANY },
98   { "booke",   PPC_OPCODE_PPC | PPC_OPCODE_BOOKE,
99     0 },
100   { "booke32", PPC_OPCODE_PPC | PPC_OPCODE_BOOKE,
101     0 },
102   { "cell",    (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
103                 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC),
104     0 },
105   { "com",     PPC_OPCODE_COMMON,
106     0 },
107   { "e200z4",  (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE| PPC_OPCODE_SPE
108                 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
109                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
110                 | PPC_OPCODE_E500 | PPC_OPCODE_E200Z4),
111     PPC_OPCODE_VLE },
112   { "e300",    PPC_OPCODE_PPC | PPC_OPCODE_E300,
113     0 },
114   { "e500",    (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
115                 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
116                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
117                 | PPC_OPCODE_E500),
118     0 },
119   { "e500mc",  (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
120                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
121                 | PPC_OPCODE_E500MC),
122     0 },
123   { "e500mc64",  (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
124                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
125                 | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER5
126                 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
127     0 },
128   { "e5500",    (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
129                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
130                 | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
131                 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
132                 | PPC_OPCODE_POWER7),
133     0 },
134   { "e6500",   (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
135                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
136                 | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_ALTIVEC
137                 | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_E6500 | PPC_OPCODE_POWER4
138                 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
139     0 },
140   { "e500x2",  (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
141                 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
142                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
143                 | PPC_OPCODE_E500),
144     0 },
145   { "efs",     PPC_OPCODE_PPC | PPC_OPCODE_EFS,
146     0 },
147   { "power4",  PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4,
148     0 },
149   { "power5",  (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
150                 | PPC_OPCODE_POWER5),
151     0 },
152   { "power6",  (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
153                 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC),
154     0 },
155   { "power7",  (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
156                 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
157                 | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
158     0 },
159   { "power8",  (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
160                 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
161                 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
162                 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX),
163     0 },
164   { "power9",  (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
165                 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
166                 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
167                 | PPC_OPCODE_HTM | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
168                 | PPC_OPCODE_VSX | PPC_OPCODE_VSX3 ),
169     0 },
170   { "ppc",     PPC_OPCODE_PPC,
171     0 },
172   { "ppc32",   PPC_OPCODE_PPC,
173     0 },
174   { "ppc64",   PPC_OPCODE_PPC | PPC_OPCODE_64,
175     0 },
176   { "ppc64bridge", PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE,
177     0 },
178   { "ppcps",   PPC_OPCODE_PPC | PPC_OPCODE_PPCPS,
179     0 },
180   { "pwr",     PPC_OPCODE_POWER,
181     0 },
182   { "pwr2",    PPC_OPCODE_POWER | PPC_OPCODE_POWER2,
183     0 },
184   { "pwr4",    PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4,
185     0 },
186   { "pwr5",    (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
187                 | PPC_OPCODE_POWER5),
188     0 },
189   { "pwr5x",   (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
190                 | PPC_OPCODE_POWER5),
191     0 },
192   { "pwr6",    (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
193                 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC),
194     0 },
195   { "pwr7",    (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
196                 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
197                 | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
198     0 },
199   { "pwr8",    (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
200                 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
201                 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
202                 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX),
203     0 },
204   { "pwr9",    (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
205                 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
206                 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
207                 | PPC_OPCODE_HTM | PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2
208                 | PPC_OPCODE_VSX | PPC_OPCODE_VSX3 ),
209     0 },
210   { "pwrx",    PPC_OPCODE_POWER | PPC_OPCODE_POWER2,
211     0 },
212   { "spe",     PPC_OPCODE_PPC | PPC_OPCODE_EFS,
213     PPC_OPCODE_SPE },
214   { "titan",   (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_PMR
215                 | PPC_OPCODE_RFMCI | PPC_OPCODE_TITAN),
216     0 },
217   { "vle",     (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE| PPC_OPCODE_SPE
218                 | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
219                 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
220                 | PPC_OPCODE_E500),
221     PPC_OPCODE_VLE },
222   { "vsx",     PPC_OPCODE_PPC,
223     PPC_OPCODE_VSX | PPC_OPCODE_VSX3 },
224   { "htm",     PPC_OPCODE_PPC,
225     PPC_OPCODE_HTM },
226 };
227
228 /* Switch between Booke and VLE dialects for interlinked dumps.  */
229 static ppc_cpu_t
230 get_powerpc_dialect (struct disassemble_info *info)
231 {
232   ppc_cpu_t dialect = 0;
233
234   dialect = POWERPC_DIALECT (info);
235
236   /* Disassemble according to the section headers flags for VLE-mode.  */
237   if (dialect & PPC_OPCODE_VLE
238       && info->section->owner != NULL
239       && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour
240       && elf_object_id (info->section->owner) == PPC32_ELF_DATA
241       && (elf_section_flags (info->section) & SHF_PPC_VLE) != 0)
242     return dialect;
243   else
244     return dialect & ~ PPC_OPCODE_VLE;
245 }
246
247 /* Handle -m and -M options that set cpu type, and .machine arg.  */
248
249 ppc_cpu_t
250 ppc_parse_cpu (ppc_cpu_t ppc_cpu, ppc_cpu_t *sticky, const char *arg)
251 {
252   unsigned int i;
253
254   for (i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
255     if (strcmp (ppc_opts[i].opt, arg) == 0)
256       {
257         if (ppc_opts[i].sticky)
258           {
259             *sticky |= ppc_opts[i].sticky;
260             if ((ppc_cpu & ~*sticky) != 0)
261               break;
262           }
263         ppc_cpu = ppc_opts[i].cpu;
264         break;
265       }
266   if (i >= sizeof (ppc_opts) / sizeof (ppc_opts[0]))
267     return 0;
268
269   ppc_cpu |= *sticky;
270   return ppc_cpu;
271 }
272
273 /* Determine which set of machines to disassemble for.  */
274
275 static void
276 powerpc_init_dialect (struct disassemble_info *info)
277 {
278   ppc_cpu_t dialect = 0;
279   ppc_cpu_t sticky = 0;
280   char *arg;
281   struct dis_private *priv = calloc (sizeof (*priv), 1);
282
283   if (priv == NULL)
284     priv = &private;
285
286   switch (info->mach)
287     {
288     case bfd_mach_ppc_403:
289     case bfd_mach_ppc_403gc:
290       dialect = ppc_parse_cpu (dialect, &sticky, "403");
291       break;
292     case bfd_mach_ppc_405:
293       dialect = ppc_parse_cpu (dialect, &sticky, "405");
294       break;
295     case bfd_mach_ppc_601:
296       dialect = ppc_parse_cpu (dialect, &sticky, "601");
297       break;
298     case bfd_mach_ppc_a35:
299     case bfd_mach_ppc_rs64ii:
300     case bfd_mach_ppc_rs64iii:
301       dialect = ppc_parse_cpu (dialect, &sticky, "pwr2") | PPC_OPCODE_64;
302       break;
303     case bfd_mach_ppc_e500:
304       dialect = ppc_parse_cpu (dialect, &sticky, "e500");
305       break;
306     case bfd_mach_ppc_e500mc:
307       dialect = ppc_parse_cpu (dialect, &sticky, "e500mc");
308       break;
309     case bfd_mach_ppc_e500mc64:
310       dialect = ppc_parse_cpu (dialect, &sticky, "e500mc64");
311       break;
312     case bfd_mach_ppc_e5500:
313       dialect = ppc_parse_cpu (dialect, &sticky, "e5500");
314       break;
315     case bfd_mach_ppc_e6500:
316       dialect = ppc_parse_cpu (dialect, &sticky, "e6500");
317       break;
318     case bfd_mach_ppc_titan:
319       dialect = ppc_parse_cpu (dialect, &sticky, "titan");
320       break;
321     case bfd_mach_ppc_vle:
322       dialect = ppc_parse_cpu (dialect, &sticky, "vle");
323       break;
324     default:
325       dialect = ppc_parse_cpu (dialect, &sticky, "power9") | PPC_OPCODE_ANY;
326     }
327
328   arg = info->disassembler_options;
329   while (arg != NULL)
330     {
331       ppc_cpu_t new_cpu = 0;
332       char *end = strchr (arg, ',');
333
334       if (end != NULL)
335         *end = 0;
336
337       if ((new_cpu = ppc_parse_cpu (dialect, &sticky, arg)) != 0)
338         dialect = new_cpu;
339       else if (strcmp (arg, "32") == 0)
340         dialect &= ~(ppc_cpu_t) PPC_OPCODE_64;
341       else if (strcmp (arg, "64") == 0)
342         dialect |= PPC_OPCODE_64;
343       else
344         fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), arg);
345
346       if (end != NULL)
347         *end++ = ',';
348       arg = end;
349     }
350
351   info->private_data = priv;
352   POWERPC_DIALECT(info) = dialect;
353 }
354
355 #define PPC_OPCD_SEGS 64
356 static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS+1];
357 #define VLE_OPCD_SEGS 32
358 static unsigned short vle_opcd_indices[VLE_OPCD_SEGS+1];
359
360 /* Calculate opcode table indices to speed up disassembly,
361    and init dialect.  */
362
363 void
364 disassemble_init_powerpc (struct disassemble_info *info)
365 {
366   int i;
367   unsigned short last;
368
369   if (powerpc_opcd_indices[PPC_OPCD_SEGS] == 0)
370     {
371
372       i = powerpc_num_opcodes;
373       while (--i >= 0)
374         {
375           unsigned op = PPC_OP (powerpc_opcodes[i].opcode);
376
377           powerpc_opcd_indices[op] = i;
378         }
379
380       last = powerpc_num_opcodes;
381       for (i = PPC_OPCD_SEGS; i > 0; --i)
382         {
383           if (powerpc_opcd_indices[i] == 0)
384             powerpc_opcd_indices[i] = last;
385           last = powerpc_opcd_indices[i];
386         }
387
388       i = vle_num_opcodes;
389       while (--i >= 0)
390         {
391           unsigned op = VLE_OP (vle_opcodes[i].opcode, vle_opcodes[i].mask);
392           unsigned seg = VLE_OP_TO_SEG (op);
393
394           vle_opcd_indices[seg] = i;
395         }
396
397       last = vle_num_opcodes;
398       for (i = VLE_OPCD_SEGS; i > 0; --i)
399         {
400           if (vle_opcd_indices[i] == 0)
401             vle_opcd_indices[i] = last;
402           last = vle_opcd_indices[i];
403         }
404     }
405
406   if (info->arch == bfd_arch_powerpc)
407     powerpc_init_dialect (info);
408 }
409
410 /* Print a big endian PowerPC instruction.  */
411
412 int
413 print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
414 {
415   return print_insn_powerpc (memaddr, info, 1, get_powerpc_dialect (info));
416 }
417
418 /* Print a little endian PowerPC instruction.  */
419
420 int
421 print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
422 {
423   return print_insn_powerpc (memaddr, info, 0, get_powerpc_dialect (info));
424 }
425
426 /* Print a POWER (RS/6000) instruction.  */
427
428 int
429 print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
430 {
431   return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
432 }
433
434 /* Extract the operand value from the PowerPC or POWER instruction.  */
435
436 static long
437 operand_value_powerpc (const struct powerpc_operand *operand,
438                        unsigned long insn, ppc_cpu_t dialect)
439 {
440   long value;
441   int invalid;
442   /* Extract the value from the instruction.  */
443   if (operand->extract)
444     value = (*operand->extract) (insn, dialect, &invalid);
445   else
446     {
447       if (operand->shift >= 0)
448         value = (insn >> operand->shift) & operand->bitm;
449       else
450         value = (insn << -operand->shift) & operand->bitm;
451       if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
452         {
453           /* BITM is always some number of zeros followed by some
454              number of ones, followed by some number of zeros.  */
455           unsigned long top = operand->bitm;
456           /* top & -top gives the rightmost 1 bit, so this
457              fills in any trailing zeros.  */
458           top |= (top & -top) - 1;
459           top &= ~(top >> 1);
460           value = (value ^ top) - top;
461         }
462     }
463
464   return value;
465 }
466
467 /* Determine whether the optional operand(s) should be printed.  */
468
469 static int
470 skip_optional_operands (const unsigned char *opindex,
471                         unsigned long insn, ppc_cpu_t dialect)
472 {
473   const struct powerpc_operand *operand;
474
475   for (; *opindex != 0; opindex++)
476     {
477       operand = &powerpc_operands[*opindex];
478       if ((operand->flags & PPC_OPERAND_NEXT) != 0
479           || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
480               && operand_value_powerpc (operand, insn, dialect) !=
481                  ppc_optional_operand_value (operand)))
482         return 0;
483     }
484
485   return 1;
486 }
487
488 /* Find a match for INSN in the opcode table, given machine DIALECT.
489    A DIALECT of -1 is special, matching all machine opcode variations.  */
490
491 static const struct powerpc_opcode *
492 lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
493 {
494   const struct powerpc_opcode *opcode;
495   const struct powerpc_opcode *opcode_end;
496   unsigned long op;
497
498   /* Get the major opcode of the instruction.  */
499   op = PPC_OP (insn);
500
501   /* Find the first match in the opcode table for this major opcode.  */
502   opcode_end = powerpc_opcodes + powerpc_opcd_indices[op + 1];
503   for (opcode = powerpc_opcodes + powerpc_opcd_indices[op];
504        opcode < opcode_end;
505        ++opcode)
506     {
507       const unsigned char *opindex;
508       const struct powerpc_operand *operand;
509       int invalid;
510
511       if ((insn & opcode->mask) != opcode->opcode
512           || (dialect != (ppc_cpu_t) -1
513               && ((opcode->flags & dialect) == 0
514                   || (opcode->deprecated & dialect) != 0)))
515         continue;
516
517       /* Check validity of operands.  */
518       invalid = 0;
519       for (opindex = opcode->operands; *opindex != 0; opindex++)
520         {
521           operand = powerpc_operands + *opindex;
522           if (operand->extract)
523             (*operand->extract) (insn, dialect, &invalid);
524         }
525       if (invalid)
526         continue;
527
528       return opcode;
529     }
530
531   return NULL;
532 }
533
534 /* Find a match for INSN in the VLE opcode table.  */
535
536 static const struct powerpc_opcode *
537 lookup_vle (unsigned long insn)
538 {
539   const struct powerpc_opcode *opcode;
540   const struct powerpc_opcode *opcode_end;
541   unsigned op, seg;
542
543   op = PPC_OP (insn);
544   if (op >= 0x20 && op <= 0x37)
545     {
546       /* This insn has a 4-bit opcode.  */
547       op &= 0x3c;
548     }
549   seg = VLE_OP_TO_SEG (op);
550
551   /* Find the first match in the opcode table for this major opcode.  */
552   opcode_end = vle_opcodes + vle_opcd_indices[seg + 1];
553   for (opcode = vle_opcodes + vle_opcd_indices[seg];
554        opcode < opcode_end;
555        ++opcode)
556     {
557       unsigned long table_opcd = opcode->opcode;
558       unsigned long table_mask = opcode->mask;
559       bfd_boolean table_op_is_short = PPC_OP_SE_VLE(table_mask);
560       unsigned long insn2;
561       const unsigned char *opindex;
562       const struct powerpc_operand *operand;
563       int invalid;
564
565       insn2 = insn;
566       if (table_op_is_short)
567         insn2 >>= 16;
568       if ((insn2 & table_mask) != table_opcd)
569         continue;
570
571       /* Check validity of operands.  */
572       invalid = 0;
573       for (opindex = opcode->operands; *opindex != 0; ++opindex)
574         {
575           operand = powerpc_operands + *opindex;
576           if (operand->extract)
577             (*operand->extract) (insn, (ppc_cpu_t)0, &invalid);
578         }
579       if (invalid)
580         continue;
581
582       return opcode;
583     }
584
585   return NULL;
586 }
587
588 /* Print a PowerPC or POWER instruction.  */
589
590 static int
591 print_insn_powerpc (bfd_vma memaddr,
592                     struct disassemble_info *info,
593                     int bigendian,
594                     ppc_cpu_t dialect)
595 {
596   bfd_byte buffer[4];
597   int status;
598   unsigned long insn;
599   const struct powerpc_opcode *opcode;
600   bfd_boolean insn_is_short;
601
602   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
603   if (status != 0)
604     {
605       /* The final instruction may be a 2-byte VLE insn.  */
606       if ((dialect & PPC_OPCODE_VLE) != 0)
607         {
608           /* Clear buffer so unused bytes will not have garbage in them.  */
609           buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0;
610           status = (*info->read_memory_func) (memaddr, buffer, 2, info);
611           if (status != 0)
612             {
613               (*info->memory_error_func) (status, memaddr, info);
614               return -1;
615             }
616         }
617       else
618         {
619           (*info->memory_error_func) (status, memaddr, info);
620           return -1;
621         }
622     }
623
624   if (bigendian)
625     insn = bfd_getb32 (buffer);
626   else
627     insn = bfd_getl32 (buffer);
628
629   /* Get the major opcode of the insn.  */
630   opcode = NULL;
631   insn_is_short = FALSE;
632   if ((dialect & PPC_OPCODE_VLE) != 0)
633     {
634       opcode = lookup_vle (insn);
635       if (opcode != NULL)
636         insn_is_short = PPC_OP_SE_VLE(opcode->mask);
637     }
638   if (opcode == NULL)
639     opcode = lookup_powerpc (insn, dialect);
640   if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
641     opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
642
643   if (opcode != NULL)
644     {
645       const unsigned char *opindex;
646       const struct powerpc_operand *operand;
647       int need_comma;
648       int need_paren;
649       int skip_optional;
650
651       if (opcode->operands[0] != 0)
652         (*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
653       else
654         (*info->fprintf_func) (info->stream, "%s", opcode->name);
655
656       if (insn_is_short)
657         /* The operands will be fetched out of the 16-bit instruction.  */
658         insn >>= 16;
659
660       /* Now extract and print the operands.  */
661       need_comma = 0;
662       need_paren = 0;
663       skip_optional = -1;
664       for (opindex = opcode->operands; *opindex != 0; opindex++)
665         {
666           long value;
667
668           operand = powerpc_operands + *opindex;
669
670           /* Operands that are marked FAKE are simply ignored.  We
671              already made sure that the extract function considered
672              the instruction to be valid.  */
673           if ((operand->flags & PPC_OPERAND_FAKE) != 0)
674             continue;
675
676           /* If all of the optional operands have the value zero,
677              then don't print any of them.  */
678           if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
679             {
680               if (skip_optional < 0)
681                 skip_optional = skip_optional_operands (opindex, insn,
682                                                         dialect);
683               if (skip_optional)
684                 continue;
685             }
686
687           value = operand_value_powerpc (operand, insn, dialect);
688
689           if (need_comma)
690             {
691               (*info->fprintf_func) (info->stream, ",");
692               need_comma = 0;
693             }
694
695           /* Print the operand as directed by the flags.  */
696           if ((operand->flags & PPC_OPERAND_GPR) != 0
697               || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
698             (*info->fprintf_func) (info->stream, "r%ld", value);
699           else if ((operand->flags & PPC_OPERAND_FPR) != 0)
700             (*info->fprintf_func) (info->stream, "f%ld", value);
701           else if ((operand->flags & PPC_OPERAND_VR) != 0)
702             (*info->fprintf_func) (info->stream, "v%ld", value);
703           else if ((operand->flags & PPC_OPERAND_VSR) != 0)
704             (*info->fprintf_func) (info->stream, "vs%ld", value);
705           else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
706             (*info->print_address_func) (memaddr + value, info);
707           else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
708             (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
709           else if ((operand->flags & PPC_OPERAND_FSL) != 0)
710             (*info->fprintf_func) (info->stream, "fsl%ld", value);
711           else if ((operand->flags & PPC_OPERAND_FCR) != 0)
712             (*info->fprintf_func) (info->stream, "fcr%ld", value);
713           else if ((operand->flags & PPC_OPERAND_UDI) != 0)
714             (*info->fprintf_func) (info->stream, "%ld", value);
715           else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
716                    && (((dialect & PPC_OPCODE_PPC) != 0)
717                        || ((dialect & PPC_OPCODE_VLE) != 0)))
718             (*info->fprintf_func) (info->stream, "cr%ld", value);
719           else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
720                    && (((dialect & PPC_OPCODE_PPC) != 0)
721                        || ((dialect & PPC_OPCODE_VLE) != 0)))
722             {
723               static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
724               int cr;
725               int cc;
726
727               cr = value >> 2;
728               if (cr != 0)
729                 (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
730               cc = value & 3;
731               (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
732             }
733           else
734             (*info->fprintf_func) (info->stream, "%d", (int) value);
735
736           if (need_paren)
737             {
738               (*info->fprintf_func) (info->stream, ")");
739               need_paren = 0;
740             }
741
742           if ((operand->flags & PPC_OPERAND_PARENS) == 0)
743             need_comma = 1;
744           else
745             {
746               (*info->fprintf_func) (info->stream, "(");
747               need_paren = 1;
748             }
749         }
750
751       /* We have found and printed an instruction.
752          If it was a short VLE instruction we have more to do.  */
753       if (insn_is_short)
754         {
755           memaddr += 2;
756           return 2;
757         }
758       else
759         /* Otherwise, return.  */
760         return 4;
761     }
762
763   /* We could not find a match.  */
764   (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
765
766   return 4;
767 }
768
769 void
770 print_ppc_disassembler_options (FILE *stream)
771 {
772   unsigned int i, col;
773
774   fprintf (stream, _("\n\
775 The following PPC specific disassembler options are supported for use with\n\
776 the -M switch:\n"));
777
778   for (col = 0, i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
779     {
780       col += fprintf (stream, " %s,", ppc_opts[i].opt);
781       if (col > 66)
782         {
783           fprintf (stream, "\n");
784           col = 0;
785         }
786     }
787   fprintf (stream, " 32, 64\n");
788 }