Back to index

cell-binutils  2.17cvs20070401
mt-dis.c
Go to the documentation of this file.
00001 /* Disassembler interface for targets using CGEN. -*- C -*-
00002    CGEN: Cpu tools GENerator
00003 
00004    THIS FILE IS MACHINE GENERATED WITH CGEN.
00005    - the resultant file is machine generated, cgen-dis.in isn't
00006 
00007    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
00008    Free Software Foundation, Inc.
00009 
00010    This file is part of the GNU Binutils and GDB, the GNU debugger.
00011 
00012    This program is free software; you can redistribute it and/or modify
00013    it under the terms of the GNU General Public License as published by
00014    the Free Software Foundation; either version 2, or (at your option)
00015    any later version.
00016 
00017    This program is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020    GNU General Public License for more details.
00021 
00022    You should have received a copy of the GNU General Public License
00023    along with this program; if not, write to the Free Software Foundation, Inc.,
00024    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00025 
00026 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
00027    Keep that in mind.  */
00028 
00029 #include "sysdep.h"
00030 #include <stdio.h>
00031 #include "ansidecl.h"
00032 #include "dis-asm.h"
00033 #include "bfd.h"
00034 #include "symcat.h"
00035 #include "libiberty.h"
00036 #include "mt-desc.h"
00037 #include "mt-opc.h"
00038 #include "opintl.h"
00039 
00040 /* Default text to print if an instruction isn't recognized.  */
00041 #define UNKNOWN_INSN_MSG _("*unknown*")
00042 
00043 static void print_normal
00044   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
00045 static void print_address
00046   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
00047 static void print_keyword
00048   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
00049 static void print_insn_normal
00050   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
00051 static int print_insn
00052   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
00053 static int default_print_insn
00054   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
00055 static int read_insn
00056   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
00057    unsigned long *);
00058 
00059 /* -- disassembler routines inserted here.  */
00060 
00061 /* -- dis.c */
00062 static void print_dollarhex (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
00063 static void print_pcrel (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
00064 
00065 static void
00066 print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00067                void * dis_info,
00068                long value,
00069                unsigned int attrs ATTRIBUTE_UNUSED,
00070                bfd_vma pc ATTRIBUTE_UNUSED,
00071                int length ATTRIBUTE_UNUSED)
00072 {
00073   disassemble_info *info = (disassemble_info *) dis_info;
00074 
00075   info->fprintf_func (info->stream, "$%lx", value);
00076 
00077   if (0)
00078     print_normal (cd, dis_info, value, attrs, pc, length);
00079 }
00080 
00081 static void
00082 print_pcrel (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00083             void * dis_info,
00084             long value,
00085             unsigned int attrs ATTRIBUTE_UNUSED,
00086             bfd_vma pc ATTRIBUTE_UNUSED,
00087             int length ATTRIBUTE_UNUSED)
00088 {
00089   print_address (cd, dis_info, value + pc, attrs, pc, length);
00090 }
00091 
00092 /* -- */
00093 
00094 void mt_cgen_print_operand
00095   (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
00096 
00097 /* Main entry point for printing operands.
00098    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
00099    of dis-asm.h on cgen.h.
00100 
00101    This function is basically just a big switch statement.  Earlier versions
00102    used tables to look up the function to use, but
00103    - if the table contains both assembler and disassembler functions then
00104      the disassembler contains much of the assembler and vice-versa,
00105    - there's a lot of inlining possibilities as things grow,
00106    - using a switch statement avoids the function call overhead.
00107 
00108    This function could be moved into `print_insn_normal', but keeping it
00109    separate makes clear the interface between `print_insn_normal' and each of
00110    the handlers.  */
00111 
00112 void
00113 mt_cgen_print_operand (CGEN_CPU_DESC cd,
00114                         int opindex,
00115                         void * xinfo,
00116                         CGEN_FIELDS *fields,
00117                         void const *attrs ATTRIBUTE_UNUSED,
00118                         bfd_vma pc,
00119                         int length)
00120 {
00121   disassemble_info *info = (disassemble_info *) xinfo;
00122 
00123   switch (opindex)
00124     {
00125     case MT_OPERAND_A23 :
00126       print_dollarhex (cd, info, fields->f_a23, 0, pc, length);
00127       break;
00128     case MT_OPERAND_BALL :
00129       print_dollarhex (cd, info, fields->f_ball, 0, pc, length);
00130       break;
00131     case MT_OPERAND_BALL2 :
00132       print_dollarhex (cd, info, fields->f_ball2, 0, pc, length);
00133       break;
00134     case MT_OPERAND_BANKADDR :
00135       print_dollarhex (cd, info, fields->f_bankaddr, 0, pc, length);
00136       break;
00137     case MT_OPERAND_BRC :
00138       print_dollarhex (cd, info, fields->f_brc, 0, pc, length);
00139       break;
00140     case MT_OPERAND_BRC2 :
00141       print_dollarhex (cd, info, fields->f_brc2, 0, pc, length);
00142       break;
00143     case MT_OPERAND_CB1INCR :
00144       print_dollarhex (cd, info, fields->f_cb1incr, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00145       break;
00146     case MT_OPERAND_CB1SEL :
00147       print_dollarhex (cd, info, fields->f_cb1sel, 0, pc, length);
00148       break;
00149     case MT_OPERAND_CB2INCR :
00150       print_dollarhex (cd, info, fields->f_cb2incr, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00151       break;
00152     case MT_OPERAND_CB2SEL :
00153       print_dollarhex (cd, info, fields->f_cb2sel, 0, pc, length);
00154       break;
00155     case MT_OPERAND_CBRB :
00156       print_dollarhex (cd, info, fields->f_cbrb, 0, pc, length);
00157       break;
00158     case MT_OPERAND_CBS :
00159       print_dollarhex (cd, info, fields->f_cbs, 0, pc, length);
00160       break;
00161     case MT_OPERAND_CBX :
00162       print_dollarhex (cd, info, fields->f_cbx, 0, pc, length);
00163       break;
00164     case MT_OPERAND_CCB :
00165       print_dollarhex (cd, info, fields->f_ccb, 0, pc, length);
00166       break;
00167     case MT_OPERAND_CDB :
00168       print_dollarhex (cd, info, fields->f_cdb, 0, pc, length);
00169       break;
00170     case MT_OPERAND_CELL :
00171       print_dollarhex (cd, info, fields->f_cell, 0, pc, length);
00172       break;
00173     case MT_OPERAND_COLNUM :
00174       print_dollarhex (cd, info, fields->f_colnum, 0, pc, length);
00175       break;
00176     case MT_OPERAND_CONTNUM :
00177       print_dollarhex (cd, info, fields->f_contnum, 0, pc, length);
00178       break;
00179     case MT_OPERAND_CR :
00180       print_dollarhex (cd, info, fields->f_cr, 0, pc, length);
00181       break;
00182     case MT_OPERAND_CTXDISP :
00183       print_dollarhex (cd, info, fields->f_ctxdisp, 0, pc, length);
00184       break;
00185     case MT_OPERAND_DUP :
00186       print_dollarhex (cd, info, fields->f_dup, 0, pc, length);
00187       break;
00188     case MT_OPERAND_FBDISP :
00189       print_dollarhex (cd, info, fields->f_fbdisp, 0, pc, length);
00190       break;
00191     case MT_OPERAND_FBINCR :
00192       print_dollarhex (cd, info, fields->f_fbincr, 0, pc, length);
00193       break;
00194     case MT_OPERAND_FRDR :
00195       print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_dr, 0|(1<<CGEN_OPERAND_ABS_ADDR));
00196       break;
00197     case MT_OPERAND_FRDRRR :
00198       print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_drrr, 0|(1<<CGEN_OPERAND_ABS_ADDR));
00199       break;
00200     case MT_OPERAND_FRSR1 :
00201       print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_sr1, 0|(1<<CGEN_OPERAND_ABS_ADDR));
00202       break;
00203     case MT_OPERAND_FRSR2 :
00204       print_keyword (cd, info, & mt_cgen_opval_h_spr, fields->f_sr2, 0|(1<<CGEN_OPERAND_ABS_ADDR));
00205       break;
00206     case MT_OPERAND_ID :
00207       print_dollarhex (cd, info, fields->f_id, 0, pc, length);
00208       break;
00209     case MT_OPERAND_IMM16 :
00210       print_dollarhex (cd, info, fields->f_imm16s, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
00211       break;
00212     case MT_OPERAND_IMM16L :
00213       print_dollarhex (cd, info, fields->f_imm16l, 0, pc, length);
00214       break;
00215     case MT_OPERAND_IMM16O :
00216       print_pcrel (cd, info, fields->f_imm16s, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00217       break;
00218     case MT_OPERAND_IMM16Z :
00219       print_dollarhex (cd, info, fields->f_imm16u, 0, pc, length);
00220       break;
00221     case MT_OPERAND_INCAMT :
00222       print_dollarhex (cd, info, fields->f_incamt, 0, pc, length);
00223       break;
00224     case MT_OPERAND_INCR :
00225       print_dollarhex (cd, info, fields->f_incr, 0, pc, length);
00226       break;
00227     case MT_OPERAND_LENGTH :
00228       print_dollarhex (cd, info, fields->f_length, 0, pc, length);
00229       break;
00230     case MT_OPERAND_LOOPSIZE :
00231       print_pcrel (cd, info, fields->f_loopo, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
00232       break;
00233     case MT_OPERAND_MASK :
00234       print_dollarhex (cd, info, fields->f_mask, 0, pc, length);
00235       break;
00236     case MT_OPERAND_MASK1 :
00237       print_dollarhex (cd, info, fields->f_mask1, 0, pc, length);
00238       break;
00239     case MT_OPERAND_MODE :
00240       print_dollarhex (cd, info, fields->f_mode, 0, pc, length);
00241       break;
00242     case MT_OPERAND_PERM :
00243       print_dollarhex (cd, info, fields->f_perm, 0, pc, length);
00244       break;
00245     case MT_OPERAND_RBBC :
00246       print_dollarhex (cd, info, fields->f_rbbc, 0, pc, length);
00247       break;
00248     case MT_OPERAND_RC :
00249       print_dollarhex (cd, info, fields->f_rc, 0, pc, length);
00250       break;
00251     case MT_OPERAND_RC1 :
00252       print_dollarhex (cd, info, fields->f_rc1, 0, pc, length);
00253       break;
00254     case MT_OPERAND_RC2 :
00255       print_dollarhex (cd, info, fields->f_rc2, 0, pc, length);
00256       break;
00257     case MT_OPERAND_RC3 :
00258       print_dollarhex (cd, info, fields->f_rc3, 0, pc, length);
00259       break;
00260     case MT_OPERAND_RCNUM :
00261       print_dollarhex (cd, info, fields->f_rcnum, 0, pc, length);
00262       break;
00263     case MT_OPERAND_RDA :
00264       print_dollarhex (cd, info, fields->f_rda, 0, pc, length);
00265       break;
00266     case MT_OPERAND_ROWNUM :
00267       print_dollarhex (cd, info, fields->f_rownum, 0, pc, length);
00268       break;
00269     case MT_OPERAND_ROWNUM1 :
00270       print_dollarhex (cd, info, fields->f_rownum1, 0, pc, length);
00271       break;
00272     case MT_OPERAND_ROWNUM2 :
00273       print_dollarhex (cd, info, fields->f_rownum2, 0, pc, length);
00274       break;
00275     case MT_OPERAND_SIZE :
00276       print_dollarhex (cd, info, fields->f_size, 0, pc, length);
00277       break;
00278     case MT_OPERAND_TYPE :
00279       print_dollarhex (cd, info, fields->f_type, 0, pc, length);
00280       break;
00281     case MT_OPERAND_WR :
00282       print_dollarhex (cd, info, fields->f_wr, 0, pc, length);
00283       break;
00284     case MT_OPERAND_XMODE :
00285       print_dollarhex (cd, info, fields->f_xmode, 0, pc, length);
00286       break;
00287 
00288     default :
00289       /* xgettext:c-format */
00290       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
00291               opindex);
00292     abort ();
00293   }
00294 }
00295 
00296 cgen_print_fn * const mt_cgen_print_handlers[] = 
00297 {
00298   print_insn_normal,
00299 };
00300 
00301 
00302 void
00303 mt_cgen_init_dis (CGEN_CPU_DESC cd)
00304 {
00305   mt_cgen_init_opcode_table (cd);
00306   mt_cgen_init_ibld_table (cd);
00307   cd->print_handlers = & mt_cgen_print_handlers[0];
00308   cd->print_operand = mt_cgen_print_operand;
00309 }
00310 
00311 
00312 /* Default print handler.  */
00313 
00314 static void
00315 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00316              void *dis_info,
00317              long value,
00318              unsigned int attrs,
00319              bfd_vma pc ATTRIBUTE_UNUSED,
00320              int length ATTRIBUTE_UNUSED)
00321 {
00322   disassemble_info *info = (disassemble_info *) dis_info;
00323 
00324 #ifdef CGEN_PRINT_NORMAL
00325   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
00326 #endif
00327 
00328   /* Print the operand as directed by the attributes.  */
00329   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00330     ; /* nothing to do */
00331   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00332     (*info->fprintf_func) (info->stream, "%ld", value);
00333   else
00334     (*info->fprintf_func) (info->stream, "0x%lx", value);
00335 }
00336 
00337 /* Default address handler.  */
00338 
00339 static void
00340 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00341               void *dis_info,
00342               bfd_vma value,
00343               unsigned int attrs,
00344               bfd_vma pc ATTRIBUTE_UNUSED,
00345               int length ATTRIBUTE_UNUSED)
00346 {
00347   disassemble_info *info = (disassemble_info *) dis_info;
00348 
00349 #ifdef CGEN_PRINT_ADDRESS
00350   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
00351 #endif
00352 
00353   /* Print the operand as directed by the attributes.  */
00354   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
00355     ; /* Nothing to do.  */
00356   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
00357     (*info->print_address_func) (value, info);
00358   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
00359     (*info->print_address_func) (value, info);
00360   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
00361     (*info->fprintf_func) (info->stream, "%ld", (long) value);
00362   else
00363     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
00364 }
00365 
00366 /* Keyword print handler.  */
00367 
00368 static void
00369 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00370               void *dis_info,
00371               CGEN_KEYWORD *keyword_table,
00372               long value,
00373               unsigned int attrs ATTRIBUTE_UNUSED)
00374 {
00375   disassemble_info *info = (disassemble_info *) dis_info;
00376   const CGEN_KEYWORD_ENTRY *ke;
00377 
00378   ke = cgen_keyword_lookup_value (keyword_table, value);
00379   if (ke != NULL)
00380     (*info->fprintf_func) (info->stream, "%s", ke->name);
00381   else
00382     (*info->fprintf_func) (info->stream, "???");
00383 }
00384 
00385 /* Default insn printer.
00386 
00387    DIS_INFO is defined as `void *' so the disassembler needn't know anything
00388    about disassemble_info.  */
00389 
00390 static void
00391 print_insn_normal (CGEN_CPU_DESC cd,
00392                  void *dis_info,
00393                  const CGEN_INSN *insn,
00394                  CGEN_FIELDS *fields,
00395                  bfd_vma pc,
00396                  int length)
00397 {
00398   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
00399   disassemble_info *info = (disassemble_info *) dis_info;
00400   const CGEN_SYNTAX_CHAR_TYPE *syn;
00401 
00402   CGEN_INIT_PRINT (cd);
00403 
00404   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
00405     {
00406       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
00407        {
00408          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
00409          continue;
00410        }
00411       if (CGEN_SYNTAX_CHAR_P (*syn))
00412        {
00413          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
00414          continue;
00415        }
00416 
00417       /* We have an operand.  */
00418       mt_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
00419                              fields, CGEN_INSN_ATTRS (insn), pc, length);
00420     }
00421 }
00422 
00423 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
00424    the extract info.
00425    Returns 0 if all is well, non-zero otherwise.  */
00426 
00427 static int
00428 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00429           bfd_vma pc,
00430           disassemble_info *info,
00431           bfd_byte *buf,
00432           int buflen,
00433           CGEN_EXTRACT_INFO *ex_info,
00434           unsigned long *insn_value)
00435 {
00436   int status = (*info->read_memory_func) (pc, buf, buflen, info);
00437 
00438   if (status != 0)
00439     {
00440       (*info->memory_error_func) (status, pc, info);
00441       return -1;
00442     }
00443 
00444   ex_info->dis_info = info;
00445   ex_info->valid = (1 << buflen) - 1;
00446   ex_info->insn_bytes = buf;
00447 
00448   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
00449   return 0;
00450 }
00451 
00452 /* Utility to print an insn.
00453    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
00454    The result is the size of the insn in bytes or zero for an unknown insn
00455    or -1 if an error occurs fetching data (memory_error_func will have
00456    been called).  */
00457 
00458 static int
00459 print_insn (CGEN_CPU_DESC cd,
00460            bfd_vma pc,
00461            disassemble_info *info,
00462            bfd_byte *buf,
00463            unsigned int buflen)
00464 {
00465   CGEN_INSN_INT insn_value;
00466   const CGEN_INSN_LIST *insn_list;
00467   CGEN_EXTRACT_INFO ex_info;
00468   int basesize;
00469 
00470   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
00471   basesize = cd->base_insn_bitsize < buflen * 8 ?
00472                                      cd->base_insn_bitsize : buflen * 8;
00473   insn_value = cgen_get_insn_value (cd, buf, basesize);
00474 
00475 
00476   /* Fill in ex_info fields like read_insn would.  Don't actually call
00477      read_insn, since the incoming buffer is already read (and possibly
00478      modified a la m32r).  */
00479   ex_info.valid = (1 << buflen) - 1;
00480   ex_info.dis_info = info;
00481   ex_info.insn_bytes = buf;
00482 
00483   /* The instructions are stored in hash lists.
00484      Pick the first one and keep trying until we find the right one.  */
00485 
00486   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
00487   while (insn_list != NULL)
00488     {
00489       const CGEN_INSN *insn = insn_list->insn;
00490       CGEN_FIELDS fields;
00491       int length;
00492       unsigned long insn_value_cropped;
00493 
00494 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
00495       /* Not needed as insn shouldn't be in hash lists if not supported.  */
00496       /* Supported by this cpu?  */
00497       if (! mt_cgen_insn_supported (cd, insn))
00498         {
00499           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00500          continue;
00501         }
00502 #endif
00503 
00504       /* Basic bit mask must be correct.  */
00505       /* ??? May wish to allow target to defer this check until the extract
00506         handler.  */
00507 
00508       /* Base size may exceed this instruction's size.  Extract the
00509          relevant part from the buffer. */
00510       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
00511          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00512        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
00513                                       info->endian == BFD_ENDIAN_BIG);
00514       else
00515        insn_value_cropped = insn_value;
00516 
00517       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
00518          == CGEN_INSN_BASE_VALUE (insn))
00519        {
00520          /* Printing is handled in two passes.  The first pass parses the
00521             machine insn and extracts the fields.  The second pass prints
00522             them.  */
00523 
00524          /* Make sure the entire insn is loaded into insn_value, if it
00525             can fit.  */
00526          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
00527              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
00528            {
00529              unsigned long full_insn_value;
00530              int rc = read_insn (cd, pc, info, buf,
00531                               CGEN_INSN_BITSIZE (insn) / 8,
00532                               & ex_info, & full_insn_value);
00533              if (rc != 0)
00534               return rc;
00535              length = CGEN_EXTRACT_FN (cd, insn)
00536               (cd, insn, &ex_info, full_insn_value, &fields, pc);
00537            }
00538          else
00539            length = CGEN_EXTRACT_FN (cd, insn)
00540              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
00541 
00542          /* Length < 0 -> error.  */
00543          if (length < 0)
00544            return length;
00545          if (length > 0)
00546            {
00547              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
00548              /* Length is in bits, result is in bytes.  */
00549              return length / 8;
00550            }
00551        }
00552 
00553       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
00554     }
00555 
00556   return 0;
00557 }
00558 
00559 /* Default value for CGEN_PRINT_INSN.
00560    The result is the size of the insn in bytes or zero for an unknown insn
00561    or -1 if an error occured fetching bytes.  */
00562 
00563 #ifndef CGEN_PRINT_INSN
00564 #define CGEN_PRINT_INSN default_print_insn
00565 #endif
00566 
00567 static int
00568 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
00569 {
00570   bfd_byte buf[CGEN_MAX_INSN_SIZE];
00571   int buflen;
00572   int status;
00573 
00574   /* Attempt to read the base part of the insn.  */
00575   buflen = cd->base_insn_bitsize / 8;
00576   status = (*info->read_memory_func) (pc, buf, buflen, info);
00577 
00578   /* Try again with the minimum part, if min < base.  */
00579   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
00580     {
00581       buflen = cd->min_insn_bitsize / 8;
00582       status = (*info->read_memory_func) (pc, buf, buflen, info);
00583     }
00584 
00585   if (status != 0)
00586     {
00587       (*info->memory_error_func) (status, pc, info);
00588       return -1;
00589     }
00590 
00591   return print_insn (cd, pc, info, buf, buflen);
00592 }
00593 
00594 /* Main entry point.
00595    Print one instruction from PC on INFO->STREAM.
00596    Return the size of the instruction (in bytes).  */
00597 
00598 typedef struct cpu_desc_list
00599 {
00600   struct cpu_desc_list *next;
00601   CGEN_BITSET *isa;
00602   int mach;
00603   int endian;
00604   CGEN_CPU_DESC cd;
00605 } cpu_desc_list;
00606 
00607 int
00608 print_insn_mt (bfd_vma pc, disassemble_info *info)
00609 {
00610   static cpu_desc_list *cd_list = 0;
00611   cpu_desc_list *cl = 0;
00612   static CGEN_CPU_DESC cd = 0;
00613   static CGEN_BITSET *prev_isa;
00614   static int prev_mach;
00615   static int prev_endian;
00616   int length;
00617   CGEN_BITSET *isa;
00618   int mach;
00619   int endian = (info->endian == BFD_ENDIAN_BIG
00620               ? CGEN_ENDIAN_BIG
00621               : CGEN_ENDIAN_LITTLE);
00622   enum bfd_architecture arch;
00623 
00624   /* ??? gdb will set mach but leave the architecture as "unknown" */
00625 #ifndef CGEN_BFD_ARCH
00626 #define CGEN_BFD_ARCH bfd_arch_mt
00627 #endif
00628   arch = info->arch;
00629   if (arch == bfd_arch_unknown)
00630     arch = CGEN_BFD_ARCH;
00631    
00632   /* There's no standard way to compute the machine or isa number
00633      so we leave it to the target.  */
00634 #ifdef CGEN_COMPUTE_MACH
00635   mach = CGEN_COMPUTE_MACH (info);
00636 #else
00637   mach = info->mach;
00638 #endif
00639 
00640 #ifdef CGEN_COMPUTE_ISA
00641   {
00642     static CGEN_BITSET *permanent_isa;
00643 
00644     if (!permanent_isa)
00645       permanent_isa = cgen_bitset_create (MAX_ISAS);
00646     isa = permanent_isa;
00647     cgen_bitset_clear (isa);
00648     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
00649   }
00650 #else
00651   isa = info->insn_sets;
00652 #endif
00653 
00654   /* If we've switched cpu's, try to find a handle we've used before */
00655   if (cd
00656       && (cgen_bitset_compare (isa, prev_isa) != 0
00657          || mach != prev_mach
00658          || endian != prev_endian))
00659     {
00660       cd = 0;
00661       for (cl = cd_list; cl; cl = cl->next)
00662        {
00663          if (cgen_bitset_compare (cl->isa, isa) == 0 &&
00664              cl->mach == mach &&
00665              cl->endian == endian)
00666            {
00667              cd = cl->cd;
00668              prev_isa = cd->isas;
00669              break;
00670            }
00671        }
00672     } 
00673 
00674   /* If we haven't initialized yet, initialize the opcode table.  */
00675   if (! cd)
00676     {
00677       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
00678       const char *mach_name;
00679 
00680       if (!arch_type)
00681        abort ();
00682       mach_name = arch_type->printable_name;
00683 
00684       prev_isa = cgen_bitset_copy (isa);
00685       prev_mach = mach;
00686       prev_endian = endian;
00687       cd = mt_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
00688                              CGEN_CPU_OPEN_BFDMACH, mach_name,
00689                              CGEN_CPU_OPEN_ENDIAN, prev_endian,
00690                              CGEN_CPU_OPEN_END);
00691       if (!cd)
00692        abort ();
00693 
00694       /* Save this away for future reference.  */
00695       cl = xmalloc (sizeof (struct cpu_desc_list));
00696       cl->cd = cd;
00697       cl->isa = prev_isa;
00698       cl->mach = mach;
00699       cl->endian = endian;
00700       cl->next = cd_list;
00701       cd_list = cl;
00702 
00703       mt_cgen_init_dis (cd);
00704     }
00705 
00706   /* We try to have as much common code as possible.
00707      But at this point some targets need to take over.  */
00708   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
00709      but if not possible try to move this hook elsewhere rather than
00710      have two hooks.  */
00711   length = CGEN_PRINT_INSN (cd, pc, info);
00712   if (length > 0)
00713     return length;
00714   if (length < 0)
00715     return -1;
00716 
00717   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
00718   return cd->default_insn_bitsize / 8;
00719 }