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