Back to index

cell-binutils  2.17cvs20070401
mmix-dis.c
Go to the documentation of this file.
00001 /* mmix-dis.c -- Disassemble MMIX instructions.
00002    Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
00003    Written by Hans-Peter Nilsson (hp@bitrange.com)
00004 
00005    This file is part of GDB and the GNU binutils.
00006 
00007    GDB and the GNU binutils are free software; you can redistribute
00008    them and/or modify them under the terms of the GNU General Public
00009    License as published by the Free Software Foundation; either version 2,
00010    or (at your option) any later version.
00011 
00012    GDB and the GNU binutils are distributed in the hope that they
00013    will be useful, but WITHOUT ANY WARRANTY; without even the implied
00014    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
00015    the GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this file; see the file COPYING.  If not, write to the Free
00019    Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
00020    MA 02110-1301, USA.  */
00021 
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include "opcode/mmix.h"
00026 #include "dis-asm.h"
00027 #include "libiberty.h"
00028 #include "bfd.h"
00029 #include "opintl.h"
00030 
00031 #define BAD_CASE(x)                       \
00032  do                                       \
00033    {                                      \
00034      fprintf (stderr,                            \
00035              _("Bad case %d (%s) in %s:%d\n"),   \
00036              x, #x, __FILE__, __LINE__);  \
00037      abort ();                                   \
00038    }                                      \
00039  while (0)
00040 
00041 #define FATAL_DEBUG                                            \
00042  do                                                            \
00043    {                                                           \
00044      fprintf (stderr,                                                 \
00045              _("Internal: Non-debugged code (test-case missing): %s:%d"),\
00046              __FILE__, __LINE__);                              \
00047      abort ();                                                        \
00048    }                                                           \
00049  while (0)
00050 
00051 #define ROUND_MODE(n)                                   \
00052  ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" :      \
00053   (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" :   \
00054   _("(unknown)"))
00055 
00056 #define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
00057 #define INSN_BACKWARD_OFFSET_BIT (1 << 24)
00058 
00059 struct mmix_dis_info
00060  {
00061    const char *reg_name[256];
00062    const char *spec_reg_name[32];
00063 
00064    /* Waste a little memory so we don't have to allocate each separately.
00065       We could have an array with static contents for these, but on the
00066       other hand, we don't have to.  */
00067    char basic_reg_name[256][sizeof ("$255")];
00068  };
00069 
00070 /* Initialize a target-specific array in INFO.  */
00071 
00072 static bfd_boolean
00073 initialize_mmix_dis_info (struct disassemble_info *info)
00074 {
00075   struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
00076   int i;
00077 
00078   if (minfop == NULL)
00079     return FALSE;
00080 
00081   memset (minfop, 0, sizeof (*minfop));
00082 
00083   /* Initialize register names from register symbols.  If there's no
00084      register section, then there are no register symbols.  */
00085   if ((info->section != NULL && info->section->owner != NULL)
00086       || (info->symbols != NULL
00087          && info->symbols[0] != NULL
00088          && bfd_asymbol_bfd (info->symbols[0]) != NULL))
00089     {
00090       bfd *abfd = info->section && info->section->owner != NULL
00091        ? info->section->owner
00092        : bfd_asymbol_bfd (info->symbols[0]);
00093       asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
00094 
00095       if (reg_section != NULL)
00096        {
00097          /* The returned symcount *does* include the ending NULL.  */
00098          long symsize = bfd_get_symtab_upper_bound (abfd);
00099          asymbol **syms = malloc (symsize);
00100          long nsyms;
00101          long i;
00102 
00103          if (syms == NULL)
00104            {
00105              FATAL_DEBUG;
00106              free (minfop);
00107              return FALSE;
00108            }
00109          nsyms = bfd_canonicalize_symtab (abfd, syms);
00110 
00111          /* We use the first name for a register.  If this is MMO, then
00112             it's the name with the first sequence number, presumably the
00113             first in the source.  */
00114          for (i = 0; i < nsyms && syms[i] != NULL; i++)
00115            {
00116              if (syms[i]->section == reg_section
00117                 && syms[i]->value < 256
00118                 && minfop->reg_name[syms[i]->value] == NULL)
00119               minfop->reg_name[syms[i]->value] = syms[i]->name;
00120            }
00121        }
00122     }
00123 
00124   /* Fill in the rest with the canonical names.  */
00125   for (i = 0; i < 256; i++)
00126     if (minfop->reg_name[i] == NULL)
00127       {
00128        sprintf (minfop->basic_reg_name[i], "$%d", i);
00129        minfop->reg_name[i] = minfop->basic_reg_name[i];
00130       }
00131 
00132   /* We assume it's actually a one-to-one mapping of number-to-name.  */
00133   for (i = 0; mmix_spec_regs[i].name != NULL; i++)
00134     minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
00135 
00136   info->private_data = (void *) minfop;
00137   return TRUE;
00138 }
00139 
00140 /* A table indexed by the first byte is constructed as we disassemble each
00141    tetrabyte.  The contents is a pointer into mmix_insns reflecting the
00142    first found entry with matching match-bits and lose-bits.  Further
00143    entries are considered one after one until the operand constraints
00144    match or the match-bits and lose-bits do not match.  Normally a
00145    "further entry" will just show that there was no other match.  */
00146 
00147 static const struct mmix_opcode *
00148 get_opcode (unsigned long insn)
00149 {
00150   static const struct mmix_opcode **opcodes = NULL;
00151   const struct mmix_opcode *opcodep = mmix_opcodes;
00152   unsigned int opcode_part = (insn >> 24) & 255;
00153 
00154   if (opcodes == NULL)
00155     opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
00156 
00157   opcodep = opcodes[opcode_part];
00158   if (opcodep == NULL
00159       || (opcodep->match & insn) != opcodep->match
00160       || (opcodep->lose & insn) != 0)
00161     {
00162       /* Search through the table.  */
00163       for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
00164        {
00165          /* FIXME: Break out this into an initialization function.  */
00166          if ((opcodep->match & (opcode_part << 24)) == opcode_part
00167              && (opcodep->lose & (opcode_part << 24)) == 0)
00168            opcodes[opcode_part] = opcodep;
00169 
00170          if ((opcodep->match & insn) == opcodep->match
00171              && (opcodep->lose & insn) == 0)
00172            break;
00173        }
00174     }
00175 
00176   if (opcodep->name == NULL)
00177     return NULL;
00178 
00179   /* Check constraints.  If they don't match, loop through the next opcode
00180      entries.  */
00181   do
00182     {
00183       switch (opcodep->operands)
00184        {
00185          /* These have no restraint on what can be in the lower three
00186             bytes.  */
00187        case mmix_operands_regs:
00188        case mmix_operands_reg_yz:
00189        case mmix_operands_regs_z_opt:
00190        case mmix_operands_regs_z:
00191        case mmix_operands_jmp:
00192        case mmix_operands_pushgo:
00193        case mmix_operands_pop:
00194        case mmix_operands_sync:
00195        case mmix_operands_x_regs_z:
00196        case mmix_operands_neg:
00197        case mmix_operands_pushj:
00198        case mmix_operands_regaddr:
00199        case mmix_operands_get:
00200        case mmix_operands_set:
00201        case mmix_operands_save:
00202        case mmix_operands_unsave:
00203        case mmix_operands_xyz_opt:
00204          return opcodep;
00205 
00206          /* For a ROUND_MODE, the middle byte must be 0..4.  */
00207        case mmix_operands_roundregs_z:
00208        case mmix_operands_roundregs:
00209          {
00210            int midbyte = (insn >> 8) & 255;
00211 
00212            if (midbyte <= 4)
00213              return opcodep;
00214          }
00215        break;
00216 
00217        case mmix_operands_put:
00218          /* A "PUT".  If it is "immediate", then no restrictions,
00219             otherwise we have to make sure the register number is < 32.  */
00220          if ((insn & INSN_IMMEDIATE_BIT)
00221              || ((insn >> 16) & 255) < 32)
00222            return opcodep;
00223          break;
00224 
00225        case mmix_operands_resume:
00226          /* Middle bytes must be zero.  */
00227          if ((insn & 0x00ffff00) == 0)
00228            return opcodep;
00229          break;
00230 
00231        default:
00232          BAD_CASE (opcodep->operands);
00233        }
00234 
00235       opcodep++;
00236     }
00237   while ((opcodep->match & insn) == opcodep->match
00238         && (opcodep->lose & insn) == 0);
00239 
00240   /* If we got here, we had no match.  */
00241   return NULL;
00242 }
00243 
00244 /* The main disassembly function.  */
00245 
00246 int
00247 print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
00248 {
00249   unsigned char buffer[4];
00250   unsigned long insn;
00251   unsigned int x, y, z;
00252   const struct mmix_opcode *opcodep;
00253   int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
00254   struct mmix_dis_info *minfop;
00255 
00256   if (status != 0)
00257     {
00258       (*info->memory_error_func) (status, memaddr, info);
00259       return -1;
00260     }
00261 
00262   /* FIXME: Is -1 suitable?  */
00263   if (info->private_data == NULL
00264       && ! initialize_mmix_dis_info (info))
00265     return -1;
00266 
00267   minfop = (struct mmix_dis_info *) info->private_data;
00268   x = buffer[1];
00269   y = buffer[2];
00270   z = buffer[3];
00271 
00272   insn = bfd_getb32 (buffer);
00273 
00274   opcodep = get_opcode (insn);
00275 
00276   if (opcodep == NULL)
00277     {
00278       (*info->fprintf_func) (info->stream, _("*unknown*"));
00279       return 4;
00280     }
00281 
00282   (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
00283 
00284   /* Present bytes in the order they are laid out in memory.  */
00285   info->display_endian = BFD_ENDIAN_BIG;
00286 
00287   info->insn_info_valid = 1;
00288   info->bytes_per_chunk = 4;
00289   info->branch_delay_insns = 0;
00290   info->target = 0;
00291   switch (opcodep->type)
00292     {
00293     case mmix_type_normal:
00294     case mmix_type_memaccess_block:
00295       info->insn_type = dis_nonbranch;
00296       break;
00297 
00298     case mmix_type_branch:
00299       info->insn_type = dis_branch;
00300       break;
00301 
00302     case mmix_type_condbranch:
00303       info->insn_type = dis_condbranch;
00304       break;
00305 
00306     case mmix_type_memaccess_octa:
00307       info->insn_type = dis_dref;
00308       info->data_size = 8;
00309       break;
00310 
00311     case mmix_type_memaccess_tetra:
00312       info->insn_type = dis_dref;
00313       info->data_size = 4;
00314       break;
00315 
00316     case mmix_type_memaccess_wyde:
00317       info->insn_type = dis_dref;
00318       info->data_size = 2;
00319       break;
00320 
00321     case mmix_type_memaccess_byte:
00322       info->insn_type = dis_dref;
00323       info->data_size = 1;
00324       break;
00325 
00326     case mmix_type_jsr:
00327       info->insn_type = dis_jsr;
00328       break;
00329 
00330     default:
00331       BAD_CASE(opcodep->type);
00332     }
00333 
00334   switch (opcodep->operands)
00335     {
00336     case mmix_operands_regs:
00337       /*  All registers: "$X,$Y,$Z".  */
00338       (*info->fprintf_func) (info->stream, "%s,%s,%s",
00339                           minfop->reg_name[x],
00340                           minfop->reg_name[y],
00341                           minfop->reg_name[z]);
00342       break;
00343 
00344     case mmix_operands_reg_yz:
00345       /* Like SETH - "$X,YZ".  */
00346       (*info->fprintf_func) (info->stream, "%s,0x%x",
00347                           minfop->reg_name[x], y * 256 + z);
00348       break;
00349 
00350     case mmix_operands_regs_z_opt:
00351     case mmix_operands_regs_z:
00352     case mmix_operands_pushgo:
00353       /* The regular "$X,$Y,$Z|Z".  */
00354       if (insn & INSN_IMMEDIATE_BIT)
00355        (*info->fprintf_func) (info->stream, "%s,%s,%d",
00356                             minfop->reg_name[x], minfop->reg_name[y], z);
00357       else
00358        (*info->fprintf_func) (info->stream, "%s,%s,%s",
00359                             minfop->reg_name[x],
00360                             minfop->reg_name[y],
00361                             minfop->reg_name[z]);
00362       break;
00363 
00364     case mmix_operands_jmp:
00365       /* Address; only JMP.  */
00366       {
00367        bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
00368 
00369        if (insn & INSN_BACKWARD_OFFSET_BIT)
00370          offset -= (256 * 65536) * 4;
00371 
00372        info->target = memaddr + offset;
00373        (*info->print_address_func) (memaddr + offset, info);
00374       }
00375       break;
00376 
00377     case mmix_operands_roundregs_z:
00378       /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
00379         "$X,ROUND_MODE,$Z|Z".  */
00380       if (y != 0)
00381        {
00382          if (insn & INSN_IMMEDIATE_BIT)
00383            (*info->fprintf_func) (info->stream, "%s,%s,%d",
00384                                minfop->reg_name[x],
00385                                ROUND_MODE (y), z);
00386          else
00387            (*info->fprintf_func) (info->stream, "%s,%s,%s",
00388                                minfop->reg_name[x],
00389                                ROUND_MODE (y),
00390                                minfop->reg_name[z]);
00391        }
00392       else
00393        {
00394          if (insn & INSN_IMMEDIATE_BIT)
00395            (*info->fprintf_func) (info->stream, "%s,%d",
00396                                minfop->reg_name[x], z);
00397          else
00398            (*info->fprintf_func) (info->stream, "%s,%s",
00399                                minfop->reg_name[x],
00400                                minfop->reg_name[z]);
00401        }
00402       break;
00403 
00404     case mmix_operands_pop:
00405       /* Like POP - "X,YZ".  */
00406       (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
00407       break;
00408 
00409     case mmix_operands_roundregs:
00410       /* Two registers, possibly with rounding: "$X,$Z" or
00411         "$X,ROUND_MODE,$Z".  */
00412       if (y != 0)
00413        (*info->fprintf_func) (info->stream, "%s,%s,%s",
00414                             minfop->reg_name[x],
00415                             ROUND_MODE (y),
00416                             minfop->reg_name[z]);
00417       else
00418        (*info->fprintf_func) (info->stream, "%s,%s",
00419                             minfop->reg_name[x],
00420                             minfop->reg_name[z]);
00421       break;
00422 
00423     case mmix_operands_sync:
00424        /* Like SYNC - "XYZ".  */
00425       (*info->fprintf_func) (info->stream, "%u",
00426                           x * 65536 + y * 256 + z);
00427       break;
00428 
00429     case mmix_operands_x_regs_z:
00430       /* Like SYNCD - "X,$Y,$Z|Z".  */
00431       if (insn & INSN_IMMEDIATE_BIT)
00432        (*info->fprintf_func) (info->stream, "%d,%s,%d",
00433                             x, minfop->reg_name[y], z);
00434       else
00435        (*info->fprintf_func) (info->stream, "%d,%s,%s",
00436                             x, minfop->reg_name[y],
00437                             minfop->reg_name[z]);
00438       break;
00439 
00440     case mmix_operands_neg:
00441       /* Like NEG and NEGU - "$X,Y,$Z|Z".  */
00442       if (insn & INSN_IMMEDIATE_BIT)
00443        (*info->fprintf_func) (info->stream, "%s,%d,%d",
00444                             minfop->reg_name[x], y, z);
00445       else
00446        (*info->fprintf_func) (info->stream, "%s,%d,%s",
00447                             minfop->reg_name[x], y,
00448                             minfop->reg_name[z]);
00449       break;
00450 
00451     case mmix_operands_pushj:
00452     case mmix_operands_regaddr:
00453       /* Like GETA or branches - "$X,Address".  */
00454       {
00455        bfd_signed_vma offset = (y * 256 + z) * 4;
00456 
00457        if (insn & INSN_BACKWARD_OFFSET_BIT)
00458          offset -= 65536 * 4;
00459 
00460        info->target = memaddr + offset;
00461 
00462        (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
00463        (*info->print_address_func) (memaddr + offset, info);
00464       }
00465       break;
00466 
00467     case mmix_operands_get:
00468       /* GET - "X,spec_reg".  */
00469       (*info->fprintf_func) (info->stream, "%s,%s",
00470                           minfop->reg_name[x],
00471                           minfop->spec_reg_name[z]);
00472       break;
00473 
00474     case mmix_operands_put:
00475       /* PUT - "spec_reg,$Z|Z".  */
00476       if (insn & INSN_IMMEDIATE_BIT)
00477        (*info->fprintf_func) (info->stream, "%s,%d",
00478                             minfop->spec_reg_name[x], z);
00479       else
00480        (*info->fprintf_func) (info->stream, "%s,%s",
00481                             minfop->spec_reg_name[x],
00482                             minfop->reg_name[z]);
00483       break;
00484 
00485     case mmix_operands_set:
00486       /*  Two registers, "$X,$Y".  */
00487       (*info->fprintf_func) (info->stream, "%s,%s",
00488                           minfop->reg_name[x],
00489                           minfop->reg_name[y]);
00490       break;
00491 
00492     case mmix_operands_save:
00493       /* SAVE - "$X,0".  */
00494       (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
00495       break;
00496 
00497     case mmix_operands_unsave:
00498       /* UNSAVE - "0,$Z".  */
00499       (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
00500       break;
00501 
00502     case mmix_operands_xyz_opt:
00503       /* Like SWYM or TRAP - "X,Y,Z".  */
00504       (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
00505       break;
00506 
00507     case mmix_operands_resume:
00508       /* Just "Z", like RESUME.  */
00509       (*info->fprintf_func) (info->stream, "%d", z);
00510       break;
00511 
00512     default:
00513       (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
00514                           opcodep->operands);
00515       break;
00516     }
00517 
00518   return 4;
00519 }