Home | History | Annotate | Line # | Download | only in opcodes
      1       1.1     skrll /* mmix-dis.c -- Disassemble MMIX instructions.
      2  1.1.1.12  christos    Copyright (C) 2000-2026 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.1.3  christos #include "sysdep.h"
     23       1.1     skrll #include <stdio.h>
     24       1.1     skrll #include "opcode/mmix.h"
     25   1.1.1.6  christos #include "disassemble.h"
     26       1.1     skrll #include "libiberty.h"
     27       1.1     skrll #include "bfd.h"
     28       1.1     skrll #include "opintl.h"
     29       1.1     skrll 
     30   1.1.1.7  christos #define BAD_CASE(x)						\
     31   1.1.1.7  christos   do								\
     32   1.1.1.7  christos    {								\
     33   1.1.1.7  christos      opcodes_error_handler (_("bad case %d (%s) in %s:%d"),	\
     34   1.1.1.7  christos 			    x, #x, __FILE__, __LINE__);		\
     35   1.1.1.7  christos      abort ();							\
     36   1.1.1.7  christos    }								\
     37       1.1     skrll  while (0)
     38       1.1     skrll 
     39   1.1.1.7  christos #define FATAL_DEBUG						\
     40   1.1.1.7  christos  do								\
     41   1.1.1.7  christos    {								\
     42   1.1.1.7  christos      opcodes_error_handler (_("internal: non-debugged code "	\
     43   1.1.1.7  christos 			      "(test-case missing): %s:%d"),	\
     44   1.1.1.7  christos 			    __FILE__, __LINE__);		\
     45   1.1.1.7  christos      abort ();							\
     46   1.1.1.7  christos    }								\
     47       1.1     skrll  while (0)
     48       1.1     skrll 
     49       1.1     skrll #define ROUND_MODE(n)					\
     50       1.1     skrll  ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" :	\
     51       1.1     skrll   (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" :	\
     52       1.1     skrll   _("(unknown)"))
     53       1.1     skrll 
     54       1.1     skrll #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
     55       1.1     skrll #define INSN_BACKWARD_OFFSET_BIT (1 << 24)
     56       1.1     skrll 
     57   1.1.1.8  christos #define MAX_REG_NAME_LEN       256
     58   1.1.1.8  christos #define MAX_SPEC_REG_NAME_LEN  32
     59       1.1     skrll struct mmix_dis_info
     60       1.1     skrll  {
     61   1.1.1.8  christos    const char *reg_name[MAX_REG_NAME_LEN];
     62   1.1.1.8  christos    const char *spec_reg_name[MAX_SPEC_REG_NAME_LEN];
     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.1.8  christos    char basic_reg_name[MAX_REG_NAME_LEN][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.1.9  christos static bool
     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.1.9  christos     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.1.9  christos 	      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.1.8  christos 		  && syms[i]->value < MAX_REG_NAME_LEN
    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.1.11  christos 	  free (syms);
    121       1.1     skrll 	}
    122       1.1     skrll     }
    123       1.1     skrll 
    124       1.1     skrll   /* Fill in the rest with the canonical names.  */
    125   1.1.1.8  christos   for (i = 0; i < MAX_REG_NAME_LEN; i++)
    126       1.1     skrll     if (minfop->reg_name[i] == NULL)
    127       1.1     skrll       {
    128   1.1.1.2  christos 	sprintf (minfop->basic_reg_name[i], "$%ld", i);
    129       1.1     skrll 	minfop->reg_name[i] = minfop->basic_reg_name[i];
    130       1.1     skrll       }
    131       1.1     skrll 
    132       1.1     skrll   /* We assume it's actually a one-to-one mapping of number-to-name.  */
    133       1.1     skrll   for (i = 0; mmix_spec_regs[i].name != NULL; i++)
    134       1.1     skrll     minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
    135       1.1     skrll 
    136       1.1     skrll   info->private_data = (void *) minfop;
    137   1.1.1.9  christos   return true;
    138       1.1     skrll }
    139       1.1     skrll 
    140       1.1     skrll /* A table indexed by the first byte is constructed as we disassemble each
    141       1.1     skrll    tetrabyte.  The contents is a pointer into mmix_insns reflecting the
    142       1.1     skrll    first found entry with matching match-bits and lose-bits.  Further
    143       1.1     skrll    entries are considered one after one until the operand constraints
    144       1.1     skrll    match or the match-bits and lose-bits do not match.  Normally a
    145       1.1     skrll    "further entry" will just show that there was no other match.  */
    146       1.1     skrll 
    147       1.1     skrll static const struct mmix_opcode *
    148       1.1     skrll get_opcode (unsigned long insn)
    149       1.1     skrll {
    150       1.1     skrll   static const struct mmix_opcode **opcodes = NULL;
    151       1.1     skrll   const struct mmix_opcode *opcodep = mmix_opcodes;
    152       1.1     skrll   unsigned int opcode_part = (insn >> 24) & 255;
    153       1.1     skrll 
    154       1.1     skrll   if (opcodes == NULL)
    155       1.1     skrll     opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
    156       1.1     skrll 
    157       1.1     skrll   opcodep = opcodes[opcode_part];
    158       1.1     skrll   if (opcodep == NULL
    159       1.1     skrll       || (opcodep->match & insn) != opcodep->match
    160       1.1     skrll       || (opcodep->lose & insn) != 0)
    161       1.1     skrll     {
    162       1.1     skrll       /* Search through the table.  */
    163       1.1     skrll       for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
    164       1.1     skrll 	{
    165       1.1     skrll 	  /* FIXME: Break out this into an initialization function.  */
    166       1.1     skrll 	  if ((opcodep->match & (opcode_part << 24)) == opcode_part
    167       1.1     skrll 	      && (opcodep->lose & (opcode_part << 24)) == 0)
    168       1.1     skrll 	    opcodes[opcode_part] = opcodep;
    169       1.1     skrll 
    170       1.1     skrll 	  if ((opcodep->match & insn) == opcodep->match
    171       1.1     skrll 	      && (opcodep->lose & insn) == 0)
    172       1.1     skrll 	    break;
    173       1.1     skrll 	}
    174       1.1     skrll     }
    175       1.1     skrll 
    176       1.1     skrll   if (opcodep->name == NULL)
    177       1.1     skrll     return NULL;
    178       1.1     skrll 
    179       1.1     skrll   /* Check constraints.  If they don't match, loop through the next opcode
    180       1.1     skrll      entries.  */
    181       1.1     skrll   do
    182       1.1     skrll     {
    183       1.1     skrll       switch (opcodep->operands)
    184       1.1     skrll 	{
    185       1.1     skrll 	  /* These have no restraint on what can be in the lower three
    186       1.1     skrll 	     bytes.  */
    187       1.1     skrll 	case mmix_operands_regs:
    188       1.1     skrll 	case mmix_operands_reg_yz:
    189       1.1     skrll 	case mmix_operands_regs_z_opt:
    190       1.1     skrll 	case mmix_operands_regs_z:
    191       1.1     skrll 	case mmix_operands_jmp:
    192       1.1     skrll 	case mmix_operands_pushgo:
    193       1.1     skrll 	case mmix_operands_pop:
    194       1.1     skrll 	case mmix_operands_sync:
    195       1.1     skrll 	case mmix_operands_x_regs_z:
    196       1.1     skrll 	case mmix_operands_neg:
    197       1.1     skrll 	case mmix_operands_pushj:
    198       1.1     skrll 	case mmix_operands_regaddr:
    199       1.1     skrll 	case mmix_operands_get:
    200       1.1     skrll 	case mmix_operands_set:
    201       1.1     skrll 	case mmix_operands_save:
    202       1.1     skrll 	case mmix_operands_unsave:
    203       1.1     skrll 	case mmix_operands_xyz_opt:
    204       1.1     skrll 	  return opcodep;
    205       1.1     skrll 
    206       1.1     skrll 	  /* For a ROUND_MODE, the middle byte must be 0..4.  */
    207       1.1     skrll 	case mmix_operands_roundregs_z:
    208       1.1     skrll 	case mmix_operands_roundregs:
    209       1.1     skrll 	  {
    210       1.1     skrll 	    int midbyte = (insn >> 8) & 255;
    211       1.1     skrll 
    212       1.1     skrll 	    if (midbyte <= 4)
    213       1.1     skrll 	      return opcodep;
    214       1.1     skrll 	  }
    215       1.1     skrll 	break;
    216       1.1     skrll 
    217       1.1     skrll 	case mmix_operands_put:
    218       1.1     skrll 	  /* A "PUT".  If it is "immediate", then no restrictions,
    219       1.1     skrll 	     otherwise we have to make sure the register number is < 32.  */
    220       1.1     skrll 	  if ((insn & INSN_IMMEDIATE_BIT)
    221       1.1     skrll 	      || ((insn >> 16) & 255) < 32)
    222       1.1     skrll 	    return opcodep;
    223       1.1     skrll 	  break;
    224       1.1     skrll 
    225       1.1     skrll 	case mmix_operands_resume:
    226       1.1     skrll 	  /* Middle bytes must be zero.  */
    227       1.1     skrll 	  if ((insn & 0x00ffff00) == 0)
    228       1.1     skrll 	    return opcodep;
    229       1.1     skrll 	  break;
    230       1.1     skrll 
    231       1.1     skrll 	default:
    232       1.1     skrll 	  BAD_CASE (opcodep->operands);
    233       1.1     skrll 	}
    234       1.1     skrll 
    235       1.1     skrll       opcodep++;
    236       1.1     skrll     }
    237       1.1     skrll   while ((opcodep->match & insn) == opcodep->match
    238       1.1     skrll 	 && (opcodep->lose & insn) == 0);
    239       1.1     skrll 
    240       1.1     skrll   /* If we got here, we had no match.  */
    241       1.1     skrll   return NULL;
    242       1.1     skrll }
    243       1.1     skrll 
    244   1.1.1.8  christos static inline const char *
    245   1.1.1.8  christos get_reg_name (const struct mmix_dis_info * minfop, unsigned int x)
    246   1.1.1.8  christos {
    247   1.1.1.8  christos   if (x >= MAX_REG_NAME_LEN)
    248   1.1.1.8  christos     return _("*illegal*");
    249   1.1.1.8  christos   return minfop->reg_name[x];
    250   1.1.1.8  christos }
    251   1.1.1.8  christos 
    252   1.1.1.8  christos static inline const char *
    253   1.1.1.8  christos get_spec_reg_name (const struct mmix_dis_info * minfop, unsigned int x)
    254   1.1.1.8  christos {
    255   1.1.1.8  christos   if (x >= MAX_SPEC_REG_NAME_LEN)
    256   1.1.1.8  christos     return _("*illegal*");
    257   1.1.1.8  christos   return minfop->spec_reg_name[x];
    258   1.1.1.8  christos }
    259   1.1.1.8  christos 
    260       1.1     skrll /* The main disassembly function.  */
    261       1.1     skrll 
    262       1.1     skrll int
    263       1.1     skrll print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
    264       1.1     skrll {
    265       1.1     skrll   unsigned char buffer[4];
    266       1.1     skrll   unsigned long insn;
    267       1.1     skrll   unsigned int x, y, z;
    268       1.1     skrll   const struct mmix_opcode *opcodep;
    269       1.1     skrll   int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
    270       1.1     skrll   struct mmix_dis_info *minfop;
    271       1.1     skrll 
    272       1.1     skrll   if (status != 0)
    273       1.1     skrll     {
    274       1.1     skrll       (*info->memory_error_func) (status, memaddr, info);
    275       1.1     skrll       return -1;
    276       1.1     skrll     }
    277       1.1     skrll 
    278       1.1     skrll   /* FIXME: Is -1 suitable?  */
    279       1.1     skrll   if (info->private_data == NULL
    280       1.1     skrll       && ! initialize_mmix_dis_info (info))
    281       1.1     skrll     return -1;
    282       1.1     skrll 
    283       1.1     skrll   minfop = (struct mmix_dis_info *) info->private_data;
    284       1.1     skrll   x = buffer[1];
    285       1.1     skrll   y = buffer[2];
    286       1.1     skrll   z = buffer[3];
    287       1.1     skrll 
    288       1.1     skrll   insn = bfd_getb32 (buffer);
    289       1.1     skrll 
    290       1.1     skrll   opcodep = get_opcode (insn);
    291       1.1     skrll 
    292       1.1     skrll   if (opcodep == NULL)
    293       1.1     skrll     {
    294       1.1     skrll       (*info->fprintf_func) (info->stream, _("*unknown*"));
    295       1.1     skrll       return 4;
    296       1.1     skrll     }
    297       1.1     skrll 
    298       1.1     skrll   (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
    299       1.1     skrll 
    300       1.1     skrll   /* Present bytes in the order they are laid out in memory.  */
    301       1.1     skrll   info->display_endian = BFD_ENDIAN_BIG;
    302       1.1     skrll 
    303       1.1     skrll   info->insn_info_valid = 1;
    304       1.1     skrll   info->bytes_per_chunk = 4;
    305       1.1     skrll   info->branch_delay_insns = 0;
    306       1.1     skrll   info->target = 0;
    307       1.1     skrll   switch (opcodep->type)
    308       1.1     skrll     {
    309       1.1     skrll     case mmix_type_normal:
    310       1.1     skrll     case mmix_type_memaccess_block:
    311       1.1     skrll       info->insn_type = dis_nonbranch;
    312       1.1     skrll       break;
    313       1.1     skrll 
    314       1.1     skrll     case mmix_type_branch:
    315       1.1     skrll       info->insn_type = dis_branch;
    316       1.1     skrll       break;
    317       1.1     skrll 
    318       1.1     skrll     case mmix_type_condbranch:
    319       1.1     skrll       info->insn_type = dis_condbranch;
    320       1.1     skrll       break;
    321       1.1     skrll 
    322       1.1     skrll     case mmix_type_memaccess_octa:
    323       1.1     skrll       info->insn_type = dis_dref;
    324       1.1     skrll       info->data_size = 8;
    325       1.1     skrll       break;
    326       1.1     skrll 
    327       1.1     skrll     case mmix_type_memaccess_tetra:
    328       1.1     skrll       info->insn_type = dis_dref;
    329       1.1     skrll       info->data_size = 4;
    330       1.1     skrll       break;
    331       1.1     skrll 
    332       1.1     skrll     case mmix_type_memaccess_wyde:
    333       1.1     skrll       info->insn_type = dis_dref;
    334       1.1     skrll       info->data_size = 2;
    335       1.1     skrll       break;
    336       1.1     skrll 
    337       1.1     skrll     case mmix_type_memaccess_byte:
    338       1.1     skrll       info->insn_type = dis_dref;
    339       1.1     skrll       info->data_size = 1;
    340       1.1     skrll       break;
    341       1.1     skrll 
    342       1.1     skrll     case mmix_type_jsr:
    343       1.1     skrll       info->insn_type = dis_jsr;
    344       1.1     skrll       break;
    345       1.1     skrll 
    346       1.1     skrll     default:
    347       1.1     skrll       BAD_CASE(opcodep->type);
    348       1.1     skrll     }
    349       1.1     skrll 
    350       1.1     skrll   switch (opcodep->operands)
    351       1.1     skrll     {
    352       1.1     skrll     case mmix_operands_regs:
    353       1.1     skrll       /*  All registers: "$X,$Y,$Z".  */
    354       1.1     skrll       (*info->fprintf_func) (info->stream, "%s,%s,%s",
    355   1.1.1.8  christos 			     get_reg_name (minfop, x),
    356   1.1.1.8  christos 			     get_reg_name (minfop, y),
    357   1.1.1.8  christos 			     get_reg_name (minfop, z));
    358       1.1     skrll       break;
    359       1.1     skrll 
    360       1.1     skrll     case mmix_operands_reg_yz:
    361       1.1     skrll       /* Like SETH - "$X,YZ".  */
    362       1.1     skrll       (*info->fprintf_func) (info->stream, "%s,0x%x",
    363   1.1.1.8  christos 			     get_reg_name (minfop, x), y * 256 + z);
    364       1.1     skrll       break;
    365       1.1     skrll 
    366       1.1     skrll     case mmix_operands_regs_z_opt:
    367       1.1     skrll     case mmix_operands_regs_z:
    368       1.1     skrll     case mmix_operands_pushgo:
    369       1.1     skrll       /* The regular "$X,$Y,$Z|Z".  */
    370       1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    371       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s,%d",
    372   1.1.1.8  christos 			       get_reg_name (minfop, x),
    373   1.1.1.8  christos 			       get_reg_name (minfop, y), z);
    374       1.1     skrll       else
    375       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s,%s",
    376   1.1.1.8  christos 			       get_reg_name (minfop, x),
    377   1.1.1.8  christos 			       get_reg_name (minfop, y),
    378   1.1.1.8  christos 			       get_reg_name (minfop, z));
    379       1.1     skrll       break;
    380       1.1     skrll 
    381       1.1     skrll     case mmix_operands_jmp:
    382       1.1     skrll       /* Address; only JMP.  */
    383       1.1     skrll       {
    384       1.1     skrll 	bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
    385       1.1     skrll 
    386       1.1     skrll 	if (insn & INSN_BACKWARD_OFFSET_BIT)
    387       1.1     skrll 	  offset -= (256 * 65536) * 4;
    388       1.1     skrll 
    389       1.1     skrll 	info->target = memaddr + offset;
    390       1.1     skrll 	(*info->print_address_func) (memaddr + offset, info);
    391       1.1     skrll       }
    392       1.1     skrll       break;
    393       1.1     skrll 
    394       1.1     skrll     case mmix_operands_roundregs_z:
    395       1.1     skrll       /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
    396       1.1     skrll 	 "$X,ROUND_MODE,$Z|Z".  */
    397       1.1     skrll       if (y != 0)
    398       1.1     skrll 	{
    399       1.1     skrll 	  if (insn & INSN_IMMEDIATE_BIT)
    400       1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%s,%d",
    401   1.1.1.8  christos 				   get_reg_name (minfop, x),
    402       1.1     skrll 				   ROUND_MODE (y), z);
    403       1.1     skrll 	  else
    404       1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%s,%s",
    405   1.1.1.8  christos 				   get_reg_name (minfop, x),
    406       1.1     skrll 				   ROUND_MODE (y),
    407   1.1.1.8  christos 				   get_reg_name (minfop, z));
    408       1.1     skrll 	}
    409       1.1     skrll       else
    410       1.1     skrll 	{
    411       1.1     skrll 	  if (insn & INSN_IMMEDIATE_BIT)
    412       1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%d",
    413   1.1.1.8  christos 				   get_reg_name (minfop, x), z);
    414       1.1     skrll 	  else
    415       1.1     skrll 	    (*info->fprintf_func) (info->stream, "%s,%s",
    416   1.1.1.8  christos 				   get_reg_name (minfop, x),
    417   1.1.1.8  christos 				   get_reg_name (minfop, z));
    418       1.1     skrll 	}
    419       1.1     skrll       break;
    420       1.1     skrll 
    421       1.1     skrll     case mmix_operands_pop:
    422       1.1     skrll       /* Like POP - "X,YZ".  */
    423       1.1     skrll       (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
    424       1.1     skrll       break;
    425       1.1     skrll 
    426       1.1     skrll     case mmix_operands_roundregs:
    427       1.1     skrll       /* Two registers, possibly with rounding: "$X,$Z" or
    428       1.1     skrll 	 "$X,ROUND_MODE,$Z".  */
    429       1.1     skrll       if (y != 0)
    430       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s,%s",
    431   1.1.1.8  christos 			       get_reg_name (minfop, x),
    432       1.1     skrll 			       ROUND_MODE (y),
    433   1.1.1.8  christos 			       get_reg_name (minfop, z));
    434       1.1     skrll       else
    435       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s",
    436   1.1.1.8  christos 			       get_reg_name (minfop, x),
    437   1.1.1.8  christos 			       get_reg_name (minfop, z));
    438       1.1     skrll       break;
    439       1.1     skrll 
    440       1.1     skrll     case mmix_operands_sync:
    441       1.1     skrll 	/* Like SYNC - "XYZ".  */
    442       1.1     skrll       (*info->fprintf_func) (info->stream, "%u",
    443       1.1     skrll 			     x * 65536 + y * 256 + z);
    444       1.1     skrll       break;
    445       1.1     skrll 
    446       1.1     skrll     case mmix_operands_x_regs_z:
    447       1.1     skrll       /* Like SYNCD - "X,$Y,$Z|Z".  */
    448       1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    449       1.1     skrll 	(*info->fprintf_func) (info->stream, "%d,%s,%d",
    450   1.1.1.8  christos 			       x, get_reg_name (minfop, y), z);
    451       1.1     skrll       else
    452       1.1     skrll 	(*info->fprintf_func) (info->stream, "%d,%s,%s",
    453   1.1.1.8  christos 			       x, get_reg_name (minfop, y),
    454   1.1.1.8  christos 			       get_reg_name (minfop, z));
    455       1.1     skrll       break;
    456       1.1     skrll 
    457       1.1     skrll     case mmix_operands_neg:
    458       1.1     skrll       /* Like NEG and NEGU - "$X,Y,$Z|Z".  */
    459       1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    460       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%d,%d",
    461   1.1.1.8  christos 			       get_reg_name (minfop, x), y, z);
    462       1.1     skrll       else
    463       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%d,%s",
    464   1.1.1.8  christos 			       get_reg_name (minfop, x), y,
    465   1.1.1.8  christos 			       get_reg_name (minfop, z));
    466       1.1     skrll       break;
    467       1.1     skrll 
    468       1.1     skrll     case mmix_operands_pushj:
    469       1.1     skrll     case mmix_operands_regaddr:
    470       1.1     skrll       /* Like GETA or branches - "$X,Address".  */
    471       1.1     skrll       {
    472       1.1     skrll 	bfd_signed_vma offset = (y * 256 + z) * 4;
    473       1.1     skrll 
    474       1.1     skrll 	if (insn & INSN_BACKWARD_OFFSET_BIT)
    475       1.1     skrll 	  offset -= 65536 * 4;
    476       1.1     skrll 
    477       1.1     skrll 	info->target = memaddr + offset;
    478       1.1     skrll 
    479   1.1.1.8  christos 	(*info->fprintf_func) (info->stream, "%s,", get_reg_name (minfop, x));
    480       1.1     skrll 	(*info->print_address_func) (memaddr + offset, info);
    481       1.1     skrll       }
    482       1.1     skrll       break;
    483       1.1     skrll 
    484       1.1     skrll     case mmix_operands_get:
    485       1.1     skrll       /* GET - "X,spec_reg".  */
    486       1.1     skrll       (*info->fprintf_func) (info->stream, "%s,%s",
    487   1.1.1.8  christos 			     get_reg_name (minfop, x),
    488   1.1.1.8  christos 			     get_spec_reg_name (minfop, z));
    489       1.1     skrll       break;
    490       1.1     skrll 
    491       1.1     skrll     case mmix_operands_put:
    492       1.1     skrll       /* PUT - "spec_reg,$Z|Z".  */
    493       1.1     skrll       if (insn & INSN_IMMEDIATE_BIT)
    494       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%d",
    495   1.1.1.8  christos 			       get_spec_reg_name (minfop, x), z);
    496       1.1     skrll       else
    497       1.1     skrll 	(*info->fprintf_func) (info->stream, "%s,%s",
    498   1.1.1.8  christos 			       get_spec_reg_name (minfop, x),
    499   1.1.1.8  christos 			       get_reg_name (minfop, z));
    500       1.1     skrll       break;
    501       1.1     skrll 
    502       1.1     skrll     case mmix_operands_set:
    503       1.1     skrll       /*  Two registers, "$X,$Y".  */
    504       1.1     skrll       (*info->fprintf_func) (info->stream, "%s,%s",
    505   1.1.1.8  christos 			     get_reg_name (minfop, x),
    506   1.1.1.8  christos 			     get_reg_name (minfop, y));
    507       1.1     skrll       break;
    508       1.1     skrll 
    509       1.1     skrll     case mmix_operands_save:
    510       1.1     skrll       /* SAVE - "$X,0".  */
    511       1.1     skrll       (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
    512       1.1     skrll       break;
    513       1.1     skrll 
    514       1.1     skrll     case mmix_operands_unsave:
    515       1.1     skrll       /* UNSAVE - "0,$Z".  */
    516       1.1     skrll       (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
    517       1.1     skrll       break;
    518       1.1     skrll 
    519       1.1     skrll     case mmix_operands_xyz_opt:
    520       1.1     skrll       /* Like SWYM or TRAP - "X,Y,Z".  */
    521       1.1     skrll       (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
    522       1.1     skrll       break;
    523       1.1     skrll 
    524       1.1     skrll     case mmix_operands_resume:
    525       1.1     skrll       /* Just "Z", like RESUME.  */
    526       1.1     skrll       (*info->fprintf_func) (info->stream, "%d", z);
    527       1.1     skrll       break;
    528       1.1     skrll 
    529       1.1     skrll     default:
    530       1.1     skrll       (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
    531       1.1     skrll 			     opcodep->operands);
    532       1.1     skrll       break;
    533       1.1     skrll     }
    534       1.1     skrll 
    535       1.1     skrll   return 4;
    536       1.1     skrll }
    537