Home | History | Annotate | Line # | Download | only in opcodes
mmix-dis.c revision 1.1.1.2
      1      1.1     skrll /* mmix-dis.c -- Disassemble MMIX instructions.
      2  1.1.1.2  christos    Copyright 2000, 2001, 2002, 2005, 2007 Free Software Foundation, Inc.
      3      1.1     skrll    Written by Hans-Peter Nilsson (hp (at) bitrange.com)
      4      1.1     skrll 
      5      1.1     skrll    This file is part of the GNU opcodes library.
      6      1.1     skrll 
      7      1.1     skrll    This library is free software; you can redistribute it and/or modify
      8      1.1     skrll    it under the terms of the GNU General Public License as published by
      9      1.1     skrll    the Free Software Foundation; either version 3, or (at your option)
     10      1.1     skrll    any later version.
     11      1.1     skrll 
     12      1.1     skrll    It is distributed in the hope that it will be useful, but WITHOUT
     13      1.1     skrll    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14      1.1     skrll    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     15      1.1     skrll    License for more details.
     16      1.1     skrll 
     17      1.1     skrll    You should have received a copy of the GNU General Public License
     18      1.1     skrll    along with this file; see the file COPYING.  If not, write to the Free
     19      1.1     skrll    Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
     20      1.1     skrll    MA 02110-1301, USA.  */
     21      1.1     skrll 
     22      1.1     skrll #include <stdio.h>
     23      1.1     skrll #include <string.h>
     24      1.1     skrll #include <stdlib.h>
     25      1.1     skrll #include "opcode/mmix.h"
     26      1.1     skrll #include "dis-asm.h"
     27      1.1     skrll #include "libiberty.h"
     28      1.1     skrll #include "bfd.h"
     29      1.1     skrll #include "opintl.h"
     30      1.1     skrll 
     31      1.1     skrll #define BAD_CASE(x)				\
     32      1.1     skrll  do						\
     33      1.1     skrll    {						\
     34      1.1     skrll      fprintf (stderr,				\
     35      1.1     skrll 	      _("Bad case %d (%s) in %s:%d\n"),	\
     36      1.1     skrll 	      x, #x, __FILE__, __LINE__);	\
     37      1.1     skrll      abort ();					\
     38      1.1     skrll    }						\
     39      1.1     skrll  while (0)
     40      1.1     skrll 
     41      1.1     skrll #define FATAL_DEBUG							\
     42      1.1     skrll  do									\
     43      1.1     skrll    {									\
     44      1.1     skrll      fprintf (stderr,							\
     45      1.1     skrll 	      _("Internal: Non-debugged code (test-case missing): %s:%d"),\
     46      1.1     skrll 	      __FILE__, __LINE__);					\
     47      1.1     skrll      abort ();								\
     48      1.1     skrll    }									\
     49      1.1     skrll  while (0)
     50      1.1     skrll 
     51      1.1     skrll #define ROUND_MODE(n)					\
     52      1.1     skrll  ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" :	\
     53      1.1     skrll   (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" :	\
     54      1.1     skrll   _("(unknown)"))
     55      1.1     skrll 
     56      1.1     skrll #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
     57      1.1     skrll #define INSN_BACKWARD_OFFSET_BIT (1 << 24)
     58      1.1     skrll 
     59      1.1     skrll struct mmix_dis_info
     60      1.1     skrll  {
     61      1.1     skrll    const char *reg_name[256];
     62      1.1     skrll    const char *spec_reg_name[32];
     63      1.1     skrll 
     64      1.1     skrll    /* Waste a little memory so we don't have to allocate each separately.
     65      1.1     skrll       We could have an array with static contents for these, but on the
     66      1.1     skrll       other hand, we don't have to.  */
     67      1.1     skrll    char basic_reg_name[256][sizeof ("$255")];
     68      1.1     skrll  };
     69      1.1     skrll 
     70      1.1     skrll /* Initialize a target-specific array in INFO.  */
     71      1.1     skrll 
     72      1.1     skrll static bfd_boolean
     73      1.1     skrll initialize_mmix_dis_info (struct disassemble_info *info)
     74      1.1     skrll {
     75      1.1     skrll   struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
     76  1.1.1.2  christos   long i;
     77      1.1     skrll 
     78      1.1     skrll   if (minfop == NULL)
     79      1.1     skrll     return FALSE;
     80      1.1     skrll 
     81      1.1     skrll   memset (minfop, 0, sizeof (*minfop));
     82      1.1     skrll 
     83      1.1     skrll   /* Initialize register names from register symbols.  If there's no
     84      1.1     skrll      register section, then there are no register symbols.  */
     85      1.1     skrll   if ((info->section != NULL && info->section->owner != NULL)
     86      1.1     skrll       || (info->symbols != NULL
     87      1.1     skrll 	  && info->symbols[0] != NULL
     88      1.1     skrll 	  && bfd_asymbol_bfd (info->symbols[0]) != NULL))
     89      1.1     skrll     {
     90      1.1     skrll       bfd *abfd = info->section && info->section->owner != NULL
     91      1.1     skrll 	? info->section->owner
     92      1.1     skrll 	: bfd_asymbol_bfd (info->symbols[0]);
     93      1.1     skrll       asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
     94      1.1     skrll 
     95      1.1     skrll       if (reg_section != NULL)
     96      1.1     skrll 	{
     97      1.1     skrll 	  /* The returned symcount *does* include the ending NULL.  */
     98      1.1     skrll 	  long symsize = bfd_get_symtab_upper_bound (abfd);
     99      1.1     skrll 	  asymbol **syms = malloc (symsize);
    100      1.1     skrll 	  long nsyms;
    101      1.1     skrll 
    102      1.1     skrll 	  if (syms == NULL)
    103      1.1     skrll 	    {
    104      1.1     skrll 	      FATAL_DEBUG;
    105      1.1     skrll 	      free (minfop);
    106      1.1     skrll 	      return FALSE;
    107      1.1     skrll 	    }
    108      1.1     skrll 	  nsyms = bfd_canonicalize_symtab (abfd, syms);
    109      1.1     skrll 
    110      1.1     skrll 	  /* We use the first name for a register.  If this is MMO, then
    111      1.1     skrll 	     it's the name with the first sequence number, presumably the
    112      1.1     skrll 	     first in the source.  */
    113      1.1     skrll 	  for (i = 0; i < nsyms && syms[i] != NULL; i++)
    114      1.1     skrll 	    {
    115      1.1     skrll 	      if (syms[i]->section == reg_section
    116      1.1     skrll 		  && syms[i]->value < 256
    117      1.1     skrll 		  && minfop->reg_name[syms[i]->value] == NULL)
    118      1.1     skrll 		minfop->reg_name[syms[i]->value] = syms[i]->name;
    119      1.1     skrll 	    }
    120      1.1     skrll 	}
    121      1.1     skrll     }
    122      1.1     skrll 
    123      1.1     skrll   /* Fill in the rest with the canonical names.  */
    124      1.1     skrll   for (i = 0; i < 256; i++)
    125      1.1     skrll     if (minfop->reg_name[i] == NULL)
    126      1.1     skrll       {
    127  1.1.1.2  christos 	sprintf (minfop->basic_reg_name[i], "$%ld", i);
    128      1.1     skrll 	minfop->reg_name[i] = minfop->basic_reg_name[i];
    129      1.1     skrll       }
    130      1.1     skrll 
    131      1.1     skrll   /* We assume it's actually a one-to-one mapping of number-to-name.  */
    132      1.1     skrll   for (i = 0; mmix_spec_regs[i].name != NULL; i++)
    133      1.1     skrll     minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
    134      1.1     skrll 
    135      1.1     skrll   info->private_data = (void *) minfop;
    136      1.1     skrll   return TRUE;
    137      1.1     skrll }
    138      1.1     skrll 
    139      1.1     skrll /* A table indexed by the first byte is constructed as we disassemble each
    140      1.1     skrll    tetrabyte.  The contents is a pointer into mmix_insns reflecting the
    141      1.1     skrll    first found entry with matching match-bits and lose-bits.  Further
    142      1.1     skrll    entries are considered one after one until the operand constraints
    143      1.1     skrll    match or the match-bits and lose-bits do not match.  Normally a
    144      1.1     skrll    "further entry" will just show that there was no other match.  */
    145      1.1     skrll 
    146      1.1     skrll static const struct mmix_opcode *
    147      1.1     skrll get_opcode (unsigned long insn)
    148      1.1     skrll {
    149      1.1     skrll   static const struct mmix_opcode **opcodes = NULL;
    150      1.1     skrll   const struct mmix_opcode *opcodep = mmix_opcodes;
    151      1.1     skrll   unsigned int opcode_part = (insn >> 24) & 255;
    152      1.1     skrll 
    153      1.1     skrll   if (opcodes == NULL)
    154      1.1     skrll     opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
    155      1.1     skrll 
    156      1.1     skrll   opcodep = opcodes[opcode_part];
    157      1.1     skrll   if (opcodep == NULL
    158      1.1     skrll       || (opcodep->match & insn) != opcodep->match
    159      1.1     skrll       || (opcodep->lose & insn) != 0)
    160      1.1     skrll     {
    161      1.1     skrll       /* Search through the table.  */
    162      1.1     skrll       for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
    163      1.1     skrll 	{
    164      1.1     skrll 	  /* FIXME: Break out this into an initialization function.  */
    165      1.1     skrll 	  if ((opcodep->match & (opcode_part << 24)) == opcode_part
    166      1.1     skrll 	      && (opcodep->lose & (opcode_part << 24)) == 0)
    167      1.1     skrll 	    opcodes[opcode_part] = opcodep;
    168      1.1     skrll 
    169      1.1     skrll 	  if ((opcodep->match & insn) == opcodep->match
    170      1.1     skrll 	      && (opcodep->lose & insn) == 0)
    171      1.1     skrll 	    break;
    172      1.1     skrll 	}
    173      1.1     skrll     }
    174      1.1     skrll 
    175      1.1     skrll   if (opcodep->name == NULL)
    176      1.1     skrll     return NULL;
    177      1.1     skrll 
    178      1.1     skrll   /* Check constraints.  If they don't match, loop through the next opcode
    179      1.1     skrll      entries.  */
    180      1.1     skrll   do
    181      1.1     skrll     {
    182      1.1     skrll       switch (opcodep->operands)
    183      1.1     skrll 	{
    184      1.1     skrll 	  /* These have no restraint on what can be in the lower three
    185      1.1     skrll 	     bytes.  */
    186      1.1     skrll 	case mmix_operands_regs:
    187      1.1     skrll 	case mmix_operands_reg_yz:
    188      1.1     skrll 	case mmix_operands_regs_z_opt:
    189      1.1     skrll 	case mmix_operands_regs_z:
    190      1.1     skrll 	case mmix_operands_jmp:
    191      1.1     skrll 	case mmix_operands_pushgo:
    192      1.1     skrll 	case mmix_operands_pop:
    193      1.1     skrll 	case mmix_operands_sync:
    194      1.1     skrll 	case mmix_operands_x_regs_z:
    195      1.1     skrll 	case mmix_operands_neg:
    196      1.1     skrll 	case mmix_operands_pushj:
    197      1.1     skrll 	case mmix_operands_regaddr:
    198      1.1     skrll 	case mmix_operands_get:
    199      1.1     skrll 	case mmix_operands_set:
    200      1.1     skrll 	case mmix_operands_save:
    201      1.1     skrll 	case mmix_operands_unsave:
    202      1.1     skrll 	case mmix_operands_xyz_opt:
    203      1.1     skrll 	  return opcodep;
    204      1.1     skrll 
    205      1.1     skrll 	  /* For a ROUND_MODE, the middle byte must be 0..4.  */
    206      1.1     skrll 	case mmix_operands_roundregs_z:
    207      1.1     skrll 	case mmix_operands_roundregs:
    208      1.1     skrll 	  {
    209      1.1     skrll 	    int midbyte = (insn >> 8) & 255;
    210      1.1     skrll 
    211      1.1     skrll 	    if (midbyte <= 4)
    212      1.1     skrll 	      return opcodep;
    213      1.1     skrll 	  }
    214      1.1     skrll 	break;
    215      1.1     skrll 
    216      1.1     skrll 	case mmix_operands_put:
    217      1.1     skrll 	  /* A "PUT".  If it is "immediate", then no restrictions,
    218      1.1     skrll 	     otherwise we have to make sure the register number is < 32.  */
    219      1.1     skrll 	  if ((insn & INSN_IMMEDIATE_BIT)
    220      1.1     skrll 	      || ((insn >> 16) & 255) < 32)
    221      1.1     skrll 	    return opcodep;
    222      1.1     skrll 	  break;
    223      1.1     skrll 
    224      1.1     skrll 	case mmix_operands_resume:
    225      1.1     skrll 	  /* Middle bytes must be zero.  */
    226      1.1     skrll 	  if ((insn & 0x00ffff00) == 0)
    227      1.1     skrll 	    return opcodep;
    228      1.1     skrll 	  break;
    229      1.1     skrll 
    230      1.1     skrll 	default:
    231      1.1     skrll 	  BAD_CASE (opcodep->operands);
    232      1.1     skrll 	}
    233      1.1     skrll 
    234      1.1     skrll       opcodep++;
    235      1.1     skrll     }
    236      1.1     skrll   while ((opcodep->match & insn) == opcodep->match
    237      1.1     skrll 	 && (opcodep->lose & insn) == 0);
    238      1.1     skrll 
    239      1.1     skrll   /* If we got here, we had no match.  */
    240      1.1     skrll   return NULL;
    241      1.1     skrll }
    242      1.1     skrll 
    243      1.1     skrll /* The main disassembly function.  */
    244      1.1     skrll 
    245      1.1     skrll int
    246      1.1     skrll print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
    247      1.1     skrll {
    248      1.1     skrll   unsigned char buffer[4];
    249      1.1     skrll   unsigned long insn;
    250      1.1     skrll   unsigned int x, y, z;
    251      1.1     skrll   const struct mmix_opcode *opcodep;
    252      1.1     skrll   int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
    253      1.1     skrll   struct mmix_dis_info *minfop;
    254      1.1     skrll 
    255      1.1     skrll   if (status != 0)
    256      1.1     skrll     {
    257      1.1     skrll       (*info->memory_error_func) (status, memaddr, info);
    258      1.1     skrll       return -1;
    259      1.1     skrll     }
    260      1.1     skrll 
    261      1.1     skrll   /* FIXME: Is -1 suitable?  */
    262      1.1     skrll   if (info->private_data == NULL
    263      1.1     skrll       && ! initialize_mmix_dis_info (info))
    264      1.1     skrll     return -1;
    265      1.1     skrll 
    266      1.1     skrll   minfop = (struct mmix_dis_info *) info->private_data;
    267      1.1     skrll   x = buffer[1];
    268      1.1     skrll   y = buffer[2];
    269      1.1     skrll   z = buffer[3];
    270      1.1     skrll 
    271      1.1     skrll   insn = bfd_getb32 (buffer);
    272      1.1     skrll 
    273      1.1     skrll   opcodep = get_opcode (insn);
    274      1.1     skrll 
    275      1.1     skrll   if (opcodep == NULL)
    276      1.1     skrll     {
    277      1.1     skrll       (*info->fprintf_func) (info->stream, _("*unknown*"));
    278      1.1     skrll       return 4;
    279      1.1     skrll     }
    280      1.1     skrll 
    281      1.1     skrll   (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
    282      1.1     skrll 
    283      1.1     skrll   /* Present bytes in the order they are laid out in memory.  */
    284      1.1     skrll   info->display_endian = BFD_ENDIAN_BIG;
    285      1.1     skrll 
    286      1.1     skrll   info->insn_info_valid = 1;
    287      1.1     skrll   info->bytes_per_chunk = 4;
    288      1.1     skrll   info->branch_delay_insns = 0;
    289      1.1     skrll   info->target = 0;
    290      1.1     skrll   switch (opcodep->type)
    291      1.1     skrll     {
    292      1.1     skrll     case mmix_type_normal:
    293      1.1     skrll     case mmix_type_memaccess_block:
    294      1.1     skrll       info->insn_type = dis_nonbranch;
    295      1.1     skrll       break;
    296      1.1     skrll 
    297      1.1     skrll     case mmix_type_branch:
    298      1.1     skrll       info->insn_type = dis_branch;
    299      1.1     skrll       break;
    300      1.1     skrll 
    301      1.1     skrll     case mmix_type_condbranch:
    302      1.1     skrll       info->insn_type = dis_condbranch;
    303      1.1     skrll       break;
    304      1.1     skrll 
    305      1.1     skrll     case mmix_type_memaccess_octa:
    306      1.1     skrll       info->insn_type = dis_dref;
    307      1.1     skrll       info->data_size = 8;
    308      1.1     skrll       break;
    309      1.1     skrll 
    310      1.1     skrll     case mmix_type_memaccess_tetra:
    311      1.1     skrll       info->insn_type = dis_dref;
    312      1.1     skrll       info->data_size = 4;
    313      1.1     skrll       break;
    314      1.1     skrll 
    315      1.1     skrll     case mmix_type_memaccess_wyde:
    316      1.1     skrll       info->insn_type = dis_dref;
    317      1.1     skrll       info->data_size = 2;
    318      1.1     skrll       break;
    319      1.1     skrll 
    320      1.1     skrll     case mmix_type_memaccess_byte:
    321      1.1     skrll       info->insn_type = dis_dref;
    322      1.1     skrll       info->data_size = 1;
    323      1.1     skrll       break;
    324      1.1     skrll 
    325      1.1     skrll     case mmix_type_jsr:
    326      1.1     skrll       info->insn_type = dis_jsr;
    327      1.1     skrll       break;
    328      1.1     skrll 
    329      1.1     skrll     default:
    330      1.1     skrll       BAD_CASE(opcodep->type);
    331      1.1     skrll     }
    332      1.1     skrll 
    333      1.1     skrll   switch (opcodep->operands)
    334      1.1     skrll     {
    335      1.1     skrll     case mmix_operands_regs:
    336      1.1     skrll       /*  All registers: "$X,$Y,$Z".  */
    337      1.1     skrll       (*info->fprintf_func) (info->stream, "%s,%s,%s",
    338      1.1     skrll 			     minfop->reg_name[x],
    339      1.1     skrll 			     minfop->reg_name[y],
    340      1.1     skrll 			     minfop->reg_name[z]);
    341      1.1     skrll       break;
    342      1.1     skrll 
    343      1.1     skrll     case mmix_operands_reg_yz:
    344      1.1     skrll       /* Like SETH - "$X,YZ".  */
    345      1.1     skrll       (*info->fprintf_func) (info->stream, "%s,0x%x",
    346      1.1     skrll 			     minfop->reg_name[x], y * 256 + z);
    347      1.1     skrll       break;
    348      1.1     skrll 
    349      1.1     skrll     case mmix_operands_regs_z_opt:
    350      1.1     skrll     case mmix_operands_regs_z:
    351      1.1     skrll     case mmix_operands_pushgo:
    352      1.1     skrll       /* The regular "$X,$Y,$Z|Z".  */
    353      1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    354      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s,%d",
    355      1.1     skrll 			       minfop->reg_name[x], minfop->reg_name[y], z);
    356      1.1     skrll       else
    357      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s,%s",
    358      1.1     skrll 			       minfop->reg_name[x],
    359      1.1     skrll 			       minfop->reg_name[y],
    360      1.1     skrll 			       minfop->reg_name[z]);
    361      1.1     skrll       break;
    362      1.1     skrll 
    363      1.1     skrll     case mmix_operands_jmp:
    364      1.1     skrll       /* Address; only JMP.  */
    365      1.1     skrll       {
    366      1.1     skrll 	bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
    367      1.1     skrll 
    368      1.1     skrll 	if (insn & INSN_BACKWARD_OFFSET_BIT)
    369      1.1     skrll 	  offset -= (256 * 65536) * 4;
    370      1.1     skrll 
    371      1.1     skrll 	info->target = memaddr + offset;
    372      1.1     skrll 	(*info->print_address_func) (memaddr + offset, info);
    373      1.1     skrll       }
    374      1.1     skrll       break;
    375      1.1     skrll 
    376      1.1     skrll     case mmix_operands_roundregs_z:
    377      1.1     skrll       /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
    378      1.1     skrll 	 "$X,ROUND_MODE,$Z|Z".  */
    379      1.1     skrll       if (y != 0)
    380      1.1     skrll 	{
    381      1.1     skrll 	  if (insn & INSN_IMMEDIATE_BIT)
    382      1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%s,%d",
    383      1.1     skrll 				   minfop->reg_name[x],
    384      1.1     skrll 				   ROUND_MODE (y), z);
    385      1.1     skrll 	  else
    386      1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%s,%s",
    387      1.1     skrll 				   minfop->reg_name[x],
    388      1.1     skrll 				   ROUND_MODE (y),
    389      1.1     skrll 				   minfop->reg_name[z]);
    390      1.1     skrll 	}
    391      1.1     skrll       else
    392      1.1     skrll 	{
    393      1.1     skrll 	  if (insn & INSN_IMMEDIATE_BIT)
    394      1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%d",
    395      1.1     skrll 				   minfop->reg_name[x], z);
    396      1.1     skrll 	  else
    397      1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%s",
    398      1.1     skrll 				   minfop->reg_name[x],
    399      1.1     skrll 				   minfop->reg_name[z]);
    400      1.1     skrll 	}
    401      1.1     skrll       break;
    402      1.1     skrll 
    403      1.1     skrll     case mmix_operands_pop:
    404      1.1     skrll       /* Like POP - "X,YZ".  */
    405      1.1     skrll       (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
    406      1.1     skrll       break;
    407      1.1     skrll 
    408      1.1     skrll     case mmix_operands_roundregs:
    409      1.1     skrll       /* Two registers, possibly with rounding: "$X,$Z" or
    410      1.1     skrll 	 "$X,ROUND_MODE,$Z".  */
    411      1.1     skrll       if (y != 0)
    412      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s,%s",
    413      1.1     skrll 			       minfop->reg_name[x],
    414      1.1     skrll 			       ROUND_MODE (y),
    415      1.1     skrll 			       minfop->reg_name[z]);
    416      1.1     skrll       else
    417      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s",
    418      1.1     skrll 			       minfop->reg_name[x],
    419      1.1     skrll 			       minfop->reg_name[z]);
    420      1.1     skrll       break;
    421      1.1     skrll 
    422      1.1     skrll     case mmix_operands_sync:
    423      1.1     skrll 	/* Like SYNC - "XYZ".  */
    424      1.1     skrll       (*info->fprintf_func) (info->stream, "%u",
    425      1.1     skrll 			     x * 65536 + y * 256 + z);
    426      1.1     skrll       break;
    427      1.1     skrll 
    428      1.1     skrll     case mmix_operands_x_regs_z:
    429      1.1     skrll       /* Like SYNCD - "X,$Y,$Z|Z".  */
    430      1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    431      1.1     skrll 	(*info->fprintf_func) (info->stream, "%d,%s,%d",
    432      1.1     skrll 			       x, minfop->reg_name[y], z);
    433      1.1     skrll       else
    434      1.1     skrll 	(*info->fprintf_func) (info->stream, "%d,%s,%s",
    435      1.1     skrll 			       x, minfop->reg_name[y],
    436      1.1     skrll 			       minfop->reg_name[z]);
    437      1.1     skrll       break;
    438      1.1     skrll 
    439      1.1     skrll     case mmix_operands_neg:
    440      1.1     skrll       /* Like NEG and NEGU - "$X,Y,$Z|Z".  */
    441      1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    442      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%d,%d",
    443      1.1     skrll 			       minfop->reg_name[x], y, z);
    444      1.1     skrll       else
    445      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%d,%s",
    446      1.1     skrll 			       minfop->reg_name[x], y,
    447      1.1     skrll 			       minfop->reg_name[z]);
    448      1.1     skrll       break;
    449      1.1     skrll 
    450      1.1     skrll     case mmix_operands_pushj:
    451      1.1     skrll     case mmix_operands_regaddr:
    452      1.1     skrll       /* Like GETA or branches - "$X,Address".  */
    453      1.1     skrll       {
    454      1.1     skrll 	bfd_signed_vma offset = (y * 256 + z) * 4;
    455      1.1     skrll 
    456      1.1     skrll 	if (insn & INSN_BACKWARD_OFFSET_BIT)
    457      1.1     skrll 	  offset -= 65536 * 4;
    458      1.1     skrll 
    459      1.1     skrll 	info->target = memaddr + offset;
    460      1.1     skrll 
    461      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
    462      1.1     skrll 	(*info->print_address_func) (memaddr + offset, info);
    463      1.1     skrll       }
    464      1.1     skrll       break;
    465      1.1     skrll 
    466      1.1     skrll     case mmix_operands_get:
    467      1.1     skrll       /* GET - "X,spec_reg".  */
    468      1.1     skrll       (*info->fprintf_func) (info->stream, "%s,%s",
    469      1.1     skrll 			     minfop->reg_name[x],
    470      1.1     skrll 			     minfop->spec_reg_name[z]);
    471      1.1     skrll       break;
    472      1.1     skrll 
    473      1.1     skrll     case mmix_operands_put:
    474      1.1     skrll       /* PUT - "spec_reg,$Z|Z".  */
    475      1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    476      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%d",
    477      1.1     skrll 			       minfop->spec_reg_name[x], z);
    478      1.1     skrll       else
    479      1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s",
    480      1.1     skrll 			       minfop->spec_reg_name[x],
    481      1.1     skrll 			       minfop->reg_name[z]);
    482      1.1     skrll       break;
    483      1.1     skrll 
    484      1.1     skrll     case mmix_operands_set:
    485      1.1     skrll       /*  Two registers, "$X,$Y".  */
    486      1.1     skrll       (*info->fprintf_func) (info->stream, "%s,%s",
    487      1.1     skrll 			     minfop->reg_name[x],
    488      1.1     skrll 			     minfop->reg_name[y]);
    489      1.1     skrll       break;
    490      1.1     skrll 
    491      1.1     skrll     case mmix_operands_save:
    492      1.1     skrll       /* SAVE - "$X,0".  */
    493      1.1     skrll       (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
    494      1.1     skrll       break;
    495      1.1     skrll 
    496      1.1     skrll     case mmix_operands_unsave:
    497      1.1     skrll       /* UNSAVE - "0,$Z".  */
    498      1.1     skrll       (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
    499      1.1     skrll       break;
    500      1.1     skrll 
    501      1.1     skrll     case mmix_operands_xyz_opt:
    502      1.1     skrll       /* Like SWYM or TRAP - "X,Y,Z".  */
    503      1.1     skrll       (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
    504      1.1     skrll       break;
    505      1.1     skrll 
    506      1.1     skrll     case mmix_operands_resume:
    507      1.1     skrll       /* Just "Z", like RESUME.  */
    508      1.1     skrll       (*info->fprintf_func) (info->stream, "%d", z);
    509      1.1     skrll       break;
    510      1.1     skrll 
    511      1.1     skrll     default:
    512      1.1     skrll       (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
    513      1.1     skrll 			     opcodep->operands);
    514      1.1     skrll       break;
    515      1.1     skrll     }
    516      1.1     skrll 
    517      1.1     skrll   return 4;
    518      1.1     skrll }
    519